标签:LLVM

LLVM

llvm IR指令与llvm开发中对应的类与API

在llvm中间语言IR介绍中介绍了llvm中间语言IR相关的语法,重点介绍了指令相关的语法,llvm相关的语法远不止这些,之所以重点介绍指令相关的语法是因为我们学些llvm更多的是为了进行相关中间代码的优化,即基于llvm框架进行开发。而llvm开发本质上就类似用指令去完成函数功能,所以除了学习掌握中间语言IR的语法之外,更需要学会使用llvm提供给我们的API去实现这些功能,也就是需要掌握IR中相应指令在llvm中对应的类与API接口。 llvm的官方文档地址为:http://llvm.org/doxygen/modules.html ,这里详细介绍了llvm的所有模块,如下是其core部分 这一部分也是和我们使用llvm进行开发最相关的一部分。可以看到llvm的core模块主要包括以下几个部分 环境相关部分,如Contexts,Modules 类型Types 值Values 元数据Metadata 基本块Basic Block 指令Instructions 其中比较重要的是值Values,基本块BasicBlock和指令Instructions,llvm开发基本上使用最多的就是和这几个类相关的API接口,其中Values中使用最多就是常量Constant,从上图可以看到Constant主要可以概括为以下几个部分 标量常量Scalar Constants,比如整形常量ConstantInt,浮点型常量ConstantFP 组合常量Composite Constants,比如常量结构体ConstStruct,常量数组ConstantDataArray等 常量表达式Constant Expressions,主要是ConstantExpr这个类,该类有一个及其重要的API接口getGetElementPtr用来从多元素常量中获取首地址,比如获取数组,字符串的首地址 全局值Global Values,是全局变量和函数值的间接基类,换而言之就是全局值包括全局变量GlobalVariable和函数Function,全局值都有一个很重要的属性就是连接属性 全局变量Global Variables 全局别名Global Aliases 函数值Function values 从上面的图例中也可以看到我们开发中经常操作的一些元素在llvm中都是常量Constant的直接或间接子类,比如整形,浮点型,数组,字符串等,换而言之就是都是常量,这里的常量不是针对c/c++源码而言的,而是针对IR系统而言的 IRBuilder可以理解为是为方便开发者创建和插入指令而提供的一个帮助类,其作用是提供大量的用于创建/插入指令的API接口,这样做的好处是把原本需要在很多单个类中创建指令的API的功能集中到了IRBuilder这一个类中,举个例子:要创建一个IR中的gep指令,如果使用对应的类的话需要调用GetElementPtrInst类的Create函数,要创建一个alloca指令使用对应类的话需要使用AllocaInst类的构造函数AllocaInst,如果使用IRBuilder类则创建gep指令只需调用IRBuilder类的CreateGEP函数,创建alloca指令只需调用IRBuilder类的CreateAlloca函数,这样开发者就不需要记住很多类,如果有很多指令要创建,使用IRBuilder来创建指令比使用该指令对应的原始类来创建要方便的多。关于IRBuilder的官方介绍可以参看:http://llvm.org/doxygen/classllvm_1_1IRBuilder.html IRBuilder类一些重要的API接口和功能如下所示: 在llvm中常量数组用ConstantDataArray类表示,该类继承自ConstantDataSequential(常量数据序列,后面简称为CDS) 在llvm中没有专门的字符串类,因为实际上对于计算机底层而言都是对内存操作,字符串类可以看做是char[],而每一个char是8位,所以字符串可以看做是一个常量序列,该常量序列的每一个元素是无符号int8类型。正如前面所说的创建字符串对象可以使用ConstantDataArray的getString方法,然后将其传递给一个全局变量作为初始化的参数,另外一般而言c/c++中的很多函数对于字符串的操作都是通过传递该字符串首地址的指针进行的,比如printf函数。所以我们可以在前面那段代码基础上增加一个获取该变量首地址的操作,获取字符串首地址可以使用ConstantExpr这个类的getGetElementPtr函数。此时对字符串的操作的代码如下所示: [crayon-5f03a7bf434e1977372458/] 另外llvm中临时字符串可以使用StringRef和Twine来描述。 http://llvm.org/doxygen/classllvm_1_1GlobalValue.html, 全局值也是常量,继承自Constant,主要包括函数Function和全局变量GlobalVariable  

LLVM

llvm中间语言IR介绍

首先使用编译器前端clang执行如下命令即可得到中间语言IR, [crayon-5f03a7bf439d7333595460/] 其中的ori_cpp_file表示原始的cpp文件,out_ir_file表示编译后输出的IR文件。执行该命令后即会在out_ir_file路径下生成源cpp文件的llvm的汇编代码。该命令等同于执行如下命令: [crayon-5f03a7bf439e0980537810/] 如果不加-S参数那么生成的会是源cpp文件的二进制代码。 为了了解IR的语法,我们可以写一段简单的cpp源文件,然后使用clang执行前面说的命令来对比查看下生成的IR文件的内容从而来熟悉IR的语法,为了能够尽可能多的覆盖IR的语法,cpp源文件原本需要尽量包含更多变量类型和程序结构,比如字符串,整数,数组,条件分支,for/while循环结构等。但是为了更容易上手,我们可以把这些结构拆分开来每次只放到一个单独的cpp文件中,然后逐个编译,而不推荐一开始就混在一个cpp文件中,因为即使是一个简单的hello word程序其IR的代码量也是很大的,所以对于初学者而言,混在一起反而不容易上手,等基本语法都熟悉了可以在写个复杂的涵盖程序所有变量类型和程序结构的cpp文件一次性编译查看。