definei32@main() { %1=loadi32,i32* @variable; load the global variable %2=muli32%1,2 storei32%2,i32* @variable; store instruction to write to global variable reti32%2 }
全局变量以 @ 字符为前缀。 您可以看到,诸如 main 之类的函数也是 LLVM 中的全局变量。 请注意,LLVM 将全局变量视为指针; 因此,在访问全局变量的值时,必须使用 load 指令显式对全局变量进行解引用,同样,您必须使用 store 指令显式存储全局变量的值。 在这方面,LLVM IR 比 C 更接近于汇编。
局部变量
LLVM中有两种局部变量。
临时变量或寄存器变量
栈上分配的局部变量
寄存器变量可以通过为变量引入一个新符号的方式来实现。
1
%reg=addi324,2
栈上分配的局部变量可以使用alloca指令来实现。
1
%stack=allocai32
几乎每条指令都会返回一个值,该值通常分配给一个临时变量。 由于 LLVM IR 的 SSA 形式,临时变量只能分配一次。 以下代码片段会产生错误:
definei32@main() #1 { ; these are the a, b, c in the scope of main %a=alloca%struct.Point,align8 %b=alloca%struct.Point,align8 %c=alloca%struct.Point,align8 ; these are copies, which are passed as arguments %1=alloca%struct.Point,align8 %2=alloca%struct.Point,align8 ; copy the global initializer main::a to %a %3=bitcast%struct.Point* %atoi8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3,i8* bitcast (%struct.Point* @main.atoi8*),i6424,i328,i1false) ; copy the global initializer main::b to %b %4=bitcast%struct.Point* %btoi8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4,i8* bitcast (%struct.Point* @main.btoi8*),i6424,i328,i1false) ; clone a to %1 %5=bitcast%struct.Point* %1toi8* %6=bitcast%struct.Point* %atoi8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5,i8* %6,i6424,i328,i1false) ; clone b to %1 %7=bitcast%struct.Point* %2toi8* %8=bitcast%struct.Point* %btoi8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* %7,i8* %8,i6424,i328,i1false) ; call add_points with the cloned values call void @add_points(%struct.Point* sret%c,%struct.Point* byvalalign8%1,%struct.Point* byvalalign8%2) ; [...] }
我们可以看到调用者,在我们的例子中是 main,为返回值 %c 分配空间,并且确保在通过引用实际传递参数之前克隆参数 a 和 b 。
ifletFoo::ABool(b) = x { println!("A boolean! {}", b) } ifletFoo::ABool(b) = y { println!("A boolean! {}", b) } ifletFoo::ABool(b) = z { println!("A boolean! {}", b) } }
; basic type definition %Foo=type { i8, [8xi8] } ; Variants of Foo %Foo_ABool=type { i8,i8 } ; tagged with 0 %Foo_AInteger=type { i8,i32 } ; tagged with 1 %Foo_ADouble=type { i8,double } ; tagged with 2
; allocate the first Foo %x=alloca%Foo ; pointer to the first element of type i8 (the tag) %0=getelementptrinbounds%Foo,%Foo* %x,i320,i320 ; set tag to '1' storei81,i8* %0 ; bitcast Foo to the right Foo variant %1=bitcast%Foo* %xto%Foo_AInteger* ; store the constant '42' %2=getelementptrinbounds%Foo_AInteger,%Foo_AInteger* %1,i320,i321 storei3242,i32* %2
; allocate and initialize the second Foo %y=alloca%Foo %3=getelementptrinbounds%Foo,%Foo* %y,i320,i320 ; this time the tag is '2' storei82,i8* %3 ; cast to variant and store double constant %4=bitcast%Foo* %yto%Foo_ADouble* %5=getelementptrinbounds%Foo_ADouble,%Foo_ADouble* %4,i320,i321 storedouble1.337000e+03,double* %5
要检查给定的 Foo 对象是否是某个变体,必须检索标签并将其与所需值进行比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
%9=getelementptrinbounds%Foo,%Foo* %x,i320,i320 %10=loadi8,i8* %9 ; check if tag is '0', which identifies the variant Foo_ABool %11=icmpi8%10,0 bri1%11, label %bb1, label %bb2