Skip to content

Latest commit

 

History

History
275 lines (190 loc) · 5.16 KB

File metadata and controls

275 lines (190 loc) · 5.16 KB
status active
audience public
last-verified 2026-04-09

Viper IL — Quickstart

Get started with Viper's Intermediate Language (IL) in minutes. This guide shows you how to write, verify, and execute IL programs.


What is Viper IL?

Viper IL is a typed, readable intermediate language that serves as the core of the Viper toolchain:

  • Frontends (Zia, BASIC, etc.) compile to IL
  • VM executes IL directly
  • Verifier checks IL for safety and correctness
  • Transforms (SimplifyCFG, Liveness, etc.) optimize IL
  • Backends compile IL to native code

IL is designed to be human-readable and easy to inspect, making it ideal for learning compiler concepts and debugging.


Quick Start: Your First IL Program

1. Write a Simple Function

Create a file hello.il:

il 0.2.0

extern @Viper.Terminal.PrintStr(str) -> void
global const str @.msg = "Hello, Viper IL!"

func @main() -> i64 {
entry:
  %msg = const_str @.msg
  call @Viper.Terminal.PrintStr(%msg)
  ret 0
}

Compatibility:

  • When built with -DVIPER_RUNTIME_NS_DUAL=ON, legacy @rt_* externs are accepted as aliases of @Viper.*.
  • New code should emit @Viper.*.

2. Verify the IL

il-verify hello.il

The verifier checks types, control flow, and instruction well-formedness. No output means success!

3. Run the Program

viper -run hello.il

Output:

Hello, Viper IL!

IL Structure Explained

Version Header

Every IL file starts with a version declaration:

il 0.2.0

This pins the expected IL grammar version.

Extern Declarations

Declare runtime functions you'll call:

extern @Viper.Terminal.PrintI64(i64) -> void
extern @Viper.String.Concat(str, str) -> str

Global Constants

Define immutable data:

global const str @.hello = "Hello!"
global const i64 @.answer = 42

Functions

Functions contain basic blocks and instructions:

func @square(i64 %x) -> i64 {
entry:
  %result = imul.ovf %x, %x
  ret %result
}

Key points:

  • @name — Function symbol
  • %var — SSA register (assigned once, used many times)
  • entry: — First basic block label
  • ret — Return terminator (required at end of block)
  • Signed integer arithmetic uses overflow-checked opcodes (iadd.ovf, isub.ovf, imul.ovf); the plain add/sub/ mul opcodes are rejected by the verifier.

Basic IL Examples

Arithmetic

func @add(i64 %a, i64 %b) -> i64 {
entry:
  %sum = iadd.ovf %a, %b
  ret %sum
}

Control Flow

func @max(i64 %a, i64 %b) -> i64 {
entry:
  %cond = scmp_gt %a, %b
  cbr %cond, greater, less_or_equal

greater:
  ret %a

less_or_equal:
  ret %b
}

Calling Functions

func @square(i64 %x) -> i64 {
entry:
  %result = imul.ovf %x, %x
  ret %result
}

func @call_square(i64 %y) -> i64 {
entry:
  %result = call @square(%y)
  ret %result
}

Switch Statements

func @classify(i64 %n) -> i64 {
entry:
  %n32:i32 = cast.si_narrow.chk %n
  switch.i32 %n32, ^default, 0 -> ^zero, 1 -> ^one, 2 -> ^two

default:
  ret 99

zero:
  ret 0

one:
  ret 10

two:
  ret 20
}

IL Toolchain

Verify IL

Check IL files for correctness:

il-verify program.il

The verifier catches:

  • Type mismatches
  • Missing terminators
  • Invalid control flow
  • Undefined references

Disassemble IL

Pretty-print IL files:

il-dis program.il

Execute IL

Run IL programs on the VM:

viper -run program.il

Transform IL

Apply optimization passes:

viper il-opt program.il --passes "simplify-cfg" -o optimized.il

Preset pipelines via viper il-opt:

# O1 (default): SimplifyCFG → Mem2Reg → SimplifyCFG → SCCP → ConstFold →
#               Peephole → DCE → SimplifyCFG → SCCP → Inline → Peephole →
#               DCE → SimplifyCFG
viper il-opt program.il --pipeline O1 -o program.o1.il

# O2: SimplifyCFG → Mem2Reg → SimplifyCFG → LoopSimplify → LICM → LoopRotate →
#     IndVars → LoopUnroll → SimplifyCFG → SCCP → CheckOpt → EHOpt → DCE →
#     SimplifyCFG → SiblingRecursion → Inline → SimplifyCFG → SCCP →
#     ConstFold → Peephole → DCE → SimplifyCFG → GVN → Reassociate →
#     EarlyCSE → DSE → DCE → LateCleanup
viper il-opt program.il --pipeline O2 -o program.o2.il

# Custom sequence
viper il-opt program.il --passes "simplify-cfg,sccp,dce" -o out.il

Available passes: check-opt, constfold, dce, dse, earlycse, ehopt, gvn, indvars, inline, late-cleanup, licm, licm-safe, loop-rotate, loop-simplify, loop-unroll, mem2reg, peephole, reassociate, sccp, simplify-cfg

Focused validation pipelines are also addressable by name: rehab-mem2reg, rehab-peephole, and rehab-licm.


Next Steps

Learn More:

Explore:

  • Check src/tests/golden/il/ for more IL examples
  • Run viper --help for all available options
  • Experiment with optimization passes