我一直在试图理解LLVM的GetElementPtr (GEP)指令,并遇到了这个文档:
http://llvm.org/docs/GetElementPtr.html它很有帮助,但有几件事我觉得很困惑。特别是,在"GEP对什么进行了取消引用?"' (http://llvm.org/docs/GetElementPtr.html#id6)下面的代码被讨论:
%MyVar = uninitialized global { [40 x i32 ]* }
...
%idx = getelementptr { [40 x i32]* }, { [40 x i32]* }* %MyVar, i64 0, i32 0, i64 0, i64 17
%MyVar
是一个全局变量,它是一个指向结构体的指针,该结构体包含一个指向40个int型数组的指针。这很清楚。我理解%MyVar
之后的参数是它的索引,但我不明白为什么其中一些被声明为i64
而另一些被声明为i32
。
我的理解是这段代码是为64位机器编写的,并且指针被假定为64位宽。%MyVar
所指向的数组的内容是32位宽的。为什么最后一个索引是i64 17
而不是i32 17
呢?
我还应该指出,这个例子说明了GEP的非法使用(结构中的指针必须被解引用,以便索引到40个int型数组),我试图很好地理解为什么会出现这种情况。
这个问题的答案是nothing。这意味着GEP永远不会对指针解引用:它只根据您传递给它的指针计算新地址。它从不读取任何内存。
看这个例子:
%idx = getelementptr { [40 x i32]* }, { [40 x i32]* }* %MyVar, i64 0, i32 0, i64 0, i64 17
我们从%MyVar
开始,这是一个{ [40 x i32]* }*
,一个指向结构体的指针,其中包含指向数组的指针。
在用i64 0
索引之后,我们有一个对{ [40 x i32]* }
结构体的引用。%MyVar
已经指向这个,不需要解引用。
在索引第二个i32 0
之后,我们现在引用[40 x i32]*
,这是该结构体的唯一成员。它具有与结构体本身相同的内存位置,即%MyVar
。
第三个索引i64 0
现在指向[40 x i32]
数组本身。这是非法的。 GEP需要对前一步获得的指针解引用才能获得该内存地址。一般来说,GEP永远不能"通过"指针索引,除了传递给它的初始值总是指针的明显例外。
我还将指出i32 0
和i64 0
对于索引的目的是相同的,它们都指向struct/array中的第一个元素。对于前面提到的常量17
也是如此。