i1 ; — 0 1<br/> i32 ; 32- <br/> i17 ; <br/> i256 ; !
The generation of machine code for types of very large bit width is not supported. For example, for x86 you will have to limit to i64
, and for x86-64 and other 64-bit platforms - to 128-bit integers. But for intermediate representation there are no restrictions.float
, double
, and a number of platform-specific types (for example, x86_fp80
).void
is an empty value.*<br/> i32* ; 32- <br/>
[ x ]<br/> [10 x i32]<br/> [8 x double]<br/>
{ i32, i32, double }
< x ><br/> < 4 x float ><br/>
i32 (i32, i32)<br/> float ({ float, float }, { float, float })<br/>
%
, and global values ​​are @
. Local values ​​are also called registers, and LLVM - a virtual machine with an infinite number of registers. Example:%sum = add i32 %n, 5<br/> %diff = sub double %a, %b<br/> %z = add <4 x float> %v1, %v2 ; <br/> %cond = icmp eq %x, %y ; . i1.<br/> %success = call i32 @puts(i8* %str)<br/>
The type of operands is always specified explicitly, and uniquely identifies the type of the result. The operands of arithmetic instructions must be of the same type, but the instructions themselves are “overloaded” for any numeric types and vectors.bitcast
, etc. In addition, there are conversion instructions between integers and pointers, as well as a bitcast
instruction that will lead everything but you are responsible for the result.; x = (a + b) * c - d / e <br/> %tmp1 = add float %a, %b <br/> %tmp2 = mul float %tmp1, %c <br/> %tmp3 = fdiv float %d, %e <br/> %x = sub float %tmp2, %tmp3 <br/>
Looking ahead, beyond the scope of this article, we note that when using the LLVM API to generate code, everything becomes even simpler, because it follows the principle “instruction is the meaning”. We will not have to deal with the generation of unique names for intermediate values: the function that generates the instruction returns a value (a C ++ object) that can be passed as an argument to other such functions.%z = sum i32 %x, %y <br/> %z = sum i32 %z, 5 <br/>
The new value should get a new name:%z.1 = sum i32 %z, 5
However, you ask how to be if the same variable should receive different values ​​depending on some condition? Or how to organize a loop variable?ret
- return value from functionbr i1 , label _1 , label _2
- conditional transition. For example:define float @max(float %x, float %y) <br/> { <br/> %cond = fcmp ogt float %x, %y <br/> br i1 %cond, label %IfTrue, label %IfFalse <br/> IfTrue: <br/> ret float %x <br/> IfFalse: <br/> ret float %y <br/> }
(I think the syntax of the function definition is obvious).br label
switch
- generalization br
, allows you to organize the transition table:switch i32 %n, label %Default, [i32 0, label %IfZero i32 5, label %IfFive]
invoke
and unwind
are used to organize exceptions, in this article we will not dwell on them.unreachable
is a special instruction showing the compiler that execution will never reach this point. For example, this instruction may be inserted after calling the system function terminating the process.phi , [_1, label _1], ..., [_N, label _N]
As an example, consider the factorial calculation function, which could be written in C as follows:int factorial(int n) <br/> { <br/> int result = n; <br/> int i; <br/> for (i = n - 1; i > 1; --i) <br/> result *= i; <br/> return result; <br/> } <br/>
Note: a block that starts from entering a function is indicated by %0
.define i32 @factorial(i32 %n) <br/> { <br/> %i.start = sub i32 %n, 1 <br/> br label %LoopEntry <br/> LoopEntry: <br/> %result = phi i32 [%n, %0], [%result.next, %LoopBody] <br/> %i = phi i32 [%i.start, %0], [%i.next, %LoopBody] <br/> %cond = icmp sle i32 %i, 1 <br/> br i1 %cond, label %Exit, label %LoopBody <br/> LoopBody: <br/> %result.next = mul i32 %result, %i <br/> %i.next = sub i32 %i, 1 <br/> br label %LoopEntry <br/> Exit: <br/> ret i32 %result <br/> }
Do not be confused by the seemingly meaningless transitions to the label immediately following the transition instruction. As we have said, the base unit must end with an explicit control transfer. LLVM also requires that all phi instructions go at the beginning of the block, and there were no other instructions before them.load
and store
. For example:%x = load i32* %x.ptr ; i32 %x.ptr <br/> %tmp = add i32 %x, 5 ; 5 <br/> store i32 %tmp, i32* %x.ptr ; <br/>
But to use pointers, you need to somehow allocate memory for the values ​​to which they point.malloc
instruction is translated into a call to the system function of the same name and allocates memory on the heap, returning a value - a pointer of a certain type. Together with her, of course, there is an instruction free
.%struct.ptr = malloc { double, double } <br/> %string = malloc i8, i32 %length <br/> %array = malloc [16 x i32] <br/> free i8* %string <br/>
There is no official recommendation not to use the malloc
instruction, but developers admit that there is not much point in its existence now. You can call @malloc
function @malloc
or write your own allocator function that meets some special requirements.%x.ptr = alloca double ; %x.ptr double* <br/> %array = alloca float, i32 8 ; %array float*, [8 x float]! <br/>
The memory allocated by alloca
is automatically freed upon exiting the function using the ret
or unwind
instructions.alloca
, load
and store
we can use local variables in the same way as in any imperative language. For example, our long-suffering factorial function:define i32 @factorial(i32 %n) <br/> { <br/> %result.ptr = alloca i32 ; result <br/> %i.ptr = alloca i32 ; i <br/> store i32 %n, i32* %result.ptr ; result = n <br/> %tmp1 = sub i32 %n, 1 <br/> store i32 %tmp1, i32* %i.ptr ; i = n - 1 <br/> br label %Loop <br/> Loop: <br/> %i = load i32* %i.ptr ; i <br/> %cond = icmp sle i32 %i, 1 ; i <= 1<br/> br i1 %cond, label %Exit, label %LoopBody ; , <br/> LoopBody: <br/> %tmp2 = load i32* %result.ptr <br/> %tmp3 = mul i32 %tmp2, %i <br/> store i32 %tmp3, i32* %result.ptr ; result *= i <br/> %i.next = sub i32 %i, 1 <br/> store i32 %i.next, i32* %i.ptr ; --i <br/> br label %Loop <br/> Exit: <br/> %result = load i32* %result.ptr <br/> ret i32 %result ; return result <br/> } <br/>
Verbose enough, but tell me, where else besides a similar article will you write the code on LLVM manually? :-)factorial
function after passing this algorithm:define i32 @factorial(i32 %n) { <br/> ; <label>:0 <br/> %tmp1 = sub i32 %n, 1 <br/> br label %Loop <br/> Loop: <br/> %i.ptr.0 = phi i32 [ %tmp1, %0 ], [ %i.next, %LoopBody ] <br/> %result.ptr.0 = phi i32 [ %n, %0 ], [ %tmp3, %LoopBody ] <br/> %cond = icmp sle i32 %i.ptr.0, 1 <br/> br i1 %cond, label %Exit, label %LoopBody <br/> LoopBody: <br/> %tmp3 = mul i32 %result.ptr.0, %i.ptr.0 <br/> %i.next = sub i32 %i.ptr.0, 1 <br/> br label %Loop <br/> Exit: <br/> ret i32 %result.ptr.0 <br/> } <br/>
%ptr = add i32* %array, i32 %index
To calculate the addresses of elements of arrays, structures, etc. with the correct typing, there is a special instruction getelementptr
.%array = alloca i32, i32 %size <br/> %ptr = getelementptr i32* %array, i32 %index ; i32* <br/>
getelementptr
only calculates the address, but does not access memory. The instruction takes an arbitrary number of indices and can dereference structures of any nesting. For example, from the following C code:struct s { <br/> int n; <br/> char *a[4]; <br/> }; <br/> struct *s = ...; <br/> char c = s->a[2][5]; <br/>
the following sequence of instructions will be generated:%ptr = getelementptr { i32, [4 x i8*] }* %s, i32 1, i32 2, i32 5 <br/> %c = load i8* %ptr <br/>
As you can see, indexes are counted from zero.extractvalue
and insertvalue
instructions extractvalue
are very similar to insertvalue
. They differ in that they take not a pointer to an aggregate data type (array or structure), but a value of this type itself. extractvalue
returns the corresponding value of the sub-element, not a pointer to it, but insertvalue
generates a new value of the aggregate type.%n = extractvalue { i32, [4 x i8*] } %s, 0 <br/> %tmp = add i32 %n, 1 <br/> %s.1 = insertvalue { i32, [4 x i8*] } %s, i32 %tmp, 0 <br/>
@llvm.sqrt.*
, @llvm.sin.*
, Etc. There are also primitives for atomic operations and some others.%llvm.dbg.stoppoint
are inserted into IR (sets the correspondence between lines of the source code and the generated code), %llvm.dbg.declare
(sets the description of a local variable), etc. as arguments to which pointers to special structures are passed.@llvm.gcroot
, @llvm.gcread
and @llvm.gc.write
allow you to encode the information needed for the GC to work, and the plug-in interface to the LLVM compiler to generate the necessary data structures from this information and insert calls to runtime.int factorial(int n) <br/> { <br/> if (n < 2) return 1; <br/> return n * factorial(n - 1); <br/> } <br/>
Source: https://habr.com/ru/post/47878/
All Articles