Lab 7 实验指导

理解 getElementPtr 指令

在你准备动手写这个 lab 之前,我们强烈建议你先自己写几个带有数组的程序并自己编译为 LLVM IR 看一下不同情况下 clang 是怎么做的,不然你可能会对 getElementPtr(下面简称为 GEP) 这个指令感到迷惑。如果你看完实验指导并且生成了自己的代码之后还是有疑问,可以浏览 这里

LLVM 的指针操作 GEP 指令几乎是所有指针计算的关键。

GEP 指令的工作是“计算地址”,本身并不进行任何数据的访问和修改。GEP 指令的最基本语法为 <result> = getelementptr <ty>, <ty>* <ptrval>, {<ty> <index>}*,其中第一个 <ty> 表示第一个索引所指向的类型,第二个 <ty> 表示后面的指针基址 <ptrval> 的类型,<ty> <index> 表示一组索引的类型和值。要注意索引的类型和索引指向的基本类型是不一样的,索引的类型一般为 i32i64 ,而索引指向的基本类型确定的是增加索引值时指针的偏移量。

第一个索引不会改变返回的指针的类型,也就是说 ptrval 前面的 <ty>* 对应什么类型,返回就是什么类型;第一个索引的偏移量的是由第一个索引的值和第一个 ty 指定的基本类型共同确定的。

gep1

上图中第一个索引指向的基本类型是 [6 x i8],索引值是 1,所以 GEP 指令返回的值相对基址 @a_gv 前进了 6 个字节。由于只有一个索引,所以返回的指针也是 [6 x i8]* 类型。

而对于后面的索引,每增加一个索引,就会使得该索引使用的基本类型和返回的指针的类型去掉一层。

gep2

上图中 %elem_ptr = getelementptr [6 x i8], [6 x i8]* @a_gv, i32 0, i32 1 这一句中第一个索引值是 0,指向的类型是 [6 x i8],因此其使返回的指针先前进 0 x 6 个字节,也就是不前进。第二个索引的值是 1,使用的基本类型就是 i8[6 x i8] 去掉左边的 6),因此其使返回的指针前进一个字节,返回的指针类型为 i8*

GEP 指令对于新上手的程序员来说比较难理解,所幸我们实验中涉及到指针计算的部分只有数组,而且高维数组可以用一个一维数组来模拟,比如一个 [4][5] 的二维数组,我们可以用一个 [20] 的一维数组来模拟,这就极大的减少了我们的工作量。

下面对数组 a[5][4] 中使用 GEP 指令计算 a[2][3] 的地址,给出几个使用 GEP 指令的示例:

; 1
@a = global [5 x [4 x i32]] zeroinitializer
%1 = getelementptr [5 x [4 x i32]], [5 x [4 x i32]]* @a, i32 0, i32 2, i32 3 ; %1 类型为 i32*

; 2
@a = global [5 x [4 x i32]] zeroinitializer
%1 = getelementptr [5 x [4 x i32]], [5 x [4 x i32]]* @a, i32 0, i32 2  ; %1 类型为 [4 x i32]*,可以理解为 C 语言中指向长度为 4 的一维数组基址的指针
%2 = getelementptr [4 x i32], [4 x i32]* %1, i32 0, i32 3 ; %2 类型为 i32*

; 3
@a = global [5 x [4 x i32]] zeroinitializer
%1 = getelementptr [5 x [4 x i32]], [5 x [4 x i32]]* @a, i32 0, i32 0  ; %1 类型为 [4 x i32]*
%2 = getelementptr [4 x i32], [4 x i32]* %1, i32 2, i32 3 ; %2 类型为 i32*

; 4
@a = global [20 x i32] zeroinitializer
%1 = mul i32 2, 4
%2 = add i32 %1, 3
%3 = getelementptr [20 x i32], [20 x i32]* @a, i32 0, i32 %2 ; %3 类型为 i32*

; 5
@a = global [20 x i32] zeroinitializer
%1 = getelementptr [20 x i32], [20 x i32]* @a, i32 0, i32 0 ; %1 类型为 i32*
%2 = mul i32 2, 4
%3 = getelementptr i32, i32* %1, i32 %2 ; %3 类型为 i32*
%4 = getelementptr i32, i32* %3, i32 3 ; %4 类型为 i32*

results matching ""

    No results matching ""