编译器架构的王者LLVM——(11)深入理解GetElementPtr

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 —— 题记

版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy

深入理解GetElementPtr

LLVM平台,和C语言极为类似,强类型,需要复杂的指针操作,基于系统的符号调用等。而LLVM的指针操作指令,GetElementPtr,几乎是所有指针计算的关键,而理解它个运作原理,正确的使用,非常的重要。

强类型的LLVM

编写LLVM需要时刻记住,LLVM是强类型的,每一条语句,都有确定的类型,GetElementPtr也正是这样,不同的参数,会有不同类型的返回类型。

我们先来看一段LLVM官网上的示例:

struct munger_struct {
  int f1;
  int f2;
};
void munge(struct munger_struct *P) {
  P[0].f1 = P[1].f1 + P[2].f2;
}
...
munger_struct Array[3];
...
munge(Array);

我们用Clang以C格式编译这段代码,munge函数会编译成如下IR:

void %munge(%struct.munger_struct* %P) {
entry:
  %tmp = getelementptr %struct.munger_struct* %P, i32 1, i32 0
  %tmp = load i32* %tmp
  %tmp6 = getelementptr %struct.munger_struct* %P, i32 2, i32 1
  %tmp7 = load i32* %tmp6
  %tmp8 = add i32 %tmp7, %tmp
  %tmp9 = getelementptr %struct.munger_struct* %P, i32 0, i32 0
  store i32 %tmp8, i32* %tmp9
  ret void
}

我们仔细来观察一下,每一条指令,都有明确的指明 P 指针的类型为 %struct.munger_struct*

而下面的load语句,也间接说明了返回类型为 i32*

我们在正确理解GetElementPtr的工作方式时,必须时刻了解对应的类型,这样才不会偏差。

GetElementPtr的指令规则

GetElementPtr指令其实是一条指针计算语句,本身并不进行任何数据的访问或修改,进行是计算指针,修改计算后指针的类型。

GetElementPtr至少有两个参数,第一个参数为要进行计算的原始指针,往往是一个结构体指针,或数组首地址指针。

第二个参数及以后的参数,都称为indices,表示要进行计算的参数,如结构体的第几个元素,数组的第几个元素。

下面我们结合示例,来对应看一下是如何工作的:

    P[0].f1 

这是示例代码中的被赋值指针,我们C语言的经验告诉我们,首先P[0]的地址就是数组的首地址,而f1又是结构体的第一个参数,那么P的地址就是我们最终要放置数据的结构地址。

这条地址计算对应如下语句:

    %tmp9 = getelementptr %struct.munger_struct* %P, i32 0, i32 0

我们发现参数是两个0,这两个0含义不大一样,第一个0是数组计算符,并不会改变返回的类型,因为,我们任何一个指针都可以作为一个数组来使用,进行对应的指针计算,所以这个0并不会省略。

第二个0是结构体的计算地址,表示的是结构体的第0个元素的地址,这时,会根据结构体指针的类型,选取其中的元素长度,进行计算,最后返回的则是结构体成员的指针。

同理,我们可以对照参考这两条语句:

    P[1].f1
    P[2].f2

对应的计算翻译后为:

  %tmp = getelementptr %struct.munger_struct* %P, i32 1, i32 0
  %tmp6 = getelementptr %struct.munger_struct* %P, i32 2, i32 1

注意事项

首先,不是全部的indices都必须是i32,也可以是i64,但结构体的计算地址,也就是上面例子中的第二个数字,必须是i32

GEP x,1,0,0 和 GEP x,1 计算后的地址是一样的,但类型不一样,所以千万注意不要在语句后添加多余的0。

其他情况

仅有数组计算

如果仅有数组指针计算,那么就简单了许多,数组指针的移动只需要一个参数即可。

但如果是仅有结构体指针,那么还是必须两个参数才行

多维数组

个人觉得LLVM的数组定义很难写,推荐自己用一维数组代替,比较计算也不复杂。这样高维数组统一化成一维后,都成了基本的指针计算,就非常简单了。

连续选取

GetElementPtr基本上可以认为是不限参数长度的,可以连续选取,于是我们可以实现:

    A->B->C

这类连续指向的计算。

但个人不推荐这样做,尤其是语法驱动的编译时,也很难做到这点,建议分开一条一条的语句进行执行,分别选取。

参考

http://llvm.org/docs/GetElementPtr.html

最近研究的LLVM技术,大部分应用于在进行的ELite编译器开发,欢迎朋友们关注和参与。

https://github.com/elite-lang/Elite

时间: 2024-11-03 22:34:59

编译器架构的王者LLVM——(11)深入理解GetElementPtr的相关文章

编译器架构的王者LLVM——(8)函数的调用及基本运算符

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 函数的调用及基本运算符 之前我们提到了函数的定义,那么,定义好的函数如何调用才行呢?今天我们就来了解一下,函数的调用. 函数调用的宏形式 我们去读之前对函数调用的语法树翻译形式: printf("%d\

编译器架构的王者LLVM——(7)函数的翻译方法

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 函数的翻译方法 前面介绍了许多编译器架构上面的特点,如何组织语法树.如果多遍扫描语法树.今天开始,我们就要设计本编译器中最核心的部分了,如何设计一个编译时宏,再利用LLVM按顺序生成模块. 设计宏 我们

编译器架构的王者LLVM——(10)变量的存储与读取

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 变量的存储与读取 变量是一款编程语言中的核心,说编译语言是一种符号处理工具,其实是有些道理的.栈式符号表可以方便的记录编译过程中的变量和语法符号,我们上节已经了解了其中的实现方法.那么,还有没有其他的办

编译器架构的王者LLVM——(9)栈式符号表的构建

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 栈式符号表的构建 栈式符号表对于一款编译器,无疑是核心的组件. 无论你在做什么符号扫描,那么都离不开符号表,如何得知一个符号是否定义,以及它的类型,那么唯有查看符号表中的记录. 栈式符号表并不复杂,但思

编译器架构的王者LLVM——(5)语法树模型的基本结构

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 语法树模型的基本结构 上次我们看了Lex和Yacc的翻译文件,可能一些朋友并不了解其中的执行部分,而且,对这个抽象语法树是怎么构建起来的还不清楚.今天我们就再详细介绍一下如果方便的构建一棵抽象语法树(A

架构设计中服务层的简单理解

如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 在ddd设计中我们经常会提到服务层,服务层是什么?职责是什么?有什么好处?. 先看简单的层次图(注:这里并没有考虑其他多余的领域逻辑数据层存储,或者UOW这些细节) 我的理解是服务层是处于我的应用程序业务层和表现层之间的应用程序边界,边界可能是很薄的一层类设计或者是分布式服务网络跃点.它是一个与技术无关的名词.由表现层直接调用,契约,执行命令(修改状态(CUD))或者是查询返回dto(数据迁

1×1卷积核理解

1*1的卷积核在NIN.Googlenet中被广泛使用,但其到底有什么作用也是一直困扰的问题,这里总结和归纳下在网上查到的自认为很合理的一些答案,包括1)跨通道的特征整合2)特征通道的升维和降维  3)减少卷积核参数(简化模型) 1 - 引入 在我学习吴恩达老师Deeplearning.ai深度学习课程的时候,老师在第四讲卷积神经网络第二周深度卷积网络:实例探究的2.5节网络中的网络以及1×1卷积对1×1卷积做了较为详细且通俗易懂的解释.现自己做一下记录. 2 - 1×1卷积理解 假设当前输入张

LLVM 3.9 发布,编译器架构

LLVM 3.9 发布了,LLVM 是 Low Level Virtual Machine (低级虚拟机)的简称,这个库提供了与编译器相关的支持,可以作为多种语言编译器的后台来使用.能够进行程序语言的编译期优化.链接优化.在线编译优化. 代码生成.LLVM的项目是一个模块化和可重复使用的编译器和工具技术的集合(app开发ty300.com).LLVM是伊利诺伊大学的一个研究项目,提供一个现代化的,基于SSA的编 译策略能够同时支持静态和动态的任意编程语言的编译目标(入门教程qkxue.net).

LLVM 3.6 发布,编译器架构

LLVM 3.6 发布,此版本现已提供在:http://llvm.org/releases/.此版本是 LLVM 社区辛苦开发六个月的结果,包括大量 bug 修复,优化改进,Clang 支持更多被提议的  C++1z 功能,更好的原生 Windows 兼容性,本地对象文件中嵌入 LLVM IR,绑定 Go 等等,更多内容请看发行说明 [LLVM, Clang]. LLVM 是 Low Level Virtual Machine (低级虚拟机)的简称,这个库提供了与编译器相关的支持,可以作为多种语