Llvm GEP Explained
1 min read
Why 0 in GEP
为什么生成的GEP会的第一个参数是0呢?官方文档过于晦涩,这篇博客很好的解释了这个问题。
long nums[] = {1, 2, 3};
long i;
long index_i(void) {
return nums[i];
}
@nums = dso_local global [3 x i64] [i64 1, i64 2, i64 3], align 16
@i = common dso_local global i64 0, align 8
define dso_local i64 @index_i() #0 {
%0 = load i64, i64* @i, align 8
%arrayidx = getelementptr inbounds [3 x i64], [3 x i64]* @nums, i64 0, i64 %0
%1 = load i64, i64* %arrayidx, align 8
ret i64 %1
}
简单来说数组和指针在LLVM里是严格区分的,不可以用C语言的方式来理解。传给GEP的参数必须是指针,因此实际上传的是指向数组的指针,因此索引方式为(&nums)[0][i]
,第一个0表示了数组地址。
How to use in IRBuilder
需要注意GEP返回的是一个指针,要用load或者store来使用
llvm::Type *elmType = ...;
llvm::ArrayType *arrayType = ...;
llvm::Value *array = ...;
size_t index = ...;
auto gep = builder.CreateGEP(arrayType, array,
{builder.getInt64(0), builder.getInt64(index)});
auto elm = builder.CreateLoad(elmType, gep);
... // do what you want with elm
同理的一个坑,如果一个C语言函数接受一个指针,在IR里传入的参数也需要用GEP来获取首地址
// Function signature
void func(int *array);
// LLVM code
auto gep = builder.CreateGEP(arrayType, array,
{builder.getInt64(0), builder.getInt64(0)});
auto ret = builder.CreateCall(func, gep);
Tags:
llvm