一起学习LLVM(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feibabeibei_beibei/article/details/88073678

学习LLVM的源码目录:

一、LLVM的周边项目:

1.clang、llvm、clang-tools-extra、compiler-rt:

clang+LLVM:clang是LLVM的前端,把各种源码编译处理;

clang-tools-extra:clang默认以外的认为不是很重要的工具;

Compiler-RT 项⽬为硬件不⽀持的低级功能提供特定的⽀持。例如,32位

⽬标通常缺少⽀持64位除法的指令, Compiler-RT 通过提供特定⽬标的优

化函数来解决此问题,使⽤这样的函数可以在32位指令处理器上实现64位

除法。为LLVM IR;

eg:clang -S -m32 test.c -o test-32bit.S

clang -S test.c -o test-64bit.S

 

 

其中—udivdi3就是在Compiler-Rt中实现;

2.lldb、libc++:

lldb 项⽬属于全新的基础架构,该架构⽀持现代的多线程程序,并且以

更加⾼效的⽅式处理调试符号,模块化的组件为功能的扩展打下良好的基

础。另外,由于 lldb 更加开放的特性(其licsence并不是GPL。GPL要求

使⽤GPL授权的产品都必须开源), lldb ⼏乎可以集成到任何想要集成

的产品中去,⽽不⽤担⼼法律问题。

lldb 会将调试信息转换为 clang 类型,以便它可以利⽤ clang 编译器的

基础架构。这使得 lldb 可以在表达式中⽀持最新的 c 、 c++ 、 Objecti

ve-C 和 Objective-C++ 语⾔的所有功能和运⾏时,⽽⽆需重新实现这些

功能。此外它还利⽤编译器来处理函数调⽤表达式时的所有ABI接⼝,反汇

编指令和提取指令细节等流程,把 llvm 和 clang 的基础架构运⽤到了极

致。

libc++ 库是 llvm 项⽬对 C++ 标准库的重写,它⽀持包括 C++11 和 C++

1y 在内的最新的 C++ 标准;

 

3.LLD

LLD 是 GNU 链接器的直接替代品,它接受与 GNU 相同的命令⾏参数

和脚本⽂件。 lld 团队在与 FreeBSD 紧密合作的过程中,⾮常重视

解决兼容性问题,因为希望能在未来版本的操作系统中,希望能选择

LLD 作为系统的默认链接器。因此,截⾄2017年2⽉, LLD 已经能够

链接整个 FreeBSD / amd64 基础系统,包括内核。

2. LLD 运⾏速度⾮常快,在多核计算机上链接⼤型程序时, LLD 的运⾏

速度可以达到 GNU gold 链接器的两倍多。

3. LLD ⽀持各种 CPU / ABI ,包

括 x86-64 , x86 , x32 , AArch64 , ARM , MIPS 32/64⼤/⼩

端, PowerPC , PowerPC 64 和 AMDGPU 。其中, x86-64 的⽀持最

为完美,完全可以⽤在⽣产环境, AArch64 和 MIPS 也不错。

x86 只能说应该没问题,但尚未经过完美的测试,还有对 ARM 的⽀

持,正在积极开发中。

4. 不管 lld 被如何编译出来,它始终是⼀个交叉链接器,始终⽀持上述

所有⽬标架构。 lld 甚⾄都不提供编译时的选项来启⽤/禁⽤任何⼀个

⽬标架构,所以,把 lld 集成到你的编译⼯具⾥应该可以很放⼼。

5. 可以将 LLD 嵌⼊到程序中去,以消除程序对外部链接器的依赖性。只

需要构造⽬标⽂件和命令⾏参数,就像调⽤外部链接器⼀样,然后从

代码中调⽤链接器的主函数 lld :: elf :: link 。

6. LLD 很⼩。使⽤ LLVM libObject 库来读取⽬标⽂件,虽然这样⽐较

显得不是很公平,但截⾄2017年2⽉, LLD / ELF 仅包含 21k ⾏ C +

+ 代码,⽽ GNU gold 包含 198k ⾏ C ++ 代码。这数据也⾜以说明 L

LD 真的很⼩。

7. LLD 默认⽀持链接时优化( LTO )。想要使⽤ LTO 的话只需要将 -f

lto 选项传递给 clang ,然后 clang 则不会创建的本机的 native 对

象格式,⽽是 LLVM bitcode 格式。然后 LLD 读取 bitcode ⽬标⽂

件,使⽤ LLVM 编译并产⽣输出⽂件。在开启 LTO 时, LLD 参与编译

的全部过程,对整个程序进⾏优化。

8. 古⽼的 Unix 系统(90年代之前甚⾄之前)的⼀些⾮常古⽼的功能已

被删除。⼀些默认设置也已经进⾏了调整。例如,默认情况下,堆栈

被标记为不可执⾏,来加强安全性。

 

用处:提高编译链接的速度

 

eg:java2c后端的对于bc的处理速度问题:

默认的是gcc的链接器。

 

4.OpenMP

OpenMP 是由 OpenMP Architecture Review Board 牵头提出的,并已被

⼴泛接受,⽤于共享内存并⾏系统的多处理器程序设计的⼀套指导性编译

处理⽅案(Compiler Directive) 。OpenMP⽀持的编程语⾔包括 C 、 C++ 和

Fortran ;⽽⽀持 OpenMp 的编译器包括 Sun Compiler , GNU Compile

r 和 Intel Compiler 等。

 

OpenMp 提供了对并⾏算法的⾼层的抽象描述,程序员通过在源代码中加

⼊专⽤的 pragma 来指明⾃⼰的意图,由此编译器可以⾃动将程序进⾏并

⾏化,并在必要之处加⼊同步互斥以及通信。当选择忽略这些 pragma ,

或者编译器不⽀持 OpenMp 时,程序⼜可退化为通常的程序(⼀般为串⾏),

代码仍然可以正常运作,只是不能利⽤多线程来加速程序执⾏。

 

eg:提高clang++的版本增加编译速度:

 

5.Polly

Polly 的原理是从 LLVM-IR 开始,检测并提取有效的循环内核,然后对于每个内核,导出数学模型,并精确地描述内核中的各个计算和存储器访问,对这些数学模型执⾏各种分析和代码转换。 在派⽣并应⽤所有优化之后,将重新⽣成优化的 LLVM-IR 并将其插⼊ LLVM-IR 模块。

 

二、学习llvm源码目录:

那么这里面有一个宏观的概念,那就是一个编译单元(即一个.c文件),在LLVM IR中代表着一个Module,而一个Module里面含有Global Value,主要包括Global Variable 和 Function,而至于Global Alias接触比较少,而一个Function里面包含着Basic Block,而一个 Basic Block里面包含着指令,如add。那么关系你可以认为是Module -> Function -> Basic Block -> Instructions. 这是一个宏观的认识:

http://llvm.org/doxygen/classllvm_1_1GlobalValue.html

 

1.llvm/include

从llvm库⾥导出来的头⽂件主要包含以下三个⼦⽂件夹:

llvm/include/llvm :所有LLVM特定的头⽂件,以及LLVM不同部分的⼦⽬录:Analysis,CodeGen,Target,Transforms等...

llvm/include/llvm/Support :为LLVM(不⼀定特定于LLVM)提供的通⽤⽀持库。例如,某些C ++ STL实⽤程序和命令⾏选项处理库也在此存储头⽂件。

llvm/include/llvm/Config :配置脚本配置的头⽂件。 它们包装“标准”UNIX和C头⽂件。 源代码可以包

含这些头⽂件,头⽂件⾃动处理配置脚本⽣成的条件

2.llvm/lib

llvm/lib/IR/ :实现核类(如Instruction和BasicBlock)的核LLVM件。

llvm/lib/AsmParser/ :LLVM汇编语⾔解析器库的源代码。

llvm/lib/Bitcode/ :读写bitcode的代码。

llvm/lib/Analysis/ :各种程序分析,如调⽤图,感应变量,⾃然循环识别等。

llvm/lib/Transforms/ :IR到IR程序转换,例如积极死代码消除,稀疏条件常数传播,内联,循环不变代码,死全局消除等等。

llvm/lib/Target/ :描述代码⽣成的⽬标体系结构的⽂件。例如, llvm/lib/Target/X86 保存X86机器描述。

llvm/lib/CodeGen/ :代码⽣成器的主要部分:指令选择器,指令调度和寄存器分配。

llvm/lib/ExecutionEngine/ :于在解释和JIT编译的场景中在运时直接执bitcode的库。

 

3.LLVM/tools:

llvm-ar :归档程序⽣成包含给定LLVM bitcode⽂件的归档⽂件,可选择使⽤索引以便更快地查找。

 

llvm-as :汇编:将⼈类可读的LLVM程序集转换为LLVM bitcode。

 

llvm-dis : 反汇编:将LLVM bitcode转换为⼈类可读的LLVM程序集。

 

llvm-link :链接器:将多个LLVM模块链接到⼀个程序中。

 

lli :LLVM解释器,它可以直接执⾏LLVMbitcode(虽然⾮常慢...)。对于⽀持它的架构(⽬前是x86,Sparc和PowerPC),默认情况下,lli将作为Just-In-Time编译器(如果编译了功能),并且将⽐解释器更快地执⾏代码。

 

llc :llc是LLVM后端编译器,它将LLVM bitcode转换为本机机器代码⽂件。当然也可以生成cpp(llvm3.8以下):

 

 

opt :opt读取LLVM bitcode, 负责将bitcode进⾏打乱、重组等等(在命令⾏中指定),并输出结果bitcode。 opt -help 命令获取更多细节。opt还可以对输⼊LLVM bitcode⽂件运⾏特定分析并打印结果,可以⽤于调试分析,可是从中找到很多运⾏的细节。这个⽂件夹⾥包含了,⽤于处理LLVM源代码的实⽤程序; 有些也是是构建过程的⼀部分,因为它们是部分基础结构的代码⽣成器。

 

问题:是不是通过重写lli就可以写出对于bc的解释器来?

调用的是JIT的引擎代码,比较脱离主题!

简单看一下lli的源码:

初始化:

https://github.com/llvm-mirror/llvm/blob/master/tools/lli/lli.cpp

 

 

三、定制编译系统

cmake配置详解

编译llvm源代码之前必须要使CMake具来进配置。跟常规的 config

ure 配置脚本不同的是,CMake会成各种各样的配置件,包括各种 *.

inc 件和 llvm/include/Config/config.h 。

传递给 cmake 命令的参数的格式为 -D<variable name>=<value> ,

会有以下种参数和选项。

参数

CMAKE_C_COMPILER

告诉cmake使哪个C编译器。 默认情况下,这将是 /usr/bin/cc 。

CMAKE_CXX_COMPILER

告诉cmake使哪个C ++编译器。 默认情况下,这将是 / usr / bin / c ++ 。

CMAKE_BUILD_TYPE

告诉cmake您尝试为其件的构建类型。 有效选项包括Debug,Release,

RelWithDebInfo和MinSizeRel。 默认为Debug。

CMAKE_INSTALL_PREFIX

指定运构建件的安装操作时的安装录。

LLVM_TARGETS_TO_BUILD

以分号分隔的列表,于控制将构建哪些标并链接到llc。 这相当于configure脚本中

的--enable-targets选项。 默认列表定义为LLVM_ALL_TARGETS , 默认值包括:

AArch64,AMDGPU,ARM,BPF,Hexagon,Mips,MSP430,NVPTX,

PowerPC,Sparc,SystemZ,X86,XCore。LLVM_ENABLE_DOXYGEN

从源代码构建基于doxygen的档。默认情况下禁它,因为它很慢并且会产⽣⼤量输

出。

LLVM_ENABLE_SPHINX

从源代码构建基于sphinx的档。 默认情况下禁此选项,因为它很慢并产⽣⼤量输

出。 建议使Sphinx 1.5或更版本。

LLVM_BUILD_LLVM_DYLIB

成libLLVM.so,这个库包含组默认的LLVM组件,可以使

LLVM_DYLIB_COMPONENTS覆盖这些组件。 默认值包含部分LLVM的功能,并在

tools/llvm-shlib/CMakelists.txt义。

LLVM_OPTIMIZED_TABLEGEN

编译个在LLVM编译期间使的release版的 tablegen 。这可以⼤⼤加快调试版本的

速度。

 

猜你喜欢

转载自blog.csdn.net/feibabeibei_beibei/article/details/88073678
今日推荐