| llvm Assembly Language Reference Manual |
| Abstract |
This document describes the LLVM assembly language IR/VM. LLVM is an SSA based representation that attempts to be a useful midlevel IR by providing type safety, low level operations, flexibility, and the capability to represent 'all' high level languages cleanly.
| Introduction |
This dual nature leads to three different representations of LLVM (the human readable assembly representation, the compact bytecode representation, and the in memory, pointer based, representation). This document describes the human readable representation and notation.
The LLVM representation aims to be a light weight and low level while being expressive, type safe, and extensible at the same time. It aims to be a "universal IR" of sorts, by being at a low enough level that high level ideas may be cleanly mapped to it. By providing type safety, LLVM can be used as the target of optimizations: for example, through pointer analysis, it can be proven that a C automatic variable is never accessed outside of the current function... allowing it to be promoted to a simple SSA value instead of a memory location.
%x = add int 1, %x...because only a phi node may refer to itself. The LLVM api provides a verification function (verify) that may be used to verify that a whole module or a single method is well formed. It is useful to validate whether an optimization pass performed a well formed transformation to the code.
Describe the typesetting conventions here.
| Identifiers |
LLVM requires the values start with a '%' sign for two reasons: Compilers don't need to worry about name clashes with reserved words, and the set of reserved words may be expanded in the future without penalty. Additionally, unnamed identifiers allow a compiler to quickly come up with a temporary variable without having to avoid symbol table conflicts.
Reserved words in LLVM are very similar to reserved words in other languages. There are keywords for different opcodes ('add', 'cast', 'ret', etc...), for primitive type names ('void', 'uint', etc...), and others. These reserved words cannot conflict with variable names, because none of them may start with a '%' character.
Here is an example of LLVM code to multiply the integer variable '%X' by 8:
The easy way:
%result = mul int %X, 8After strength reduction:
%result = shl int %X, ubyte 3And the hard way:
add int %X, %X ; yields {int}:%0
add int %0, %0 ; yields {int}:%1
%result = add int %1, %1
This last way of multiplying %X by 8 illustrates several important lexical features of LLVM:
...and it also show a convention that we follow in this document. When demonstrating instructions, we will follow an instruction with a comment that defines the type and name of value produced. Comments are shown in italic text.
| Type System |
The assembly language form for the type system was heavily influenced by the type problems in the C language1.
| Primitive Types |
|
|
| signed | sbyte, short, int, long, float, double |
| unsigned | ubyte, ushort, uint, ulong |
| integral | ubyte, sbyte, ushort, short, uint, int, ulong, long |
| floating point | float, double |
| first class | bool, ubyte, sbyte, ushort, short, uint, int, ulong, long, float, double, lock |
| Derived Types |
[40 x int ]: Array of 40 integer values.
[41 x int ]: Array of 41 integer values.
[40 x uint]: Array of 40 unsigned integer values.
Fixed sized arrays are very useful for compiler optimization passes and for representing analysis results. Additionally, multidimensional arrays must have fixed sizes for all dimensions except the outer-most dimension.
Here are some examples of multidimensional arrays:
| [3 x [4 x int]] | : 3x4 array integer values. |
| [[10 x int]] | : Nx10 array of integer values. |
| [2 x [3 x [4 x uint]]] | : 2x3x4 array of unsigned integer values. |
<returntype> (<parameter list>)Where '<parameter list>' is a comma seperated list of type specifiers.
| int (int) | : method taking an int, returning an int |
| float (int, int *) * | : Pointer to a method that takes an int and a pointer to int, returning float. |
Structures are accessed using 'load and 'store' by getting a pointer to a field with the 'getelementptr' instruction.
{ <type list> }
| { int, int, int } | : a triple of three int values |
| { float, int (int *) * } | : A pair, where the first element is a float and the second element is a pointer to a method that takes an int, returning an int. |
Packed types should be 'nonsaturated' because standard data types are not saturated. Maybe have a saturated packed type?
| High Level Structure |
| Module Structure |
| Method Structure |
talk about how basic blocks delinate labels
talk about how basic blocks end with terminators
| Instruction Reference |
| Terminator Instructions |
There are three different terminator instructions: the 'ret' instruction, the 'br' instruction, and the 'switch' instruction.
ret <type> <value> ; Return a value from a non-void method ret void ; Return from void method
There are two forms of the 'ret' instructruction: one that returns a value and then causes control flow, and one that just causes control flow to occur.
ret int 5 ; Return an integer value of 5 ret void ; Return from a void method
br bool <cond>, label <iftrue>, label <iffalse> br label <dest> ; Unconditional branch
Test: %cond = seteq int %a, %b br bool %cond, label %IfEqual, label %IfUnequal IfEqual: ret bool true IfUnequal: ret bool false
; Definitions for lookup indirect branch
%switchtype = type [<anysize> x { uint, label }]
; Lookup indirect branch
switch uint <value>, label <defaultdest>, %switchtype <switchtable>
; Indexed indirect branch
switch uint <idxvalue>, label <defaultdest>, [<anysize> x label] <desttable>
The 'switch' statement supports two different styles of indirect branching: lookup branching and indexed branching. Lookup branching is generally useful if the values to switch on are spread far appart, where index branching is useful if the values to switch on are generally dense.
The two different forms of the 'switch' statement are simple hints to the underlying virtual machine implementation. For example, a virtual machine may choose to implement a small indirect branch table as a series of predicated comparisons: if it is faster for the target architecture.
The indexed form of the 'switch' instruction uses three parameters: an 'uint' index value, a default 'label' and a sized array of 'label's. The 'dests' array must be a constant array.
The index branch form simply looks up a label element directly in a table and branches to it.
In either case, the compiler knows the static size of the array, because it is provided as part of the constant values type.
; Emulate a conditional br instruction
%Val = cast bool %value to uint
switch uint %Val, label %truedest, [1 x label] [label %falsedest ]
; Emulate an unconditional br instruction
switch uint 0, label %dest, [ 0 x label] [ ]
; Implement a jump table using the constant pool:
void "testmeth"(int %arg0)
%switchdests = [3 x label] [ label %onzero, label %onone, label %ontwo ]
{
...
switch uint %val, label %otherwise, [3 x label] %switchdests...
...
}
; Implement the equivilent jump table directly:
switch uint %val, label %otherwise, [3 x label] [ label %onzero,
label %onone,
label %ontwo ]
<result> = call <method ty> %<method name>(<method args>) with label <break label>
TODO: icall .. with needs to be defined as well for an indirect call.
For a more comprehensive explanation of this instruction look in the llvm/docs/2001-05-18-ExceptionHandling.txt document.
%retval = call int (int) %Test(int 15) with label %TestCleanup ; {int}:retval set
| Unary Operations |
There is only one unary operators: the 'not' instruction.
<result> = not <ty> <var> ; yields {ty}:result
Note that the 'not' instruction is is not defined over to 'bool' type. To invert a boolean value, the recommended method is to use:
<result> = xor bool true, <var> ; yields {bool}:result
%x = not int 1 ; {int}:x is now equal to 0
%x = not bool true ; {bool}:x is now equal to false
| Binary Operations |
There are several different binary operators:
<result> = add <ty> <var1>, <var2> ; yields {ty}:result
<result> = add int 4, %var ; yields {int}:result = 4 + %var
<result> = sub <ty> <var1>, <var2> ; yields {ty}:result
Note that the 'sub' instruction is the cannonical way the 'neg' instruction is represented as well.
<result> = sub int 4, %var ; yields {int}:result = 4 - %var
<result> = sub int 0, %val ; yields {int}:result = -%var
<result> = mul <ty> <var1>, <var2> ; yields {ty}:result
There is no signed vs unsigned multiplication. The appropriate action is taken based on the type of the operand.
<result> = mul int 4, %var ; yields {int}:result = 4 * %var
<result> = div <ty> <var1>, <var2> ; yields {ty}:result
<result> = div int 4, %var ; yields {int}:result = 4 / %var
<result> = rem <ty> <var1>, <var2> ; yields {ty}:result
...
<result> = rem int 4, %var ; yields {int}:result = 4 % %var
<result> = seteq <ty> <var1>, <var2> ; yields {bool}:result
<result> = setne <ty> <var1>, <var2> ; yields {bool}:result
<result> = setlt <ty> <var1>, <var2> ; yields {bool}:result
<result> = setgt <ty> <var1>, <var2> ; yields {bool}:result
<result> = setle <ty> <var1>, <var2> ; yields {bool}:result
<result> = setge <ty> <var1>, <var2> ; yields {bool}:result
The 'setlt', 'setgt', 'setle', and 'setge' instructions do not operate on 'bool' typed arguments.
<result> = seteq int 4, 5 ; yields {bool}:result = false
<result> = setne float 4, 5 ; yields {bool}:result = true
<result> = setlt uint 4, 5 ; yields {bool}:result = true
<result> = setgt sbyte 4, 5 ; yields {bool}:result = false
<result> = setle sbyte 4, 5 ; yields {bool}:result = true
<result> = setge sbyte 4, 5 ; yields {bool}:result = false
| Bitwise Binary Operations |
<result> = and <ty> <var1>, <var2> ; yields {ty}:result
<result> = and int 4, %var ; yields {int}:result = 4 & %var
<result> = and int 15, 40 ; yields {int}:result = 8
<result> = and int 4, 8 ; yields {int}:result = 0
<result> = or <ty> <var1>, <var2> ; yields {ty}:result
<result> = or int 4, %var ; yields {int}:result = 4 | %var
<result> = or int 15, 40 ; yields {int}:result = 47
<result> = or int 4, 8 ; yields {int}:result = 12
<result> = xor <ty> <var1>, <var2> ; yields {ty}:result
<result> = xor int 4, %var ; yields {int}:result = 4 ^ %var
<result> = xor int 15, 40 ; yields {int}:result = 39
<result> = xor int 4, 8 ; yields {int}:result = 12
<result> = shl <ty> <var1>, ubyte <var2> ; yields {ty}:result
<result> = shl int 4, ubyte %var ; yields {int}:result = 4 << %var
<result> = shl int 4, ubyte 2 ; yields {int}:result = 16
<result> = shl int 1, ubyte 10 ; yields {int}:result = 1024
<result> = shr <ty> <var1>, ubyte <var2> ; yields {ty}:result
<result> = shr int 4, ubyte %var ; yields {int}:result = 4 >> %var
<result> = shr int 4, ubyte 1 ; yields {int}:result = 2
<result> = shr int 4, ubyte 2 ; yields {int}:result = 1
<result> = shr int 4, ubyte 3 ; yields {int}:result = 0
| Memory Access Operations |
<result> = malloc <type> ; yields { type *}:result
<result> = malloc [<type>], uint <NumElements> ; yields {[type] *}:result
'type' may be any type except for a unsized array type.
%array = malloc [4 x ubyte ] ; yields {[%4 x ubyte]*}:array
%size = add uint 2, 2 ; yields {uint}:size = uint 4
%array1 = malloc [ubyte], uint 4 ; yields {[ubyte]*}:array1
%array2 = malloc [ubyte], uint %size ; yields {[ubyte]*}:array2
free <type> <value> ; yields {void}
%array = malloc [4 x ubyte] ; yields {[4 x ubyte]*}:array
free [4 x ubyte]* %array
<result> = alloca <type> ; yields {type*}:result
<result> = alloca [<type>], uint <NumElements> ; yields {[type] *}:result
'type' may be any type except for a unsized array type.
Note that a virtual machine may generate more efficient native code for a method if all of the fixed size 'alloca' instructions live in the first basic block of that method.
%ptr = alloca int ; yields {int*}:ptr
%ptr = alloca [int], uint 4 ; yields {[int]*}:ptr
<result> = load <ty>* <pointer> ; yields {ty}:result
<result> = load <ty>* <arrayptr>{, uint <idx>}+ ; yields {ty}:result
<result> = load <ty>* <structptr>{, ubyte <idx>}+ ; yields field type
In the first form, '<ty>' must be a pointer to a simple type (a primitive type or another pointer).
In the second form, '<ty>' must be a pointer to an array, and a list of one or more indices is provided as indexes into the (possibly multidimensional) array. No bounds checking is performed on array reads.
In the third form, the pointer must point to a (possibly nested) structure. There shall be one ubyte argument for each level of dereferencing involved.
%ptr = alloca int ; yields {int*}:ptr
store int 3, int* %ptr ; yields {void}
%val = load int* %ptr ; yields {int}:val = int 3
%array = malloc [4 x ubyte] ; yields {[4 x ubyte]*}:array
store ubyte 124, [4 x ubyte]* %array, uint 4
%val = load [4 x ubyte]* %array, uint 4 ; yields {ubyte}:val = ubyte 124
%val = load {{int, float}}* %stptr, 0, 1 ; yields {float}:val
store <ty> <value>, <ty>* <pointer> ; yields {void}
store <ty> <value>, <ty>* <arrayptr>{, uint <idx>}+ ; yields {void}
store <ty> <value>, <ty>* <structptr>{, ubyte <idx>}+ ; yields {void}e
The semantics of this instruction closely match that of the load instruction, except that memory is written to, not read from.
%ptr = alloca int ; yields {int*}:ptr
store int 3, int* %ptr ; yields {void}
%val = load int* %ptr ; yields {int}:val = int 3
%array = malloc [4 x ubyte] ; yields {[4 x ubyte]*}:array
store ubyte 124, [4 x ubyte]* %array, uint 4
%val = load [4 x ubyte]* %array, uint 4 ; yields {ubyte}:val = ubyte 124
%val = load {{int, float}}* %stptr, 0, 1 ; yields {float}:val
<result> = getelementptr <ty>* <arrayptr>{, uint <idx>}+ ; yields {ty*}:result
<result> = getelementptr <ty>* <structptr>{, ubyte <idx>}+ ; yields field type*
%aptr = getelementptr {int, [12 x ubyte]}* %sptr, 1 ; yields {[12 x ubyte]*}:aptr
%ub = load [12x ubyte]* %aptr, 4 ;yields {ubyte}:ub
| Other Operations |
%retval = call int %test(int %argc)
A new instruction icall or similar should be introduced to represent an indirect call.
Example:
%retval = icall int %funcptr(int %arg1) ; yields {int}:%retval
| Builtin Functions |
Builtin functions are very similar to normal functions, except they are defined by the implementation. Invocations of these functions are very similar to method invocations, except that the syntax is a little less verbose.
Builtin functions are useful to implement semi-high level ideas like a 'min' or 'max' operation that can have important properties when doing program analysis. For example:
Example:
; Example of a normal method call
%maximum = call int %maximum(int %arg1, int %arg2) ; yields {int}:%maximum
; Examples of potential builtin functions
%max = max(int %arg1, int %arg2) ; yields {int}:%max
%min = min(int %arg1, int %arg2) ; yields {int}:%min
%sin = sin(double %arg) ; yields {double}:%sin
%cos = cos(double %arg) ; yields {double}:%cos
; Show that builtin's are polymorphic, like instructions
%max = max(float %arg1, float %arg2) ; yields {float}:%max
%cos = cos(float %arg) ; yields {float}:%cos
The 'maximum' vs 'max' example illustrates the difference in calling semantics between a 'call' instruction and a builtin function invocation. Notice that the 'maximum' example assumes that the method is defined local to the caller.
| TODO List |
| Possible Extensions |
| Related Work |