我对llvm如何访问数组感到困惑。
对于二维数组,如
int a[5][5];
int func1(){
return a[1][2];
}
翻译的llvm-ir是
@a = global [5 x [5 x i32]] zeroinitializer, align 16
define i32 @func1() #0 {
entry:
%0 = load i32, i32* getelementptr inbounds ([5 x [5 x i32]], [5 x [5 x i32]]* @a, i64 0, i64 1, i64 2), align 4
ret i32 %0
}
我认为应该首先使用索引1来获取内部维度';[5 x i32] ';然后使用索引2来获取&;i32&;
但是当一个二维数组作为函数参数(或数组指针)时,事情就变得奇怪了
int func2(int a[][5]){
return a[2][3];
}
define i32 @func2([5 x i32]* %a) #0 {
entry:
%a.addr = alloca [5 x i32]*, align 8
store [5 x i32]* %a, [5 x i32]** %a.addr, align 8
%0 = load [5 x i32]*, [5 x i32]** %a.addr, align 8
%arrayidx = getelementptr inbounds [5 x i32], [5 x i32]* %0, i64 2
%arrayidx1 = getelementptr inbounds [5 x i32], [5 x i32]* %arrayidx, i64 0, i64 3
%1 = load i32, i32* %arrayidx1, align 4
ret i32 %1
}
我不知道我的理解是否正确。
似乎"a"已加载到%0,且当前%0的类型为"[5 x i32]*">
%0 = load [5 x i32]*, [5 x i32]** %a.addr, align 8
然后使用"%0"访问外部维度的"a",但现在"%0"被认为是"[5 x i32]"one_answers"%arrayidx"将会有"i32"
%arrayidx = getelementptr inbounds [5 x i32], [5 x i32]* %0, i64 2
然后就更奇怪了,"%arrayidx"仍然被认为是"[5 x i32]",但它实际上是"i32">
%arrayidx1 = getelementptr inbounds [5 x i32], [5 x i32]* %arrayidx, i64 0, i64 3
怎么解释?如何使用像Builder.CreateInBoundsGEP(type, array, Idxs);
这样的API来生成它?这似乎不可能,因为我试过了
// type is "[5 x i32]" and array also has a type of "[5 x i32]", inorder to generate the same ir
// as %arrayidx = getelementptr inbounds [5 x i32], [5 x i32]* %0, i64 2
auto arrayidx = Builder.CreateInBoundsGEP(type, array, Idxs)
// but now arrayidx is "i32" and now type and the type of arrayidx is not match
auto arrayidx1 = Builder.CreateInBoundsGEP(type, arrayidx, Idxs)
%arrayidx = getelementptr inbounds [5 x i32], [5 x i32]* %0, i64 2
%0
和%arrayidx
都是[5 x i32]*
。
B = getelementptr <type>, <type>* A, i64 idx0
类似于B = &A[idx0]
。
%arrayidx1 = getelementptr inbounds [5 x i32], [5 x i32]* %arrayidx, i64 0, i64 3
%arrayidx1
是i32*
。
C = getelementptr <type>, <type>* B, i64 idx0, i64 idx1
类似于C = &B[idx0][idx1]