LLVM IR GetElementPtr指令简介

getelementptr是LLVM IR里的一个用于计算指针偏移量的指令,非常常见但是又非常容易引起误解。 内容参考——GetElementPtrLLVM IR tutorial

getelementptr指令只是计算偏移量,不对指针做解引用。

语法:

<result> = getelementptr <ty>, ptr <ptrval>{, <ty> <idx>}*
<result> = getelementptr inbounds <ty>, ptr <ptrval>{, <ty> <idx>}*
<result> = getelementptr nusw <ty>, ptr <ptrval>{, <ty> <idx>}*
<result> = getelementptr nuw <ty>, ptr <ptrval>{, <ty> <idx>}*
<result> = getelementptr inrange(S,E) <ty>, ptr <ptrval>{, <ty> <idx>}*<result> = getelementptr <ty>, <N x ptr> <ptrval>, <vector index type> <idx>

太复杂,先只考虑最简单的情况

<result> = getelementptr <ty>, ptr <ptrval>{, <ty> <idx>}* 第一个参数<ty> 代表要用什么样的类型解读第二个参数<ptrval>,这个类型为聚合类型,即结构体、数组或者向量。

第二个参数<ptrval>是一个value,是一个指针,作为指针偏移量计算的起始点。 {, <ty> <idx>}*是正则表达式的记号,表示<ty> <idx>这个结构可出现0次或多次,其中<ty>为整形,idx为具体的索引值。

考虑以下样例:

struct complicate{
  int x;
  long y;
  struct insideComplicate{
    int x;
    long y;
  } z;
  char a[10];
};

char accessA(struct complicate* c){
  c->z.y = 3;
  c->a[3] = 'c';
  return c->a[5];
}

采用clang file.c -O2 -o file -c -emit-llvm编译(-O2用以生产更简洁的IR),得到以下IR:

%struct.complicate = type { i32, i64, %struct.insideComplicate, [10 x i8] }

%struct.insideComplicate = type { i32, i64 }

define dso_local signext i8 @accessA(ptr nocapture noundef %0) local_unnamed_addr #2 {
  %2 = getelementptr inbounds %struct.complicate, ptr %0, i64 0, i32 2, i32 1
  store i64 3, ptr %2, align 8, !tbaa !13
  %3 = getelementptr inbounds %struct.complicate, ptr %0, i64 0, i32 3, i64 3
  store i8 99, ptr %3, align 1, !tbaa !17
  %4 = getelementptr inbounds %struct.complicate, ptr %0, i64 0, i32 3, i64 5
  %5 = load i8, ptr %4, align 1, !tbaa !17
  ret i8 %5
}

c->z.y 被解析成getelementptr inbounds %struct.complicate, ptr %0, i64 0, i32 2, i32 1,其中%0c, 第一组i64 0可看作由%struct.complicate组成的数组里取第一个元素,第二组i32 2表示在%struct.complicate这个结构体类型里取第三个元素,注意——这里的第三个元素仅仅就是第三个元素,与每个元素的字节数无关。在%struct.complicate中,第一个元素为i32,第二个元素为i64,第三个元素为%struct.insideComplicate,因此第二组i32 2取到%struct.insideComplicate。第三组i32 1对类型%struct.insideComplicate取第二个元素i64,于是完成c->z.y的取地址工作。

剩下两条getelementptr指令与源码的对应关系留给读者。