diff --git a/docs/tutorials/07-ir-generation-1-llvm.md b/docs/tutorials/07-ir-generation-1-llvm.md index c697dda..7f02b75 100644 --- a/docs/tutorials/07-ir-generation-1-llvm.md +++ b/docs/tutorials/07-ir-generation-1-llvm.md @@ -1211,17 +1211,19 @@ LVal → Ident {'[' Exp ']'} 现在来理解一下上面这一条指令。第一个 `` 表示的是第一个索引所指向的类型,有时也是**返回值的类型**。第二个 `` 表示的是后面的指针基地址 `` 的类型, ` ` 表示的是一组索引的类型和值,在本实验中索引的类型为 `i32`。索引指向的基本类型确定的是增加索引值时指针的偏移量。 -说完理论,不如结合一个实例来讲解。考虑数组 `a[5]`,需要获取 `a[3]` 的地址,有如下写法: +说完理论,不如结合一个实例来讲解。考虑数组 `a[5]`,需要获取 `a[3]` 的地址,有如下两种写法: ```llvm +; 方法一 %1 = getelementptr [5 x i32], [5 x i32]* @a, i32 0, i32 3 +; 方法二 %2 = getelementptr [5 x i32], [5 x i32]* @a, i32 0 %3 = getelementptr i32, i32* %2, i32 3 - -%3 = getelementptr i32, i32* @a, i32 3 ``` +当数组作为参数时,需要先将其转换为指针类型,即方法二中的第一条指令。在被调用的函数中,对于指针类型的参数,使用方法二中的第二条指令即可获取对应下标元素的地址。 + ### (2)数组定义与调用 这一章将主要讲述数组定义和调用,包括全局数组,局部数组的定义,以及函数中的数组调用。对于全局数组定义,与全局变量一样,同学们需要将所有量**全部计算到特定的值**。对于一个维度内全是 0 的地方,可以采用 `zeroinitializer` 来统一置 0。 @@ -1248,8 +1250,6 @@ char c[8] = "foobar"; @c = dso_local global [8 x i8] [i8 102, i8 111, i8 111, i8 98, i8 97, i8 114, i8 0, i8 0] ``` -当然,`zeroinitializer` 不是必须的,同学们完全可以一个个 `i32 0` 写进去,但对于一些很阴间的样例点,不用 `zeroinitializer` 可能会导致 **TLE** ,例如全局数组 `int a[1000];` ,不使用该指令就需要输出 **1000 次 i32 0**,必然导致 TLE,所以还是推荐同学们使用 `zeroinitializer`。 - 对于局部数组,在定义的时候同样需要使用 `alloca` 指令,其存取指令同样采用 **load 和 store**,只是在此之前需要采用 `getelementptr` 获取数组内应位置的地址。 字符数组的字符串常量初始化,可以自行设计实现。LLVM IR 中,全局字符数组的字符串常量初始化可以直接通过字符串赋值,局部字符数组则也需要通过 `alloca` 指令分配内存空间,逐个元素初始化。不要忘记字符串常量末尾的结束符 '\00' 和填充符号 '\00'。