├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── implement_llvm.iml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── CMakeLists.txt ├── README.md ├── doc ├── 2004-01-30-CGO-LLVM.pdf ├── 2008-10-04-ACAT-LLVM-Intro.pdf ├── Intro to LLVM.md ├── Kaleidoscope Tutorial.md ├── LLVM Coding Standards.md ├── LLVM Language Reference Manual.md ├── LLVM Programmer’s Manual.md ├── LLVM_FrozenGene.pdf ├── SSA.md ├── The LLVM Target-Independent Code Generator.md ├── Writing an LLVM Pass.md └── image │ ├── Intro to LLVM │ ├── InstallTime.png │ ├── LLVMCompiler1.png │ ├── LTO.png │ ├── PassLinkage.png │ ├── RetargetableCompiler.png │ ├── SimpleCompiler.png │ └── X86Target.png │ └── SSA │ ├── SSA_example1.1.png │ ├── SSA_example1.2.png │ └── SSA_example1.3.png ├── lib ├── CMakeLists.txt ├── Kaleidoscope_tutorial │ ├── CMakeLists.txt │ ├── include │ │ └── KaleidoscopeJIT.h │ └── src │ │ ├── BuildingAJIT │ │ ├── CMakeLists.txt │ │ └── Chapter01 │ │ │ ├── CMakeLists.txt │ │ │ ├── KaleidoscopeJIT.h │ │ │ └── toy.cpp │ │ ├── Chapter02 │ │ ├── CMakeLists.txt │ │ └── toy.cpp │ │ ├── Chapter03 │ │ ├── CMakeLists.txt │ │ └── toy.cpp │ │ ├── Chapter04 │ │ ├── CMakeLists.txt │ │ └── toy.cpp │ │ ├── Chapter05 │ │ ├── CMakeLists.txt │ │ └── toy.cpp │ │ ├── Chapter06 │ │ ├── CMakeLists.txt │ │ └── toy.cpp │ │ └── Chapter07 │ │ ├── CMakeLists.txt │ │ └── toy.cpp ├── src_clang │ └── CMakeLists.txt └── src_llvm │ └── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | .idea/ 24 | .vscode/ 25 | build/ 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | # *.txt 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | cmake-build-debug/ -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/implement_llvm.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(implement_llvm) 3 | set(CMAKE_CXX_STANDARD 11) 4 | 5 | set(LLVM_DIR /media/cyoung/000E88CC0009670E/llvm/build_install/lib/cmake/llvm) 6 | #set(LLVM_DIR /home/cyoung/llvm/build_install/lib/cmake/llvm) 7 | 8 | #添加cmake指令 9 | set (CMAKE_MODULE_PATH ${LLVM_DIR}) 10 | include(${LLVM_DIR}/AddLLVM.cmake) 11 | 12 | 13 | 14 | 15 | find_package(LLVM REQUIRED CONFIG) 16 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 17 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 18 | include_directories(${LLVM_INCLUDE_DIRS}) 19 | add_definitions(${LLVM_DEFINITIONS}) 20 | 21 | 22 | 23 | add_subdirectory(lib) 24 | 25 | 26 | # Find the libraries that correspond to the LLVM components 27 | # that we wish to use 28 | llvm_map_components_to_libnames(llvm_libs support core irreader) 29 | 30 | # Link against LLVM libraries 31 | #target_link_libraries(implement_llvm ${llvm_libs}) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # implement_llvm 2 | 3 | 环境:ubuntu16.04 , Jetbrain Clion IDE 4 | 5 | 网上的入门教程很多,[@snsn1984](https://blog.csdn.net/snsn1984/article/details/81283070),但是没有一个手把手上手实践的教程,最近几天倒腾llvm,创建了第一个实践项目,下面就将把这个过程梳理下来,供小白参考 6 | 7 | ## 1.下载源码,编译 8 | 9 | [llvm官方文档](http://llvm.org/docs/GettingStarted.html) [clang官方文档](http://clang.llvm.org/get_started.html),比较详细,但是太冗长,下边给出简单方法: 10 | 11 | ### git clone源码: 12 | 13 | ```shell 14 | cd youLLVM_Path/ 15 | #llvm源码 16 | git clone https://git.llvm.org/git/llvm.git/ 17 | cd llvm/tools 18 | #clang源码,放在llvm/tools下 19 | git clone https://git.llvm.org/git/clang.git/ 20 | cd ../projects 21 | #compiler-rt源码,放在llvm/projects下 22 | git clone https://git.llvm.org/git/compiler-rt.git/ 23 | git clone https://git.llvm.org/git/openmp.git/ 24 | ``` 25 | 26 | ### 编译源码 27 | 28 | ```shell 29 | cd .. 30 | #来到llvm root目录下 31 | mkdir build 32 | cd build 33 | cmake -G "Unix Makefiles" .. 34 | make -j4 35 | ``` 36 | 37 | 现在源码llvm已经来到8.0.0版本,以上编译默认debug模式,编译完成需要50G存储空间,所以编译之前需要保证磁盘空间充足,加上后面安装需要的35G,所以需要为llvm保留100G左右的磁盘空间 38 | 39 | ## 2.安装 40 | 41 | 由于之前安装tvm时的需要,系统本身已经安装了llvm6.0,[安装方式](https://apt.llvm.org/): 42 | 43 | ```shell 44 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - 45 | # Fingerprint: 6084 F3CF 814B 57C1 CF12 EFD5 15CF 4D18 AF4F 7421 46 | sudo apt-get install clang-6.0 lldb-6.0 lld-6.0 47 | ``` 48 | 49 | 如果想将以上编译结果直接安装到系统中,很简单,但是不建议,因为消耗的系统空间太大 50 | 51 | ```shell 52 | #不建议!!! 53 | # build 目录下: 54 | sudo make install 55 | ``` 56 | 57 | 于是乎,想将源码安装在指定目录,为这一步,一个小白倒腾了整整一天,最后还是在[官网](http://llvm.org/docs/CMake.html)找到了答案: 58 | 59 | 现在假设安装在llvm root目录下的build_install下: 60 | 61 | ```shell 62 | cd llvmRootPath/ 63 | #创建安装目录 64 | mkdir build_install 65 | cd build 66 | #安装到指定目录 67 | cmake -DCMAKE_INSTALL_PREFIX=/llvmRootPath/build_install -P cmake_install.cmake 68 | ``` 69 | 70 | 此时已经将llvm安装到build_install下 71 | 72 | ## 3.创建第一个llvm项目 73 | 74 | 打开clion,新建项目,项目名: implement_llvm 75 | 76 | 如何在CMakeList.txt中引用项目,答案还是在[官网](http://llvm.org/docs/CMake.html#embedding-llvm-in-your-project) 77 | 78 | ```cmake 79 | cmake_minimum_required(VERSION 3.4.3) 80 | project(SimpleProject) 81 | 82 | find_package(LLVM REQUIRED CONFIG) 83 | 84 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 85 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 86 | 87 | # Set your project compile flags. 88 | # E.g. if using the C++ header files 89 | # you will need to enable C++11 support 90 | # for your compiler. 91 | 92 | include_directories(${LLVM_INCLUDE_DIRS}) 93 | add_definitions(${LLVM_DEFINITIONS}) 94 | 95 | # Now build our tools 96 | add_executable(simple-tool tool.cpp) 97 | 98 | # Find the libraries that correspond to the LLVM components 99 | # that we wish to use 100 | llvm_map_components_to_libnames(llvm_libs support core irreader) 101 | 102 | # Link against LLVM libraries 103 | target_link_libraries(simple-tool ${llvm_libs}) 104 | 105 | ``` 106 | 107 | 但是,重点来了,由于之前系统安装了llvm6.0,cmake会优先在系统中找到llvm6.0,如何调用以上源码安装库,一个小白又倒腾了半天 108 | 109 | 官网一句话:The `find_package(...)` directive when used in CONFIG mode (as in the above example) will look for the `LLVMConfig.cmake` file in various locations (see cmake manual for details),It creates a `LLVM_DIR` cache entry to save the directory where `LLVMConfig.cmake` is found 110 | 111 | 大意是说:find_package采用config模式,会根据LLVM_DIR缓存条目(cache entry)来寻找`LLVMConfig.cmake` ,这个缓存条目是个什么玩意儿???懵逼 112 | 113 | 将环境变量中加入`export LLVM_DIR=/llvmRootPath/build_install`,等等一系列措施,最后找到了方法 114 | 115 | 在CMakeList.txt里加上一句话 116 | 117 | ```cmake 118 | cmake_minimum_required(VERSION 3.4.3) 119 | project(SimpleProject) 120 | 121 | #加上一句,这是config模式来寻找LLVMConfig.cmake的路径,添加即可 122 | set(LLVM_DIR /llvmRootPath/build_install/lib/cmake/llvm) 123 | 124 | find_package(LLVM REQUIRED CONFIG) 125 | #-----后面省略----- 126 | ``` 127 | 128 | 于是乎,cmake就可以快乐的找到llvm8.0.0了,第一个项目创建完成 129 | 130 | 踩坑到此为止,后面利用此项目来学习llvm.欢迎交流. 131 | 132 | ## 4.[llvm tutotial](https://llvm.org/docs/tutorial/index.html#kaleidoscope-implementing-a-language-with-llvm) 133 | 134 | 利用google翻译的[中文文档](https://github.com/Cyoung7/implement_llvm/blob/master/doc/Kaleidoscope%20Tutorial.md)(待校对) 135 | 136 | ## 5.[LLVM Programmer’s Manual](https://llvm.org/docs/ProgrammersManual.html) 137 | 138 | llvm编程手册,利用google翻译的[中文文档](https://github.com/Cyoung7/implement_llvm/blob/master/doc/LLVM%20Programmer%E2%80%99s%20Manual.md)(待校对) 139 | 140 | ## 6.[LLVM Language Reference Manual](https://llvm.org/docs/LangRef.html) 141 | 142 | llvm IR手册,利用google翻译的[中文文档](https://github.com/Cyoung7/implement_llvm/blob/master/doc/LLVM%20Language%20Reference%20Manual.md)(待校对) 143 | 144 | -------------------------------------------------------------------------------- /doc/2004-01-30-CGO-LLVM.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/2004-01-30-CGO-LLVM.pdf -------------------------------------------------------------------------------- /doc/2008-10-04-ACAT-LLVM-Intro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/2008-10-04-ACAT-LLVM-Intro.pdf -------------------------------------------------------------------------------- /doc/Intro to LLVM.md: -------------------------------------------------------------------------------- 1 | # llvm简介 2 | 3 | [原文链接](http://www.aosabook.org/en/llvm.html) 4 | 5 | [TOC] 6 | 7 | 本章讨论了一些在LLVM成型的设计决策,这是一个包含和开发一组紧密结合的低级工具链组件(例如,汇编器,编译器,调试器等)的伞状项目,它被设计成需要在类Unix系统上兼容已存在的工具。 “LLVM”这个名字曾经是一个缩写词,但现在只是伞形项目的一个品牌。 虽然LLVM提供了一些独特的功能,并且以其一些出色的工具而闻名(例如,Clang编译器 ,C / C ++ / Objective-C编译器,它提供了许多优于GCC编译器的优点),但是LLVM与其他编译器不同的主要是它的内部架构。 8 | 9 | 从2000年12月开始,LLVM被设计为一组具有良好定义接口的可重用库。 当时,开源编程语言实现被设计为通常具有单独可执行文件的专用工具。 例如,从静态编译器(例如,GCC)重用解析器进行静态分析或重构是非常困难的。 虽然脚本语言通常提供了将运行时和解释器嵌入到更大的应用程序中的方法,但是这个运行时是一个单个整体代码块,他可能被包含在内或排除在外。 没有办法重复使用片段,并且很少在语言实现项目中共享。 10 | 11 | 除了编译器本身的组成之外,流行语言实现的社区通常是强烈的两极化:一个实现通常提供传统的静态编译器,如GCC,Free Pascal和FreeBASIC, 或者它提供了一个解释器形式的运行时编译器或即时(JIT)编译器。 看到支持两者的语言实现非常罕见,即使他们这样做,通常也很少实现代码共享。 12 | 13 | 在过去的十年中,LLVM已经彻底改变了这种状况。 LLVM现在被用作实现各种静态和运行时编译语言的通用基础结构(例如,由GCC,Java,.NET,Python,Ruby,Scheme,Haskell,D支持的语言系列,以及无数的较小的语言已知语言)。 它还取代了各种各样的专用编译器,例如Apple的OpenGL堆栈中的运行时专用引擎和Adobe After Effects产品中的图像处理库。 最后,LLVM还被用于创建各种各样的新产品,其中最着名的可能是OpenCL GPU编程语言和运行时。 14 | 15 | ## 1.经典编译器设计 16 | 17 | 传统静态编译器(如大多数C编译器)最流行的设计是三阶段设计,其主要组件是前端,优化器和后端。 前端解析源代码,检查它是否有错误,并构建一个特定于语言的抽象语法树(AST)来表示输入代码。 AST可选地转换为新的表示以进行优化,优化器和后端在代码上运行。 18 | 19 | ![SimpleCompiler](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/SimpleCompiler.png) 20 | 21 | ​ 三阶段编译器的三个主要组件 22 | 23 | 优化器负责进行各种各样的转换以尝试改进代码的运行时间,例如消除冗余计算,并且通常或多或少地独立于语言和目标。 然后,后端(也称为代码生成器)将代码映射到目标指令集。 除了生成正确的代码外,它还负责生成充分利用硬件支持的体系结构的优秀代码。 编译器后端的公共部分包括指令选择,寄存器分配和指令调度。 24 | 25 | 该模型同样适用于解释器和JIT编译器。 Java虚拟机(JVM)也是此模型的一个实现,它使用Java字节码作为前端和优化器之间的接口。 26 | 27 | ### 1.1 这种设计的含义 28 | 29 | 当编译器决定支持多种源语言或目标体系结构时,这种经典设计的最重要的优势就来了。 如果编译器在其优化器中使用公共代码表示,则可以为任何可以编译到它的语言编写前端,并且可以为可以从中编译的任何目标编写后端,如下图所示: 30 | 31 | ![RetargetableCompiler](/https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/RetargetableCompiler.png) 32 | 33 | 使用此设计,移植编译器以支持新的源语言(例如,Algol或BASIC)只需要实现新的前端,但现有的优化器和后端可以重用。 如果这些部分没有分开,那么实现新的源语言需要从头开始,因此支持`N`目标和`M`源语言需要N * M个编译器。 34 | 35 | 三阶段设计的另一个优点(直接来自可重定向性)是编译器服务于更广泛的程序员集合,而不是仅支持一种源语言和一种目标。 对于一个开源项目,这意味着可以从中抽取更大一群潜在的社区贡献者,这自然会导致编译器的更多增强和改进。 这就是为什么服务于许多社区的开源编译器(如GCC)倾向于生成比FreePASCAL等较窄的编译器更好的优化机器代码。 专有编译器的情况并非如此,其质量与项目的预算直接相关。 例如,英特尔ICC编译器因其生成的代码质量而广为人知,即使它服务于狭隘的受众。 36 | 37 | 三阶段设计的最后一个主要优势是实现前端所需的技能与优化器和后端所需的技能不同。 将这些分开使得“前端人员”更容易增强和维护他们的编译器部分。 虽然这是一个社会问题,而不是技术问题,但它在实践中很重要,特别是对于开源项目就是为了减少程序员的障碍。 38 | 39 | ### 1.2现有语言实现 40 | 41 | 虽然三阶段设计的好处在编译器教科书中引人注目并且有充分的文档记录,但实际上它几乎从未完全实现。 查看开源语言实现(当LLVM启动时),您会发现Perl,Python,Ruby和Java的实现不共享任何代码。 此外,像格拉斯哥Haskell编译器(GHC)和FreeBASIC这样的项目可以重新定位到多个不同的CPU,但是它们的实现非常特定于它们支持的一种源语言。 还部署了各种各样的专用编译器技术来实现JIT编译器,用于图像处理,正则表达式,图形卡驱动程序以及需要CPU密集型工作的其他子域. 42 | 43 | 还有,这个模型有三个主要的成功案例,第一个是Java和.NET虚拟机。 这些系统提供JIT编译器,运行时支持和定义良好的字节码格式。 这意味着任何可以编译为字节码格式的语言(数十种语言)可以再次利用优化器和JIT以及运行时。 需要权衡的是在运行时选择方面提供的实现灵活性很小:它们都强制采用JIT编译,垃圾回收以及使用非常特定的对象模型。 当遇到编译与该模型不匹配的语言(例如C)(例如,使用LLJVM项目)时,这会导致性能欠佳。 44 | 45 | 第二个成功案例可能是最不幸的,也是最常用的重用编译器技术的方法:将输入源转换为C代码(或其他语言)并通过现有的C编译器发送。 这允许重用优化器和代码生成器,提供良好的灵活性,控制运行时,并且前端实现者很容易理解,实现和维护。 不幸的是,这样做会妨碍异常处理的有效实现,提供糟糕的调试体验,减慢编译速度,并且对于需要保证尾调用(tail call)的语言(或C不支持的其他功能)可能会出现问题。 46 | 47 | 该模型的最终成功实施是GCC 。 GCC支持许多前端和后端,并且拥有活跃且广泛的贡献者社区。 GCC作为一个C编译器有着悠久的历史,它支持多个目标,并且支持其他几种语言。 随着岁月的流逝,GCC社区正在慢慢发展清洁设计。 从GCC 4.4开始,它有一个新的优化器表示(称为“GIMPLE元组”),它比前面更接近于与前端表示分离。 此外,它的Fortran和Ada前端使用干净的AST。 48 | 49 | 虽然非常成功,但这三种方法对它们的用途有很大限制,因为它们被设计为单独的应用程序。 比如,将GCC嵌入到其他应用程序中,将GCC用作运行时/ JIT编译器,或者在不引入编译器大部分的情况下提取和重用GCC片段是不现实的。 想要使用GCC的C ++前端进行文档生成,代码索引,重构和静态分析工具的人不得不将GCC用作以XML形式发送信息的独立应用程序,或编写插件以将外部代码注入GCC流程。 50 | 51 | GCC片段不能作为库重用的原因有很多,包括全局变量的泛滥使用,弱不变的常量,数据结构的设计不良,庞大的代码库,以及使用宏阻止代码库被编译以支持更多的前端/目标对。 然而,最难解决的问题是其早期设计和时代所固有的架构问题。 具体来说,GCC会遇到分层问题和抽象漏洞:后端遍历前端AST以生成调试信息,前端生成后端数据结构,整个编译器依赖于命令行接口设置的全局数据结构。 52 | 53 | ### 1.3 LLVM的代码中间表示 LLVM IR 54 | 55 | 有了历史背景和错误经验,让我们深入研究LLVM:其设计中最重要的一项便是LLVM中间表示(IR),它是用于表示编译器中的代码格式。 LLVM IR旨在托管您在编译器的优化器部分中找到的中级分析和转换。它的设计考虑了许多具体目标,包括支持轻量级运行时优化,跨函数/过程间优化,整个程序分析和积极的重组转换等。但最重要的是,它本身被定义为具有明确语义的第一类语言。 为了具体的展现,这是一个简单的`.ll`文件示例: 56 | 57 | ``` 58 | define i32 @add1(i32 %a, i32 %b) { 59 | entry: 60 | %tmp1 = add i32 %a, %b 61 | ret i32 %tmp1 62 | } 63 | 64 | define i32 @add2(i32 %a, i32 %b) { 65 | entry: 66 | %tmp1 = icmp eq i32 %a, 0 67 | br i1 %tmp1, label %done, label %recurse 68 | 69 | recurse: 70 | %tmp2 = sub i32 %a, 1 71 | %tmp3 = add i32 %b, 1 72 | %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) 73 | ret i32 %tmp4 74 | 75 | done: 76 | ret i32 %b 77 | } 78 | ``` 79 | 80 | 此LLVM IR对应于此C代码,它提供了两种不同的方法来添加整数: 81 | 82 | ```c 83 | unsigned add1(unsigned a, unsigned b) { 84 | return a+b; 85 | } 86 | 87 | // Perhaps not the most efficient way to add two numbers. 88 | unsigned add2(unsigned a, unsigned b) { 89 | if (a == 0) return b; 90 | return add2(a-1, b+1); 91 | } 92 | ``` 93 | 94 | 从这个例子中可以看出,LLVM IR是一种类似RISC的低级虚拟指令集。 与真正的RISC指令集一样,它支持简单指令的线性序列,如加,减,比较和分支。 这些指令采用三种地址形式,这意味着它们需要一些输入并在不同的寄存器中产生结果。 LLVM IR支持标签,通常看起来像一种奇怪的汇编语言形式. 95 | 96 | 与大多数RISC指令集不同,LLVM是强类型的简单类型系统(例如, `i32`是`32位整数`, `i32**`是指向`32位整数指针`),并且机器的一些细节被抽象掉。 例如,调用约定通过`call`和`ret`指令以及显式参数进行抽象。 与机器代码的另一个显着区别是LLVM IR不使用一组固定的命名寄存器,它使用一组以`%`字符命名的无限临时值。 97 | 98 | 除了作为一种语言实现之外,LLVM IR实际上以三种同构形式的定义:上面的文本格式,还有由优化本身检查和修改的内存中的数据结构,以及高效且密集的磁盘二进制“bitcode”格式。 LLVM项目还提供了将磁盘格式从文本转换为二进制的工具: `llvm-as`将文本`.ll`文件组装成包含bitcode goop的`.bc`文件, `llvm-dis`将`.bc`文件转换为`.ll`文件。 99 | 100 | 编译器的中间表示很有意思,因为它可以是编译器优化器的“完美世界”:与编译器的前端和后端不同,优化器不受特定源语言或特定目标机器的约束。  另一方面,它必须有很好地服务:它必须被设计成易于前端使用,生成针对目标硬件充分优化的代码。 101 | 102 | #### 1.3.1 编写LLVM IR优化 103 | 104 | 为了对优化如何工作提供一些直观感受,下面通过一些例子。 有许多不同类型的编译器优化,因此很难提供能够解决任意问题的方法。 也就是说,大多数优化都遵循一个简单的三部分结构: 105 | 106 | - 寻找要转变的模式。 107 | - 验证匹配实例的转换是否安全/正确。 108 | - 进行转换,更新代码。 109 | 110 | 最简单的优化是对算术标识的模式匹配,例如:对于任何整数`X` , `X-X`为0, `X-0`为`X` , `(X*2)-X`为`X` 第一个问题是LLVM IR中的这些问题。 一些例子是: 111 | 112 | ``` 113 | ⋮ ⋮ ⋮ 114 | %example1 = sub i32 %a, %a 115 | ⋮ ⋮ ⋮ 116 | %example2 = sub i32 %b, 0 117 | ⋮ ⋮ ⋮ 118 | %tmp = mul i32 %c, 2 119 | %example3 = sub i32 %tmp, %c 120 | ⋮ ⋮ ⋮ 121 | ``` 122 | 123 | 对于这些“洞察”转换,LLVM提供了一个指令简化接口,通过各种其他更高级别的转换用作实用程序。 这些特定的转换在`SimplifySubInst`函数中,如下所示: 124 | 125 | ```c 126 | // X - 0 -> X 127 | if (match(Op1, m_Zero())) 128 | return Op0; 129 | 130 | // X - X -> 0 131 | if (Op0 == Op1) 132 | return Constant::getNullValue(Op0->getType()); 133 | 134 | // (X*2) - X -> X 135 | if (match(Op0, m_Mul(m_Specific(Op1), m_ConstantInt<2>()))) 136 | return Op1; 137 | 138 | … 139 | 140 | return 0; // Nothing matched, return null to indicate no transformation. 141 | ``` 142 | 143 | 在此代码中,`Op0`和`Op1`绑定到整数减法指令的左右操作数(重要的是,这些标识不一定适用于IEEE浮点数!)。 LLVM是用C ++实现的,它的模式匹配功能并不为人所熟知(与Objective Caml等功能语言相比),但它提供了一个非常通用的模板系统,允许我们实现类似的东西。 `match`函数和`m_`函数允许我们对LLVM IR代码执行声明性模式匹配操作。 例如,如果乘法的左侧与`Op1`相同,则`m_Specific`谓词仅匹配。 144 | 145 | 总之,这三种情况都是模式匹配的,如果可以,函数返回替换,如果不可以替换,则返回空指针。 此函数的调用者( `SimplifyInstruction` )是一个调度程序,它对指令操作码进行切换,并调度到每操作码辅助函数。 它是从各种优化中调用的。 一个简单的驱动程序如下所示: 146 | 147 | ```c++ 148 | for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) 149 | if (Value *V = SimplifyInstruction(I)) 150 | I->replaceAllUsesWith(V); 151 | ``` 152 | 153 | 这段代码简单地循环遍历块中的每条指令,检查它们是否有任何简化。 如果可以(因为`SimplifyInstruction`返回非null),它会使用`replaceAllUsesWith`方法使用更简单的形式更新代码中的任何内容。 154 | 155 | ### 1.4 LLVM实现三阶段设计 156 | 157 | 在基于LLVM的编译器中,前端负责解析,验证和诊断输入代码中的错误,然后将解析的代码转换为LLVM IR(通常但不总是通过构建AST然后将AST转换为LLVM IR)。 该IR可选地通过一系列改进代码的分析和优化过程提供,然后被发送到代码生成器以生成本机机器代码, 如图所示。 这是三阶段设计的一个非常简单的实现,但是这个简单的描述掩盖了LLVM架构从LLVM IR派生的一些功能和灵活性。 158 | 159 | ![LLVMCompiler1](/https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/LLVMCompiler1.png) 160 | 161 | 162 | 163 | #### 1.4.1 LLVM IR是完整的代码表示 164 | 165 | 特别是,LLVM IR既是明确指定的,也是优化器的*唯一*接口。 这个属性意味着为LLVM编写前端所需要知道的就是LLVM IR是什么,它是如何工作的,以及它所期望哪些不需要改变。 由于LLVM IR具有第一类的文本形式,因此构建时将LLVM IR作为文本输出的前端也是合理的,然后使用Unix管道通过您选择的优化器序列和代码生成器来发送它。 166 | 167 | 这可能是令人惊讶的,但这实际上是LLVM的一个非常新颖的特性,也是其在各种不同应用中取得成功的主要原因之一。 即使是广泛成功且相对精心设计的GCC编译器也没有这个属性:它的GIMPLE中级表示不是一个独立的表示。 举个简单的例子,当GCC代码生成器发出DWARF调试信息时,它会返回并遍历源级"树"形式。GIMPLE本身对代码中的操作使用“元组”表示,但(至少从GCC 4.5开始)仍将操作数表示为返回源级树形式的引用。 168 | 169 | 这意味着前端作者需要知道并生成GCC的树数据结构以及GIMPLE来编写GCC前端。 GCC后端有类似的问题,因此他们还需要了解RTL后端的工作原理。 最后,GCC没有办法转储“代表我代码的所有内容”,或者以文本形式读取和编写GIMPLE(以及构成代码表示的相关数据结构)的方法。 结果是,用GCC进行实验相对困难,因此它的前端相对较少。 170 | 171 | #### 1.4.2 LLVM是一个库集合 172 | 173 | 在LLVM IR的设计之后,LLVM的下一个最重要的方面是把它设计为一组库,而不是像GCC这样的单独命令行编译器或像JVM或.NET虚拟机那样的不透明虚拟机。 LLVM是一种基础结构,是一组有用的编译器技术,可以解决特定问题(例如构建C编译器或特殊效果管道中的优化器)。 虽然它LLVM最强大的功能之一,但也是人们最不了解的设计点之一。 174 | 175 | 让我们看看优化器设计的一个例子:它读取LLVM IR,稍微处理它,然后发出LLVM IR,希望能更快地执行。 在LLVM中(与许多其他编译器一样),优化器被组织为不同优化传递的管道,每个优化在输入上传递运行并且可以执行某些优化操作。 传递的常见示例是内联器(将函数体替换为调用站点),表达式重新关联,循环不变代码运动等。根据优化级别,运行不同的传递:例如在`-O0`(无优化) Clang编译器不运行任何传递,在`-O3`它在其优化器中运行总共67次传递(从LLVM 2.8开始)。 176 | 177 | 每个LLVM传递都被编写为C ++类,它从`Pass`类派生(间接)。 大多数传递都是用单个`.cpp`文件编写的,而`Pass`类的子类是在匿名命名空间中定义的(这使得它对定义文件完全私有)。 为了使传递有用,文件外部的代码必须能够获取它,因此从文件中导出单个函数(创建传递)。 这是一个略微简化的例子,用于使事情具体化。 178 | 179 | ```c++ 180 | namespace { 181 | class Hello : public FunctionPass { 182 | public: 183 | // Print out the names of functions in the LLVM IR being optimized. 184 | virtual bool runOnFunction(Function &F) { 185 | cerr << "Hello: " << F.getName() << "\n"; 186 | return false; 187 | } 188 | }; 189 | } 190 | 191 | FunctionPass *createHelloPass() { return new Hello(); } 192 | ``` 193 | 194 | 如上所述,LLVM优化器提供了许多不同的传递,每个传递都以类似的方式编写。 这些传递被编译成一个或多个`.o`文件,然后将这些文件构建到一系列静态文件(Unix系统上的`.a`文件)中。 这些库提供了各种各样的分析和转换功能,并且通道尽可能松散地耦合:如果它们依赖于其他分析来完成它们的工作,它们应该独立存在,或者在其他通道中明确声明它们的依赖关系。 当给出一系列要运行的传递时,LLVM PassManager使用显式依赖关系信息来满足这些依赖关系并优化传递的执行。 195 | 196 | 库和抽象功能很棒,但它们实际上并不能解决问题。 当有人想要构建一个可以从编译器技术中受益的新工具时,有趣的是,可能是用于图像处理语言的JIT编译器。 此JIT编译器的实现者在设计时考虑了一组约束:例如,图像处理语言可能对编译时延迟高度敏感,并且具有一些惯用语言属性,这些属性出于性能原因进行优化非常重要。 197 | 198 | LLVM优化器的基于库的设计允许我们的实现者选择执行传递的顺序,以及哪些对图像处理域有意义:如果所有内容都被定义为单个大函数,则它不会感觉浪费时间内联。 如果指针很少,别名分析和内存优化就不值得烦恼了。 然而,尽管我们尽最大努力,但LLVM并没有神奇地解决所有优化问题! 由于传递子系统是模块化的,并且PassManager本身对传递的内部不了解,因此实现者可以自由地实现他们自己的语言特定传递,以弥补LLVM优化器中的缺陷或明确的语言特定优化机会。 下图显示了我们假设的XYZ图像处理系统的一个简单示例: 199 | 200 | ![PassLinkage](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/PassLinkage.png) 201 | 202 | ​ 使用LLVM的假设XYZ系统 203 | 204 | 一旦选择了一组优化(并且对代码生成器做出了类似的决定),图像处理编译器就被构建到可执行或动态库中。 由于对LLVM优化传递的唯一引用是每个`.o`文件中定义的简单`create`函数,并且由于优化器位于`.a`静态文件中,因此只有*实际使用*的优化传递链接到最终应用程序,而不是整个LLVM优化器。 在上面的示例中,由于存在对PassA和PassB的引用,它们将被链接。由于PassB使用PassD进行一些分析,因此PassD被链接。但是,因为PassC(以及许多其他优化)未被使用,它的代码没有链接到图像处理应用程序。 205 | 206 | 这就是基于库设计的LLVM的强大功能。 这种简单的设计方法允许LLVM提供大量功能,其中一些功能可能仅对特定受众有用,而不会损害只想做简单事情的库的客户端。 相比之下,传统的编译器优化器是作为紧密互连的大量代码构建的,这对于子集,推理和加速来说要困难得多。 使用LLVM,您可以了解各个优化器,而无需了解整个系统如何组合在一起。 207 | 208 | 这种基于库的设计也是为什么很多人误解LLVM的原因:LLVM库有很多功能,但它们实际上*并*没有自己*做*任何事情。 由库的客户端(例如,Clang C编译器)的设计者来决定如何最好地使用这些部件。 这种仔细的分层,分解和关注子集的能力也是LLVM优化器可广泛用于不同环境,不同应用的原因。 此外,仅仅因为LLVM提供JIT编译功能,并不意味着每个客户端都使用它。 209 | 210 | ### 1.5 可重定向LLVM代码生成器的设计 211 | 212 | LLVM代码生成器负责将LLVM IR转换为目标特定的机器代码。 一方面,代码生成器的任务是为任何给定目标生成最佳机器代码。 理想情况下,每个代码生成器应该是针对特定目标硬件的完全独立实现,但另一方面,每个目标的代码生成器需要解决非常类似的问题。 例如,每个目标需要为寄存器分配值,尽管每个目标具有不同的寄存器文件,但应尽可能共享所使用的算法。 213 | 214 | 与优化器中的方法类似,LLVM的代码生成器将代码生成问题分解为单独的传递 - 指令选择,寄存器分配,调度,代码布局优化和汇编发射 - 并提供许多默认运行的内置传递。 然后,目标硬件作者有机会在默认传递中进行选择,覆盖默认值并根据需要实现完全自定义的特定于目标的传递。 例如,x86后端使用寄存器压力降低调度程序,因为它只有很少的寄存器,但PowerPC后端使用延迟优化调度程序,因为它有很多寄存器。 x86后端使用自定义传递来处理x87浮点堆栈,ARM后端使用自定义传递将常量池岛放置在需要的函数内。 这种灵活性允许目标作者生成高效的代码,而无需从头开始为其目标硬件编写整个代码生成器。 215 | 216 | #### 1.5.1 LLVM目标描述文件 217 | 218 | “混合和匹配”的方法允许目标硬件作者选择对其体系结构有意义的内容,并允许跨不同目标重用大量代码。 这带来了另一个挑战:每个共享组件都需要能够以通用方式推断目标特定属性。 例如,共享寄存器分配器需要知道每个目标硬件的寄存器文件以及指令与其寄存器操作数之间存在的约束。 LLVM的解决方案是为每个目标提供由tblgen工具处理的声明性特定语言(一组`.td`文件)的目标描述。 x86目标的(简化)构建过程[如图11.5](https://translate.googleusercontent.com/translate_c?act=url&depth=1&hl=zh-CN&ie=UTF8&prev=_t&rurl=translate.google.com.hk&sl=en&sp=nmt4&tl=zh-CN&u=http://www.aosabook.org/en/llvm.html&xid=17259,1500000,15700023,15700124,15700149,15700186,15700191,15700201&usg=ALkJrhinVvXb6fPVCPRe2wOKN2jF14NpYQ#fig.llvm.x86)所示。 219 | 220 | ![X86Target](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/X86Target.png) 221 | 222 | `.td`文件支持的不同子系统允许目标作者构建其目标的不同部分。 例如,x86后端定义了一个寄存器类,它包含所有名为`GR32`的32位寄存器(在`.td`文件中,目标特定定义都是大写),如下所示: 223 | 224 | ``` 225 | def GR32 : RegisterClass<[i32], 32, 226 | [EAX, ECX, EDX, ESI, EDI, EBX, EBP, ESP, 227 | R8D, R9D, R10D, R11D, R14D, R15D, R12D, R13D]> { … } 228 | ``` 229 | 230 | 这个定义是说这个类中的寄存器可以保存32位整数值(“i32”),更喜欢32位对齐,具有指定的16个寄存器(在`.td`文件的其他地方定义)并有更多信息指定首选分配顺序和其他东西。 给定此定义,特定指令可以引用它,将其用作操作数。 例如,“完整32位寄存器”指令定义为: 231 | 232 | ``` 233 | let Constraints = "$src = $dst" in 234 | def NOT32r : I<0xF7, MRM2r, 235 | (outs GR32:$dst), (ins GR32:$src), 236 | "not{l}\t$dst", 237 | [(set GR32:$dst, (not GR32:$src))]>; 238 | ``` 239 | 240 | 这个定义说NOT32r是一个指令(它使用`I` tblgen类),指定编码信息( `0xF7, MRM2r` ),指定它定义一个“输出”32位寄存器`$dst`并具有一个32位寄存器“输入”名为`$src` (上面定义的`GR32`寄存器类定义哪些寄存器对操作数有效),指定指令的汇编语法(使用`{}`语法处理AT&T和Intel语法),指定指令的效果并提供它应该在最后一行匹配的模式。 第一行的“let”约束告诉寄存器分配器必须将输入和输出寄存器分配给同一物理寄存器。 241 | 242 | 这个定义是对指令的非常密集的描述,并且通用的LLVM代码可以使用从它派生的信息(通过`tblgen`工具)做很多`tblgen` 。 这个定义足以使指令选择通过编译器的输入IR代码上的模式匹配来形成该指令。 它还告诉寄存器分配器如何处理它,足以对指令进行编码和解码以加工代码字节,并且足以以文本形式解析和打印指令。 这些功能允许x86目标支持生成独立的x86汇编程序(它是“gas”GNU汇编程序的直接替代品)和目标描述中的反汇编程序以及处理JIT指令的编码。 243 | 244 | 除了提供有用的功能之外,具有由相同“真实”生成的多条信息也有其他原因。 这种方法使得汇编器和反汇编器在汇编语法或二进制编码中彼此不一致时几乎是不可行的。 它还使目标描述易于测试:指令编码可以进行单元测试,而不必涉及整个代码生成器。 245 | 246 | 虽然我们的目标是以一个很好的声明形式将尽可能多的目标信息放到`.td`文件中,但我们仍然没有解决所有问题。 相反,我们要求目标作者为各种支持例程编写一些C ++代码,并实现他们可能需要的任何目标特定传递(如`X86FloatingPoint.cpp` ,它处理x87浮点堆栈)。随着LLVM继续增长新目标,增加可以在`.td`文件中表达的目标数量变得越来越重要,并且我们继续增加`.td`文件的表达力来处理这个问题。一个很大的好处是随着时间的推移,它可以越来越容易地在LLVM中编写目标。 247 | 248 | ### 1.6 模块化设计提供的有用功能 249 | 250 | 除了优雅的设计外,模块化还为LLVM库的客户提供了一些有趣的功能。这些功能源于LLVM提供,但让客户决定如何使用它的大多数*策略*。 251 | 252 | #### 1.6.1 选择每个阶段运行的时间和地点 253 | 254 | 如前所述,LLVM IR可以有效地(反)序列化为/LLVM bitcode的二进制格式。由于LLVM IR是自包含的,并且序列化是一个无损过程,我们可以进行部分编译,将进度保存到磁盘,然后在将来的某个时间点继续工作。此特系能提供了许多有趣的功能,包括对链接时和安装时优化的支持,这两种功能都会从“编译时”延迟代码生成。 255 | 256 | 链接时优化(LTO)解决了编译器传统上一次只看到一个转换单元(例如,`.c`具有其所有头的文件)的问题,因此不能跨文件边界进行优化(如内联)。Clang等LLVM编译器使用`-flto`或`-O4`命令行选项支持此功能。此选项指示编译器向`.o`文件发出LLVM bitcode,而不是写出本机对象文件,并将代码生成延迟到链接时间,如图所示。 257 | 258 | ![LTO](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/LTO.png) 259 | 260 | 细节因您所使用的操作系统而异,但重要的是链接器检测到它具有LLVM bitcode `.o`文件而不是本机对象文件。当它看到这一点时,它会将所有bitcode文件读入内存,将它们链接在一起,然后在聚合上运行LLVM优化器。由于优化器现在可以看到代码的更大部分,它可以内联,传播常量,执行更积极的死代码消除,以及更多跨文件边界。虽然许多现代编译器支持LTO,但大多数(例如,GCC,Open64,英特尔编译器等)都是通过昂贵且缓慢的序列化过程来实现的。在LLVM中,LTO自然地脱离了系统的设计,并且适用于不同的源语言(与许多其他编译器不同),因为IR是真正的中间源语言。 261 | 262 | 安装时优化是延迟代码生成的想法,甚至比链接时间晚,一直到安装时间,下图所示。安装时间是一个非常有趣的时间(如果软件在一个盒子中发货,下载,上传到移动设备等),因为这是当你找到你所针对的设备的细节时。例如,在x86系列中,存在各种各样的芯片和特性。通过延迟指令选择,调度和代码生成的其他方面,您可以为应用程序最终运行的特定硬件选择最佳答案。 263 | 264 | ![InstallTime](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/Intro%20to%20LLVM/InstallTime.png) 265 | 266 | #### 1.6.2 单元测试优化器 267 | 268 | 编译器非常复杂,质量很重要,因此测试至关重要。例如,在修复导致优化器崩溃的错误之后,应添加回归测试以确保它不会再次发生。测试这种方法的传统方法是编写一个`.c`通过编译器运行的文件(例如),并使用一个测试工具来验证编译器是否崩溃。例如,这是GCC测试套件使用的方法。 269 | 270 | 这种方法的问题在于编译器由许多不同的子系统组成,甚至包括优化器中的许多不同的传递,所有这些传递都有可能在到达之前有问题的代码时改变输入代码的表达意思。如果前端或早期优化器发生了某些变化,测试用例很容易无法测试它应该测试的内容。 271 | 272 | 通过使用LLVM IR的文本形式和模块化优化器,LLVM测试套件具有高度集中的回归测试,可以从磁盘加载LLVM IR,通过一次优化传递运行它,并验证预期的行为。除了崩溃之外,更复杂的行为测试想要验证实际执行了优化。这是一个简单的测试用例,它检查常量传播过程是否与添加指令一起使用: 273 | 274 | ``` 275 | ; RUN: opt < %s -constprop -S | FileCheck %s 276 | define i32 @test() { 277 | %A = add i32 4, 5 278 | ret i32 %A 279 | ; CHECK: @test() 280 | ; CHECK: ret i32 9 281 | } 282 | ``` 283 | 284 | 该`RUN`行指定要执行的命令:在这种情况下,`opt`和`FileCheck`命令行工具。该`opt`程序是LLVM传递管理器的简单包装器,它连接所有标准传递(并且可以动态加载包含其他传递的插件)并将它们公开到命令行。该`FileCheck`工具验证其标准输入是否与一系列`CHECK`指令匹配。在这种情况下,这个简单的测试是验证`constprop`传球将`add`4和5 折叠成9。 285 | 286 | 虽然这看起来像是一个非常简单的例子,但通过编写.c文件来测试很难:前端经常在解析时进行常量折叠,因此编写下游到常量的代码是非常困难和脆弱的折叠优化通过。因为我们可以将LLVM IR作为文本加载并通过我们感兴趣的特定优化传递发送它,然后将结果转储为另一个文本文件,对于回归和功能测试来说,确切地测试我们想要的内容真的很简单。 287 | 288 | #### 1.6.3 使用BugPoint自动减少测试用例 289 | 290 | 当在LLVM库的编译器或其他客户端中发现错误时,修复它的第一步是获得一个再现问题的测试用例。一旦有了测试用例,最好将其最小化为再现问题的最小示例,并将其缩小到发生问题的LLVM部分,例如故障时的优化传递。虽然您最终会学习如何执行此操作,但是对于编译器生成错误代码但不会崩溃的情况,此过程非常繁琐,手动且特别痛苦。 291 | 292 | LLVM BugPoint工具使用LLVM 的IR序列化和模块化设计来自动执行此过程。例如,给定一个输入`.ll`或`.bc`文件以及导致优化器崩溃的优化传递列表,BugPoint会将输入减少到一个小测试用例并确定哪个优化器出错。然后它输出简化的测试用例和`opt`用于重现失败的命令。它通过使用类似于“delta debugging”的技术来减少输入和优化器传递列表。因为它知道LLVM IR的结构,所以与标准的“delta”命令行工具不同,BugPoint不会浪费时间生成无效的IR来输入优化器。 293 | 294 | 在更复杂的错误编译情况下,您可以指定输入,代码生成器信息,传递给可执行文件的命令行以及参考输出。 BugPoint将首先确定问题是由优化器还是代码生成器引起的,然后将测试用例重复分为两部分:一部分被发送到“已知良好”组件,另一部分被发送到“已知错误” “ 零件。通过迭代地将越来越多的代码移出已发送到已知错误代码生成器的分区,它减少了测试用例。 295 | 296 | BugPoint是一个非常简单的工具,在LLVM的整个生命周期中节省了无数小时的测试用例。没有其他开源编译器具有类似功能强大的工具,因为它依赖于明确定义的中间表示。也就是说,BugPoint并不完美,并且会从重写中获益。它可以追溯到2002年,并且通常只有当某人有一个非常棘手的错误来追踪现有工具处理得不好时才会改进。它随着时间的推移而增长,在没有一致设计或所有者的情况下积累新功能(例如JIT调试)。 297 | 298 | ### 1.7 回顾和未来的方向 299 | 300 | LLVM的模块化最初并非旨在直接实现此处描述的任何目标。这是一种自卫机制:很明显,我们不会在第一次尝试时把一切都弄好。例如,存在模块化传递管道,以便更容易隔离传递,以便在被更好的实现替换后可以丢弃它们。 301 | 302 | LLVM保持灵活的另一个主要方面(以及与库使用者有争议的话题)是我们愿意重新考虑先前的决策并对API进行广泛的更改而不必担心向后兼容性。例如,对LLVM IR本身的侵入性更改需要更新所有优化过程并导致对C ++ API的大量改变。我们已经多次这样做了,尽管它会给客户带来痛苦,但保持快速前进是正确的。为了使外部客户端的生活更轻松(并支持其他语言的绑定),我们为许多流行的API(旨在非常稳定)提供C包装器,新版本的LLVM旨在继续读取旧的`.ll`和`.bc`文件。 303 | 304 | 展望未来,我们希望继续使LLVM更加模块化,更易于子集化。例如,代码生成器仍然过于单一:目前无法根据功能对LLVM进行子集化。例如,如果您想使用JIT,但不需要内联汇编,异常处理或调试信息生成,则应该可以构建代码生成器而无需链接以支持这些功能。我们还不断提高优化器和代码生成器生成的代码质量,添加IR功能以更好地支持新语言和目标构造,并为在LLVM中执行高级语言特定优化添加更好的支持。 305 | 306 | LLVM项目以多种方式不断发展和完善。看到LLVM在其他项目中使用的不同方式的数量以及它如何在设计师从未想过的令人惊讶的新环境中不断出现,真是令人兴奋。新的LLDB调试器就是一个很好的例子:它使用Clang的C / C ++ / Objective-C解析器来解析表达式,使用LLVM JIT将它们转换为目标代码,使用LLVM反汇编程序,并使用LLVM目标来处理调用约定等等。能够重用这些现有代码允许开发调试器的人专注于编写调试器逻辑,而不是重新实现另一个(边缘正确的)C ++解析器。 307 | 308 | 尽管迄今为止取得了成功,但仍有许多工作要做,以及随着年龄的增长LLVM将变得不那么灵活和更加钙化的风险始终存在。虽然这个问题没有神奇的答案,但我希望继续接触新的问题领域,重新评估以前的决策,重新设计和丢弃代码的意愿将有所帮助。毕竟,目标不是完美,而是随着时间的推移不断变得更好。 -------------------------------------------------------------------------------- /doc/LLVM Coding Standards.md: -------------------------------------------------------------------------------- 1 | # LLVM Coding Standards 2 | 3 | [原文链接](http://llvm.org/docs/CodingStandards.html) 4 | 5 | [TOC] 6 | 7 | ## Introduction 8 | 9 | ## Languages, Libraries, and Standards 10 | 11 | ## Mechanical Source Issues 12 | 13 | ## Style Issues 14 | 15 | ## See Also 16 | 17 | -------------------------------------------------------------------------------- /doc/LLVM_FrozenGene.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/LLVM_FrozenGene.pdf -------------------------------------------------------------------------------- /doc/SSA.md: -------------------------------------------------------------------------------- 1 | # Static single assignment form 2 | *静态单一赋值形式* 3 | [链接](https://en.wikipedia.org/wiki/Static_single_assignment_form) 4 | 5 | 在编译器设计中,静态单一赋值形式(通常缩写为SSA形式或简称为SSA)是中间表示(IR)的属性,它要求每个变量只分配一次,并且每个变量在使用之前定义。原始IR中的存在变量以版本划分,新变量通常由原始名称在文本中用下标表示,以便每个定义都有自己的版本。在SSA形式中,use-def链是显式的,每个包含一个元素。 6 | 7 | SSA由Barry K. Rosen,Mark N. Wegman和F. Kenneth Zadeck于1988年提出。[1] Ron Cytron,Jeanne Ferrante和IBM的前三位研究人员开发了一种算法,可以有效地计算SSA形式。[2] 8 | 9 | 可以期望在Fortran或C的编译器中找到SSA,而在函数式语言编译器中,例如Scheme,ML和Haskell的编译器,通常使用连续传递样式(CPS)。 SSA在形式上等同于除了非本地控制流之外的良好行为的CPS子集,当CPS用作中间表示时不会发生这种情况。因此,以一个方式制定的优化和转换立即适用于另一个。 10 | 11 | ## Benefits 12 | 13 | SSA的主要用途来自于它如何通过简化变量的属性来同时简化和改进各种编译器优化的结果。 例如,考虑这段代码: 14 | 15 | ``` 16 | y := 1 17 | y := 2 18 | x := y 19 | ``` 20 | 21 | 人类可以看到第一个赋值是不必要的,并且在第三行中使用的y的值来自y的第二个赋值。 程序必须执行到达定义分析以确定这一点。 但如果该程序采用SSA形式,则这些都是即时的: 22 | 23 | ``` 24 | y1 := 1 25 | y2 := 2 26 | x1 := y2 27 | ``` 28 | 29 | 通过使用SSA启用或强大增强的编译器优化算法包括: 30 | 31 | - 常量折叠 32 | - value范围传播[3] 33 | - 稀疏条件常数传播 34 | - 无用代码消除 35 | - 全局变量编号 36 | - 部分冗余消除 37 | - 力量减少 38 | - 注册分配 39 | 40 | ## Converting to SSA 41 | 42 | 将普通代码转换为SSA形式主要是用新变量替换每个赋值的目标,并将变量的每个用法替换为到达该点的变量的“版本”。 例如,请考虑以下控制流程图: 43 | 44 | ![SSA_example1.1](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/SSA/SSA_example1.1.png) 45 | 46 | 更改“x <-- x - 3”左侧的名称,并将x的以下用法更改为该新名称将使程序保持不变。 这可以在SSA中通过创建两个新变量来利用:x1和x2,每个变量只分配一次。 同样,为所有其他变量提供可区分的下标产生: 47 | 48 | ![SSA_example1.2](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/SSA/SSA_example1.2.png) 49 | 50 | 很清楚每个用途所指的定义,除了一种情况:底部块中y的两个使用都可以指y1或y2,这取决于控制流采用的路径。 51 | 52 | 要解决此问题,会在最后一个块中插入一个特殊语句,称为Φ(Phi)函数。 该语句将通过“选择”y1或y2生成y的新定义,称为y3,具体取决于过去的控制流程。 53 | 54 | ![SSA_example1.3](https://github.com/Cyoung7/implement_llvm/blob/master/doc/image/SSA/SSA_example1.3.png) 55 | 56 | 现在,最后一个块可以简单地使用y3,并且将以任一方式获得正确的值。不需要x的Φ函数:只有x的一个版本,即x2到达这个位置,所以没有问题(换句话说,Φ(x2,x2)= x2)。 57 | 58 | 给定一个任意的控制流图,很难说出插入Φ函数的位置以及哪些变量。这个一般性问题有一个有效的解决方案,可以使用一个称为优势边界的概念来计算(见下文)。 59 | 60 | Φ功能未在大多数机器上实现为机器操作。编译器可以简单地通过在存储器(或相同的寄存器)中使用与产生Φ功能的输入的任何操作的目的地相同的位置来实现Φ功能。然而,当同时操作推测性地产生对Φ功能的输入时,这种方法不起作用,如在宽问题机器上可能发生的那样。通常,广泛发布机器具有在这种情况下由编译器用于实现Φ功能的选择指令。 61 | 62 | 根据Kenny Zadeck [4]的说法,Φ函数最初被称为伪函数,而SSA是在20世纪80年代在IBM Research开发的。 Φ功能的正式名称仅在作品首次发表在学术论文中时才被采用。 63 | 64 | ### Computing minimal SSA using dominance frontiers(边界计算) 65 | 66 | 首先,我们需要一个dominator的概念:我们说如果不通过A第一个就不可能到达B,则节点A严格控制控制流图中的节点B.这很有用,因为如果我们到达B,我们就知道A中的任何代码都已运行。如果A严格支配B或A = B,我们说A支配B(B由A支配)。 67 | 68 | 现在我们可以定义支配边界:如果A不严格支配B,则节点B处于节点A的支配边界,但确实支配B的一些直接前任。(可能节点A是B的直接前身。然后,因为任何节点都支配自身而节点A占主导地位,节点B处于节点A的支配边界。)从A的角度来看,这些节点是其他控制路径(不通过A)最早出现的节点。 69 | 70 | 优势边界捕获我们需要Φ函数的精确位置:如果节点A定义了某个变量,那么该定义和该定义单独(或重新定义)将到达每个节点A占主导地位。只有当我们离开这些节点并进入支配边界时,我们必须考虑引入同一变量的其他定义的其他流量。此外,控制流程图中不需要其他Φ功能来处理A的定义,我们可以做到这一点。 71 | 72 | 计算优势边界集[5]的一种算法是: 73 | 74 | ``` 75 | for each node b 76 | if the number of immediate predecessors of b ≥ 2 77 | for each p in immediate predecessors of b 78 | runner := p 79 | while runner ≠ idom(b) 80 | add b to runner’s dominance frontier set 81 | runner := idom(runner) 82 | ``` 83 | 84 | 注意:在上面的代码中,节点n的前一个前导是控制转移到节点n的任何节点,而idom(b)是立即支配节点b(单个集合)的节点。 85 | 86 | 有一种有效的算法可以找到每个节点的优势边界。 该算法最初在Cytron等人中描述。 同样有用的是Andrew Appel的书“Java中的现代编译器实现”第19章(剑桥大学出版社,2002年)。 有关详细信息,请参阅该文章。 87 | 88 | Rice大学的Keith D. Cooper,Timothy J. Harvey和Ken Kennedy在他们的题为“简单,快速优势算法”的论文中描述了一种算法。[5] 该算法使用精心设计的数据结构来提高性能。 89 | 90 | ## Variations that reduce the number of Φ functions 91 | 92 | “最小”SSA插入所需的最少数量的Φ函数,以确保每个名称仅被赋值一次,并且原始程序中每个名称的引用(使用)仍然可以引用唯一名称。 (需要后一个要求以确保编译器可以在每个操作中记下每个操作数的名称。) 93 | 94 | 然而,其中一些Φ功能可能已经死亡。 因此,最小SSA不一定产生特定过程所需的最少数量的Φ功能。 对于某些类型的分析,这些Φ功能是多余的,可能导致分析效率降低。 95 | 96 | ### Pruned SSA 97 | 98 | 修剪的SSA形式基于简单的观察:仅在Φ函数之后“活”的变量需要Φ函数。 (这里,“实时”表示该值沿着从所讨论的Φ函数开始的某个路径使用。)如果变量不是实时的,则不能使用Φ函数的结果,并且Φ函数的赋值为死。 99 | 100 | 修剪的SSA形式的构造使用Φ函数插入阶段中的实时变量信息来确定是否需要给定的Φ函数。如果原始变量名称不在Φ功能插入点处,则不插入Φ功能。 101 | 102 | 另一种可能性是将修剪视为死代码消除问题。然后,只有当输入程序中的任何用途被重写到它时,或者如果它将用作另一个Φ函数中的参数时,Φ函数才是有效的。输入SSA表单时,每次使用都会被重写为最接近它的定义。然后,Φ函数将被认为是实时的,只要它是支配至少一个用途的最近定义,或至少一个活Φ的参数。 103 | 104 | ### Semi-pruned SSA 105 | 106 | 半修剪的SSA形式[6]试图减少Φ函数的数量而不会产生计算实时变量信息的相对高的成本。 它基于以下观察:如果变量在进入基本块时永远不会存在,则它永远不需要Φ函数。 在SSA构造期间,省略任何“块局部”变量的Φ函数。 107 | 108 | 计算块局部变量集是一种比完全实时变量分析更简单,更快速的过程,使得半修剪SSA形式比修剪SSA形式更有效。 另一方面,半修剪的SSA形式将包含更多的Φ函数。 109 | 110 | ## Converting out of SSA form 111 | 112 | SSA格式通常不用于直接执行(尽管可以解释SSA [7]),并且它经常在“另一个IR之上”使用它与之保持直接对应。这可以通过将SSA“构造”为一组函数来实现,这些函数在现有IR的部分(基本块,指令,操作数等)与其SSA对应物之间进行映射。当不再需要SSA格式时,可以丢弃这些映射函数,只留下现在优化的IR。 113 | 114 | 在SSA表单上执行优化通常会导致纠缠的SSA-Web,这意味着存在Φ指令,其操作数并非都具有相同的根操作数。在这种情况下,使用颜色输出算法来解决SSA问题。朴素算法沿着每个前任路径引入一个副本,这导致不同根符号的源被放入Φ而不是Φ的目的地。有多种算法可以用较少的副本从SSA中出来,大多数使用干扰图或一些近似它来进行复制合并。 115 | 116 | ## Extensions 117 | 118 | SSA格式的扩展可以分为两类。 119 | 120 | 重命名方案扩展会更改重命名标准。 回想一下,SSA表单在为每个变量赋值时重命名。 替代方案包括静态单一使用形式(在使用时在每个语句中重命名每个变量)和静态单一信息形式(在赋值时重命名每个变量,并在后支配边界处重命名)。 121 | 122 | 特定于功能的扩展保留变量的单一赋值属性,但包含新的语义以模拟其他功能。 一些特定于功能的扩展模拟高级编程语言功能,如数组,对象和别名指针。 其他特定于功能的扩展模拟了低级架构功能,如推测和预测。 -------------------------------------------------------------------------------- /doc/The LLVM Target-Independent Code Generator.md: -------------------------------------------------------------------------------- 1 | # The LLVM Target-Independent Code Generator 2 | 3 | [原文链接](https://llvm.org/docs/CodeGenerator.html) 4 | 5 | [TOC] 6 | 7 | ## Introduction 8 | 9 | ## Target description classes 10 | 11 | ## Machine code description classes 12 | 13 | ## The “MC” Layer 14 | 15 | ## Target-independent code generation algorithms 16 | 17 | ## Implementing a Native Assembler 18 | 19 | ## Target-specific Implementation Notes 20 | 21 | -------------------------------------------------------------------------------- /doc/Writing an LLVM Pass.md: -------------------------------------------------------------------------------- 1 | # Writing an LLVM Pass 2 | 3 | Information on how to write LLVM transformations and analyses.(LLVM的转换和分析) 4 | 5 | ./gh-md-toc /media/cyoung/000E88CC0009670E/CLionProjects/implement_llvm/doc/Writing\ an\ LLVM\ Pass.md 6 | 7 | [原文链接](http://llvm.org/docs/WritingAnLLVMPass.html) 8 | 9 | [TOC] 10 | 11 | * [Writing an LLVM Pass](#writing-an-llvm-pass) 12 | * [Introduction — What is a pass?](#introduction--what-is-a-pass) 13 | * [Quick Start — Writing hello world](#quick-start--writing-hello-world) 14 | * [Setting up the build environment](#setting-up-the-build-environment) 15 | * [Basic code required](#basic-code-required) 16 | * [Running a pass with opt](#running-a-pass-with-opt) 17 | * [Pass classes and requirements](#pass-classes-and-requirements) 18 | * [The ImmutablePass class](#the-immutablepass-class) 19 | * [The ModulePass class](#the-modulepass-class) 20 | * [The runOnModule method](#the-runonmodule-method) 21 | * [The CallGraphSCCPass class](#the-callgraphsccpass-class) 22 | * [The doInitialization(CallGraph &) method](#the-doinitializationcallgraph--method) 23 | * [The runOnSCC method](#the-runonscc-method) 24 | * [The doFinalization(CallGraph &) method](#the-dofinalizationcallgraph--method) 25 | * [The FunctionPass class](#the-functionpass-class) 26 | * [The doInitialization(Module &) method](#the-doinitializationmodule--method) 27 | * [The runOnFunction method](#the-runonfunction-method) 28 | * [The doFinalization(Module &) method](#the-dofinalizationmodule--method) 29 | * [The LoopPass class](#the-looppass-class) 30 | * [The doInitialization(Loop *, LPPassManager &) method](#the-doinitializationloop--lppassmanager--method) 31 | * [The runOnLoop method](#the-runonloop-method) 32 | * [The doFinalization() method](#the-dofinalization-method) 33 | * [The RegionPass class](#the-regionpass-class) 34 | * [The doInitialization(Region *, RGPassManager &) method](#the-doinitializationregion--rgpassmanager--method) 35 | * [The runOnRegion method](#the-runonregion-method) 36 | * [The doFinalization() method](#the-dofinalization-method-1) 37 | * [The BasicBlockPass class](#the-basicblockpass-class) 38 | * [The doInitialization(Function &) method](#the-doinitializationfunction--method) 39 | * [The runOnBasicBlock method](#the-runonbasicblock-method) 40 | * [The doFinalization(Function &) method](#the-dofinalizationfunction--method) 41 | * [The MachineFunctionPass class](#the-machinefunctionpass-class) 42 | * [The runOnMachineFunction(MachineFunction &MF) method](#the-runonmachinefunctionmachinefunction-mf-method) 43 | * [Pass registration](#pass-registration) 44 | * [The print method](#the-print-method) 45 | * [Specifying interactions between passes](#specifying-interactions-between-passes) 46 | * [The getAnalysisUsage metho](#the-getanalysisusage-metho) 47 | * [The AnalysisUsage::addRequired<> and AnalysisUsage::addRequiredTransitive<> methods](#the-analysisusageaddrequired-and-analysisusageaddrequiredtransitive-methods) 48 | * [The AnalysisUsage::addPreserved<> method](#the-analysisusageaddpreserved-method) 49 | * [Example implementations of getAnalysisUsage](#example-implementations-of-getanalysisusage) 50 | * [The getAnalysis<> and getAnalysisIfAvailable<> methods](#the-getanalysis-and-getanalysisifavailable-methods) 51 | * [Implementing Analysis Groups](#implementing-analysis-groups) 52 | * [Analysis Group Concepts](#analysis-group-concepts) 53 | * [Using RegisterAnalysisGroup](#using-registeranalysisgroup) 54 | * [Pass Statistics](#pass-statistics) 55 | * [What PassManager does](#what-passmanager-does) 56 | * [The releaseMemory method](#the-releasememory-method) 57 | * [Registering dynamically loaded passes](#registering-dynamically-loaded-passes) 58 | * [Using existing registries](#using-existing-registries) 59 | * [Creating new registries](#creating-new-registries) 60 | * [Using GDB with dynamically loaded passes](#using-gdb-with-dynamically-loaded-passes) 61 | * [Setting a breakpoint in your pass](#setting-a-breakpoint-in-your-pass) 62 | * [Miscellaneous Problems](#miscellaneous-problems) 63 | * [Future extensions planned](#future-extensions-planned) 64 | * [Multithreaded LLVM](#multithreaded-llvm) 65 | 66 | ## Introduction — What is a pass? 67 | 68 | LLVM Pass框架是LLVM系统的重要组成部分,因为LLVM传递(transformations)存在着编译器大多数有趣部分。通过执行构成编译器的转换和优化,它们构建这些转换所使用到的分析结果,基于以上,它们是编译器代码的结构化技术。 69 | 70 | 所有LLVMpasses都是[Pass](http://llvm.org/doxygen/classllvm_1_1Pass.html)类的子类,它通过重写从Pass继承的虚方法来实现功能。根据pass的工作方式,您应该继承[ModulePass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-modulepass) , [CallGraphSCCPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-callgraphsccpass), [FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass) 或[LoopPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-looppass),或[RegionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-regionpass)或 [BasicBlockPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basicblockpass) 类,这样可以为系统提供有关pass操作的更多信息,以及如何与其他pass结合使用。 LLVM Pass Framework的一个主要特性是对您的pass有所约束(由它们派生的类指示)来让pass以高效的方式运行。 71 | 72 | 我们首先向您展示如何构建Pass,从设置代码到编译,加载和执行它。基础知识完成后,将讨论更多高级功能。 73 | 74 | ## Quick Start — Writing hello world 75 | 76 | 在这里,我们描述如何编写passes的“hello world”。 “Hello”pass旨在简单地打印出正在编译的程序中存在的非外部函数的名称。 它根本不修改程序,它只是检查它。 此pass的源代码和文件位于`lib/Transforms/Hello`目录中的LLVM源代码树中。 77 | 78 | ### Setting up the build environment 79 | 80 | 首先,配置和构建LLVM。 接下来,您需要在LLVM源代码库中的某个位置创建一个新目录。 对于这个例子,我们假设您创建了`lib/Transforms/Hello`。 最后,您必须设置一个构建脚本,该脚本将编译新pass的源代码。 为此,请将以下内容复制到CMakeLists.txt中: 81 | 82 | ```cmake 83 | add_llvm_loadable_module( LLVMHello 84 | Hello.cpp 85 | PLUGIN_TOOL 86 | opt 87 | ) 88 | ``` 89 | 90 | 和以下一行 `lib/Transforms/CMakeLists.txt`: 91 | 92 | ```cmake 93 | add_subdirectory(Hello) 94 | ``` 95 | 96 | (请注意,已经有一个名为Hello的目录,带有示例“Hello”pass;您可以使用它 - 在这种情况下,您不需要修改任何 `CMakeLists.txt`文件 - 或者,如果您想从头开始创建所有内容 ,使用另一个名字。) 97 | 98 | 此构建脚本指定编译当前目录中的Hello.cpp文件并将其链接到共享对象`$(LEVEL)/lib/LLVMHello.so`,该工具可由opt工具通过其-load选项动态加载。 如果您的操作系统使用.so之外的后缀(例如Windows或Mac OS X),则将使用相应的扩展名。 99 | 100 | 现在我们已经设置了构建脚本,我们只需要为pass本身编写代码。 101 | 102 | ### Basic code required 103 | 104 | 现在我们有了编译新pass的方法,我们只需要编写它。 从以下开始: 105 | 106 | ```c++ 107 | #include "llvm/Pass.h" 108 | #include "llvm/IR/Function.h" 109 | #include "llvm/Support/raw_ostream.h" 110 | ``` 111 | 112 | 这是必需的,因为我们正在编写Pass,我们正在使用 [Function](http://llvm.org/doxygen/classllvm_1_1Function.html)s,我们将进行一些打印。 113 | 114 | 接下来我们有: 115 | 116 | ```c++ 117 | using namespace llvm; 118 | ``` 119 | 120 | ...这是必需的,因为包含文件中的函数存在于llvm命名空间中。 121 | 122 | 接下来我们有: 123 | 124 | ```c++ 125 | namespace { 126 | ``` 127 | 128 | ...开始一个匿名命名空间。 匿名命名空间是C++的“静态”关键字是C(在全局范围内)。 它使在匿名命名空间内声明的内容仅对当前文件可见。 如果您不熟悉它们,请参阅一本体面的C++书籍以获取更多信息。 129 | 130 | 接下来,我们声明我们的传递本身: 131 | 132 | ```c++ 133 | struct Hello : public FunctionPass { 134 | ``` 135 | 136 | 这声明了一个“Hello”类,它是[FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)的子类。 稍后将详细描述不同的内置pass子类,但是现在,知道FunctionPass一次对一个函数进行操作。 137 | 138 | ```c++ 139 | static char ID; 140 | Hello() : FunctionPass(ID) {} 141 | ``` 142 | 143 | 这声明了LLVM用于标识pass的传递标识符。 这允许LLVM避免使用昂贵的C++运行时信息。 144 | 145 | ```c++ 146 | bool runOnFunction(Function &F) override { 147 | errs() << "Hello: "; 148 | errs().write_escaped(F.getName()) << '\n'; 149 | return false; 150 | } 151 | }; // end of struct Hello 152 | } // end of anonymous namespace 153 | ``` 154 | 155 | 我们声明了一个 [runOnFunction](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonfunction)方法,它覆盖了从 [FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)继承的抽象虚方法。 这是我们应该做的事情,所以我们只用每个函数的名称打印出我们的消息。 156 | 157 | ```c++ 158 | char Hello::ID = 0; 159 | ``` 160 | 161 | 我们在这里初始化通行证ID。 LLVM使用ID的地址来标识传递,因此初始化值并不重要。 162 | 163 | ```c++ 164 | static RegisterPass X("hello", "Hello World Pass", 165 | false /* Only looks at CFG */, 166 | false /* Analysis Pass */); 167 | ``` 168 | 169 | 最后,我们e [register our class](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-registration) Hello,给它一个命令行参数“hello”,并命名为“Hello World Pass”。 最后两个参数描述了它的行为:如果传递遍历CFG而不修改它,那么第三个参数设置为true; 如果pass是分析遍,例如dominator tree pass,则提供true作为第四个参数。 170 | 171 | 整体而言,.cpp文件如下所示: 172 | 173 | ```c++ 174 | #include "llvm/Pass.h" 175 | #include "llvm/IR/Function.h" 176 | #include "llvm/Support/raw_ostream.h" 177 | 178 | using namespace llvm; 179 | 180 | namespace { 181 | struct Hello : public FunctionPass { 182 | static char ID; 183 | Hello() : FunctionPass(ID) {} 184 | 185 | bool runOnFunction(Function &F) override { 186 | errs() << "Hello: "; 187 | errs().write_escaped(F.getName()) << '\n'; 188 | return false; 189 | } 190 | }; // end of struct Hello 191 | } // end of anonymous namespace 192 | 193 | char Hello::ID = 0; 194 | static RegisterPass X("hello", "Hello World Pass", 195 | false /* Only looks at CFG */, 196 | false /* Analysis Pass */); 197 | ``` 198 | 199 | 现在它们一起使用,从构建目录的顶层使用简单的“gmake”命令编译该文件,您应该获得一个新文件“lib / LLVMHello.so”。 请注意,此文件中的所有内容都包含在匿名命名空间中 - 这反映了这样一个事实:pass是自包含的单元,不需要外部接口(尽管它们可以使用它们)。 200 | 201 | ### Running a pass with *opt* 202 | 203 | 现在您有了一个全新的闪亮共享对象文件,我们可以使用opt命令通过您的传递来运行LLVM程序。 因为您使用RegisterPass注册了您的通行证,所以一旦加载,您就可以使用opt工具来访问它。 204 | 205 | 要对其进行测试,请按照 [Getting Started with the LLVM System](https://llvm.org/docs/GettingStarted.html)末尾的示例将“Hello World”编译为LLVM。 我们现在可以通过这样的转换运行程序的bitcode文件(hello.bc)(或者当然,任何bitcode文件都可以): 206 | 207 | ``` 208 | $ opt -load lib/LLVMHello.so -hello < hello.bc > /dev/null 209 | Hello: __main 210 | Hello: puts 211 | Hello: main 212 | ``` 213 | 214 | [`-load`](https://llvm.org/docs/CommandGuide/lli.html#cmdoption-load)选项指定opt应该将您的传递加载为共享对象,这使得“-hello”成为有效的命令行参数(这是您需要 [register your pass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-registration))的一个原因)。 因为Hello pass不以任何有趣的方式修改程序,所以我们只丢弃opt的结果(将它发送到 /dev/null)。 215 | 216 | 要查看您注册的其他字符串发生了什么,请尝试使用[`-help`](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-help)选项运行opt: 217 | 218 | ``` 219 | $ opt -load lib/LLVMHello.so -help 220 | OVERVIEW: llvm .bc -> .bc modular optimizer and analysis printer 221 | 222 | USAGE: opt [subcommand] [options] 223 | 224 | OPTIONS: 225 | Optimizations available: 226 | ... 227 | -guard-widening - Widen guards 228 | -gvn - Global Value Numbering 229 | -gvn-hoist - Early GVN Hoisting of Expressions 230 | -hello - Hello World Pass 231 | -indvars - Induction Variable Simplification 232 | -inferattrs - Infer set function attributes 233 | ... 234 | ``` 235 | 236 | 传递名称将作为传递的信息字符串添加,为opt用户提供一些文档。 既然你有一个工作通行证,你就可以继续前进,让它做你想要的酷转换。 一旦你完成所有的工作和测试,找出你的传球速度可能会很有用。 [PassManager](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-passmanager)提供了一个很好的命令行选项(--time-passes),允许您获取有关传递执行时间的信息以及您排队的其他传递。 例如: 237 | 238 | ```shell 239 | $ opt -load lib/LLVMHello.so -hello -time-passes < hello.bc > /dev/null 240 | Hello: __main 241 | Hello: puts 242 | Hello: main 243 | ===-------------------------------------------------------------------------=== 244 | ... Pass execution timing report ... 245 | ===-------------------------------------------------------------------------=== 246 | Total Execution Time: 0.0007 seconds (0.0005 wall clock) 247 | 248 | ---User Time--- --User+System-- ---Wall Time--- --- Name --- 249 | 0.0004 ( 55.3%) 0.0004 ( 55.3%) 0.0004 ( 75.7%) Bitcode Writer 250 | 0.0003 ( 44.7%) 0.0003 ( 44.7%) 0.0001 ( 13.6%) Hello World Pass 251 | 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0001 ( 10.7%) Module Verifier 252 | 0.0007 (100.0%) 0.0007 (100.0%) 0.0005 (100.0%) Total 253 | ``` 254 | 255 | 如您所见,我们上面的实现非常快。 opt工具会自动插入列出的其他passes,以验证passes发出的LLVM是否仍然有效并且格式良好的LLVM(尚未以某种方式被破坏)。 256 | 257 | 现在你已经看到了传递背后的机制的基础知识,我们可以讨论它们如何工作以及如何使用它们的更多细节。 258 | 259 | ## Pass classes and requirements 260 | 261 | 在设计新传递时,您应该做的第一件事就是确定应该为传递子类化的类。 [Hello World](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basiccode)示例使用 [FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)类进行实现,但我们没有讨论为什么或何时发生这种情况。 在这里,我们讨论可用的类,从最一般到最具体。 262 | 263 | 为Pass选择超类时,您应该选择最具体的类,同时仍然能够满足列出的要求。 这为LLVM Pass Infrastructure提供了优化passes运行所需的信息,因此生成的编译器不会非常慢。 264 | 265 | ### The ImmutablePass class 266 | 267 | 最简单和无聊的传递类型是“[ImmutablePass](http://llvm.org/doxygen/classllvm_1_1ImmutablePass.html)”类。 此传递类型用于不必运行的传递,不更改状态,永远不需要更新。 这不是正常类型的转换或分析,但可以提供有关当前编译器配置的信息。 268 | 269 | 虽然很少使用此传递类,但提供有关正在编译的当前目标机器的信息以及可能影响各种转换的其他静态信息非常重要。 270 | 271 | ImmutablePasses永远不会使其他转换无效,永远不会失效,永远不会“运行”。 272 | 273 | ### The ModulePass class 274 | 275 | [ModulePass](http://llvm.org/doxygen/classllvm_1_1ModulePass.html)类是您可以使用的所有超类中最常用的类。 从ModulePass派生表明您的传递使用整个程序作为一个单元,以无法预测的顺序引用函数体,或添加和删除函数。 因为对ModulePass子类的行为一无所知,所以不能对它们的执行进行优化。 276 | 277 | 模块传递可以使用函数级别传递(例如,支配者)使用`getAnalysis`接口`getAnalysis (llvm :: Function *)`来提供检索分析结果的函数,如果函数传递不需要任何模块或不可变传递。 注意,这只能对分析运行的函数进行,例如, 在统治者的情况下,你应该只要求DominatorTree进行函数定义,而不是声明。 278 | 279 | 要编写正确的ModulePass子类,请从ModulePass派生并使用以下签名重载runOnModule方法: 280 | 281 | #### The runOnModule method 282 | 283 | ```c++ 284 | virtual bool runOnModule(Module &M) = 0; 285 | ``` 286 | 287 | runOnModule方法执行pass的有趣工作。 如果模块被转换修改,它应该返回true,否则返回false。 288 | 289 | ### The CallGraphSCCPass class 290 | 291 | [CallGraphSCCPass](http://llvm.org/doxygen/classllvm_1_1CallGraphSCCPass.html)用于需要在调用图上自动遍历程序的传递(在调用者之前调用callees)。从CallGraphSCCPass派生提供了一些构建和遍历CallGraph的机制,但也允许系统优化CallGraphSCCPasses的执行。如果您的通行证符合下面列出的要求,并且不符合 [FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass) 或 [BasicBlockPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basicblockpass),的要求,则应从CallGraphSCCPass派生。 292 | 293 | TODO:简要解释一下SCC,Tarjan的算法和B-U的含义。 294 | 295 | 为了明确,CallGraphSCCPass子类是: 296 | 297 | - ...不允许检查或修改除当前SCC以及SCC的直接呼叫者和直接被叫者之外的任何功能。 298 | - ...需要保留当前的CallGraph对象,更新它以反映对程序所做的任何更改。 299 | - ...不允许在当前模块中添加或删除SCC,但它们可能会更改SCC的内容。 300 | - ...允许在当前模块中添加或删除全局变量。 301 | - ...允许在runOnSCC(包括全局数据)的调用中维护状态。 302 | 303 | 在某些情况下,实现CallGraphSCCPass有点棘手,因为它必须处理具有多个节点的SCC。如果修改程序,下面描述的所有虚拟方法都应返回true,否则返回false。 304 | 305 | #### The doInitialization(CallGraph &) method 306 | 307 | ``` 308 | virtual bool doInitialization(CallGraph &CG); 309 | ``` 310 | 311 | `doInitialization`方法允许执行CallGraphSCCPas不允许执行的大部分操作。 它们可以添加和删除函数,获取函数指针等.doInitialization方法旨在执行不依赖于正在处理的SCC的简单初始化类型的东西。 doInitialization方法调用未安排与任何其他传递执行重叠(因此它应该非常快)。 312 | 313 | #### The runOnSCC method 314 | 315 | ``` 316 | virtual bool runOnSCC(CallGraphSCC &SCC) = 0; 317 | ``` 318 | 319 | runOnSCC方法执行pass的有趣工作,如果模块被转换修改则返回true,否则返回false。 320 | 321 | #### The doFinalization(CallGraph &) method 322 | 323 | ``` 324 | virtual bool doFinalization(CallGraph &CG); 325 | ``` 326 | 327 | doFinalization方法是一种不常用的方法,当传递框架为正在编译的程序中的每个SCC调用runOnSCC时调用该方法。 328 | 329 | ### The FunctionPass class 330 | 331 | 与ModulePass子类相比, [FunctionPass](http://llvm.org/doxygen/classllvm_1_1Pass.html) 子类确实具有系统可以预期的可预测的本地行为。 所有FunctionPass都独立于程序中的所有其他功能执行程序中的每个功能。 FunctionPasses不要求它们按特定顺序执行,FunctionPasses不要修改外部函数。 332 | 333 | 显而易见,不允许FunctionPass子类: 334 | 335 | - 检查或修改当前正在处理的功能以外的功能。 336 | - 在当前模块中添加或删除功能。 337 | - 在当前模块中添加或删除全局变量。 338 | - 跨[runOnFunction](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonfunction)调用(包括全局数据)维护状态。 339 | 340 | 实现FunctionPass通常很简单(例如,请参阅Hello World pass)。 FunctionPasses可能会使三个虚拟方法超载以完成其工作。 如果修改程序,所有这些方法都应返回true,否则返回false。 341 | 342 | #### The doInitialization(Module &) method 343 | 344 | ```c++ 345 | virtual bool doInitialization(Module &M); 346 | ``` 347 | 348 | doInitialization方法允许执行不允许FunctionPasses执行的大部分操作。 它们可以添加和删除函数,获取函数指针等.doInitialization方法旨在执行不依赖于正在处理的函数的简单初始化类型的东西。 doInitialization方法调用未安排与任何其他传递执行重叠(因此它应该非常快)。 349 | 350 | 如何使用此方法的一个很好的例子是 [LowerAllocations](http://llvm.org/doxygen/LowerAllocations_8cpp-source.html)传递。 此过程将malloc和free指令转换为依赖于平台的malloc()和free()函数调用。 它使用doInitialization方法获取对其所需的malloc和free函数的引用,如有必要,可将原型添加到模块中。 351 | 352 | #### The runOnFunction method 353 | 354 | ```c++ 355 | virtual bool runOnFunction(Function &F) = 0; 356 | ``` 357 | 358 | runOnFunction方法必须由您的子类实现,以执行传递的转换或分析工作。 像往常一样,如果修改了函数,则应返回true值。 359 | 360 | #### The doFinalization(Module &) method 361 | 362 | ``` 363 | virtual bool doFinalization(Module &M); 364 | ``` 365 | 366 | doFinalization方法是一种不经常使用的方法,当传递框架为正在编译的程序中的每个函数调用[runOnFunction](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonfunction)时调用该方法。 367 | 368 | ### The LoopPass class 369 | 370 | 所有LoopPass都在函数中的每个循环上执行,与函数中的所有其他循环无关。 LoopPass以循环嵌套顺序处理循环,以便最后处理最外层循环。 371 | 372 | 允许LoopPass子类使用LPPassManager接口更新循环嵌套。 实现循环传递通常很简单。 LoopPasses可能会使三个虚拟方法超载以完成其工作。 如果修改程序,所有这些方法都应该返回true,否则应该返回false。 373 | 374 | LoopPass子类旨在作为主循环传递管道的一部分运行,需要保留其他循环在其管道所需的所有相同的函数分析。 为了简化这一过程,LoopUtils.h提供了一个getLoopAnalysisUsage函数。 它可以在子类的getAnalysisUsage覆盖中调用,以获得一致和正确的行为。 类似地,INITIALIZE_PASS_DEPENDENCY(LoopPass)将初始化这组功能分析。 375 | 376 | #### The doInitialization(Loop *, LPPassManager &) method 377 | 378 | ```c++ 379 | virtual bool doInitialization(Loop *, LPPassManager &LPM); 380 | ``` 381 | 382 | doInitialization方法旨在执行不依赖于正在处理的函数的简单初始化类型的东西。 doInitialization方法调用未安排与任何其他传递执行重叠(因此它应该非常快)。 LPPassManager接口应用于访问功能或模块级别的分析信息。 383 | 384 | #### The runOnLoop method 385 | 386 | ```c++ 387 | virtual bool runOnLoop(Loop *, LPPassManager &LPM) = 0; 388 | ``` 389 | 390 | 您的子类必须实现runOnLoop方法才能执行传递的转换或分析工作。 像往常一样,如果修改了函数,则应返回true值。 LPPassManager接口应该用于更新循环嵌套。 391 | 392 | #### The doFinalization() method 393 | 394 | ```c++ 395 | virtual bool doFinalization(); 396 | ``` 397 | 398 | doFinalization方法是一种不经常使用的方法,当传递框架为正在编译的程序中的每个循环调用runOnLoop时调用该方法。 399 | 400 | ### The RegionPass class 401 | 402 | RegionPass类似于 [LoopPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-looppass),但在函数中的每个单个条目单个退出区域上执行。 RegionPass以嵌套顺序处理区域,以便最后处理最外层区域。 403 | 404 | 允许RegionPass子类使用RGPassManager接口更新区域树。 您可以重载RegionPass的三个虚方法来实现您自己的区域传递。 如果修改程序,所有这些方法都应该返回true,否则应该返回false。 405 | 406 | #### The doInitialization(Region *, RGPassManager &) method 407 | 408 | ```c++ 409 | virtual bool doInitialization(Region *, RGPassManager &RGM); 410 | ``` 411 | 412 | doInitialization方法旨在执行不依赖于正在处理的函数的简单初始化类型的东西。 doInitialization方法调用未安排与任何其他传递执行重叠(因此它应该非常快)。 RPPassManager接口应用于访问功能或模块级别分析信息。 413 | 414 | #### The runOnRegion method 415 | 416 | ```c++ 417 | virtual bool runOnRegion(Region *, RGPassManager &RGM) = 0; 418 | ``` 419 | 420 | runOnRegion方法必须由您的子类实现,以执行传递的转换或分析工作。 像往常一样,如果修改了区域,则应返回真值。 应使用RGPassManager接口更新区域树。 421 | 422 | #### The doFinalization() method 423 | 424 | ```c++ 425 | virtual bool doFinalization(); 426 | ``` 427 | 428 | doFinalization方法是一种不常用的方法,当pass框架为正在编译的程序中的每个区域调用runOnRegion时调用该方法。 429 | 430 | ### The BasicBlockPass class 431 | 432 | `BasicBlockPasses` 就像[FunctionPass’s](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)一样,除了它们必须一次限制它们的检查和修改范围到一个基本块。 因此,他们不允许执行以下任何操作: 433 | 434 | - 修改或检查当前基本块之外的任何基本块。 435 | - 在 [runOnBasicBlock](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonbasicblock).的调用中维护状态。 436 | - 修改控制流图(通过更改终止符指令) 437 | - 任何禁止使用 [FunctionPasses](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)的东西。 438 | 439 | BasicBlockPasses对传统的本地和“窥视孔”优化非常有用。 它们可能会覆盖[FunctionPass’s](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass) 所具有的相同的[doInitialization(Module &)](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-doinitialization-mod)和 [doFinalization(Module &)](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-dofinalization-mod) 方法,但也可以实现以下虚拟方法: 440 | 441 | #### The doInitialization(Function &) method 442 | 443 | ```c++ 444 | virtual bool doInitialization(Function &F); 445 | ``` 446 | 447 | `doInitialization` 方法允许执行`BasicBlockPass`es不允许执行的大部分操作,但FunctionPasses可以执行。 doInitialization方法旨在执行简单的初始化,该初始化不依赖于正在处理的BasicBlock。 doInitialization方法调用未安排与任何其他传递执行重叠(因此它应该非常快)。 448 | 449 | #### The runOnBasicBlock method 450 | 451 | ```c++ 452 | virtual bool runOnBasicBlock(BasicBlock &BB) = 0; 453 | ``` 454 | 455 | 重写此函数以执行BasicBlockPass的工作。 此功能不允许检查或修改参数以外的基本块,也不允许修改CFG。 如果修改了基本块,则必须返回true值。 456 | 457 | #### The doFinalization(Function &) method 458 | 459 | ```c++ 460 | virtual bool doFinalization(Function &F); 461 | ``` 462 | 463 | doFinalization方法是一种不经常使用的方法,当传递框架为正在编译的程序中的每个BasicBlock调用[runOnBasicBlock](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonbasicblock)时调用该方法。 这可用于执行按功能完成。 464 | 465 | ### The MachineFunctionPass class 466 | 467 | `MachineFunctionPass`是LLVM代码生成器的一部分,它在程序中每个LLVM函数的机器相关表示上执行。 468 | 469 | 代码生成器传递由TargetMachine :: addPassesToEmitFile和类似例程专门注册和初始化,因此通常不能从opt或bugpoint命令运行它们。 470 | 471 | MachineFunctionPass也是一个FunctionPass,因此适用于FunctionPass的所有限制也适用于它。 MachineFunctionPasses还有其他限制。 特别是,不允许MachineFunctionPasses执行以下任何操作: 472 | 473 | - 修改或创建任何LLVM IR指令,BasicBlocks,Arguments,Functions,GlobalVariables,GlobalAliases或Modules。 474 | - 修改当前正在处理的MachineFunction以外的MachineFunction。 475 | - 跨 [runOnMachineFunction](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-runonmachinefunction) (包括全局数据)的调用维护状态。 476 | 477 | #### The runOnMachineFunction(MachineFunction &MF) method 478 | 479 | ```c++ 480 | virtual bool runOnMachineFunction(MachineFunction &MF) = 0; 481 | ``` 482 | 483 | runOnMachineFunction可以被认为是MachineFunctionPass的主要入口点; 也就是说,您应该覆盖此方法以执行MachineFunctionPass的工作。 484 | 485 | 在Module中的每个MachineFunction上调用runOnMachineFunction方法,以便MachineFunctionPass可以对函数的机器相关表示执行优化。 如果您想获得正在使用的MachineFunction的LLVM函数,请使用MachineFunction的getFunction()访问器方法 - 但请记住,您不能从MachineFunctionPass修改LLVM函数或其内容。 486 | 487 | ### Pass registration 488 | 489 | 在Hello World示例传递中,我们说明了传递注册的工作原理,并讨论了使用它的一些原因以及它的用途。 在这里,我们讨论如何以及为什么通过注册。 490 | 491 | 如上所述,通过RegisterPass模板注册。 template参数是要在命令行上使用的传递的名称,用于指定应将传递添加到程序中(例如,使用opt或bugpoint)。 第一个参数是传递的名称,它将用于程序的 [`-help`](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-help)输出,以及-debug-pass选项生成的调试输出。 492 | 493 | 如果您希望传递易于转储,则应实现虚拟打印方法: 494 | 495 | #### The print method 496 | 497 | ```c++ 498 | virtual void print(llvm::raw_ostream &O, const Module *M) const; 499 | ``` 500 | 501 | 打印方法必须通过“分析”来实现,以便打印分析结果的人类可读版本。 这对于调试分析本身以及其他人来确定分析如何工作非常有用。 使用opt -analyze参数来调用此方法。 502 | 503 | llvm :: raw_ostream参数指定要在其上写入结果的流,Module参数提供指向已分析程序的顶级模块的指针。 但请注意,在某些情况下(例如从调试器调用Pass :: dump()),此指针可能为NULL,因此它只应用于增强调试输出,不应该依赖它。 504 | 505 | ### Specifying interactions between passes 506 | 507 | PassManager的主要职责之一是确保传递正确地相互交互。 因为PassManager试图 [optimize the execution of passes](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-passmanager),所以它必须知道传递如何相互交互以及各种传递之间存在哪些依赖关系。 为了跟踪这一点,每次传递都可以声明在当前传递之前需要执行的传递集,以及当前传递失效的传递。 508 | 509 | 通常,此功能用于要求在运行传递之前计算分析结果。 运行任意转换过程可以使计算的分析结果无效,这是失效集指定的。 如果传递未实现 [getAnalysisUsage](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysisusage)方法,则默认为没有任何先决条件传递,并使所有其他传递无效。 510 | 511 | #### The getAnalysisUsage metho 512 | 513 | ```c++ 514 | virtual void getAnalysisUsage(AnalysisUsage &Info) const; 515 | ``` 516 | 517 | 通过实现getAnalysisUsage方法,可以为转换指定必需和无效的集合。 实现应该在 [AnalysisUsage](http://llvm.org/doxygen/classllvm_1_1AnalysisUsage.html)对象中填写有关哪些传递是必需的而不是无效的信息。 要执行此操作,传递可以在AnalysisUsage对象上调用以下任何方法: 518 | 519 | #### The AnalysisUsage::addRequired<> and AnalysisUsage::addRequiredTransitive<> methods 520 | 521 | 如果你的传球需要执行前一个传球(例如分析),它可以使用这些方法之一安排在传球之前运行。 LLVM有许多不同类型的分析和传递,可以满足从DominatorSet到BreakCriticalEdges的范围。 例如,要求BreakCriticalEdges保证在运行pass时CFG中没有关键边缘。 522 | 523 | 一些分析[chain](https://llvm.org/docs/AliasAnalysis.html#aliasanalysis-chaining) 到其他分析来完成它们的工作。 例如,需要`AliasAnalysis `实现链接到其他别名分析过程。 在分析链的情况下,应使用addRequiredTransitive方法而不是addRequired方法。 这通知PassManager,只要需要通过,传递所需的传递应该是活动的。 524 | 525 | #### The AnalysisUsage::addPreserved<> method 526 | 527 | PassManager的一项工作是优化分析的运行方式和时间。特别是,它试图避免重新计算数据,除非它需要。出于这个原因,允许传递声明它们保留(即,它们不会使现有分析无效),如果它可用的话。例如,简单的常量折叠传递不会修改CFG,因此它不可能影响支配者分析的结果。默认情况下,假定所有传递都使所有其他传递无效。 528 | 529 | AnalysisUsage类提供了几种在与addPreserved相关的特定情况下有用的方法。特别是,可以调用setPreservesAll方法来指示传递根本不修改LLVM程序(对于分析也是如此),并且setPreservesCFG方法可以由更改程序中的指令但不修改CFG或终止符指令(请注意,此属性是为[BasicBlockPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basicblockpass)隐式设置的)。 530 | 531 | addPreserved对于像BreakCriticalEdges这样的转换特别有用。这个过程知道如何更新一小组循环和支配者相关的分析(如果它们存在),所以它可以保留它们,尽管它会破坏CFG。 532 | 533 | #### Example implementations of getAnalysisUsage 534 | 535 | ```c++ 536 | // This example modifies the program, but does not modify the CFG 537 | void LICM::getAnalysisUsage(AnalysisUsage &AU) const { 538 | AU.setPreservesCFG(); 539 | AU.addRequired(); 540 | } 541 | ``` 542 | 543 | #### The getAnalysis<> and getAnalysisIfAvailable<> methods 544 | 545 | Pass :: getAnalysis <>方法由您的类自动继承,使您可以访问使用 [getAnalysisUsage](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysisusage)方法声明的通道。 它需要一个模板参数来指定所需的传递类,并返回对该传递的引用。 例如: 546 | 547 | class you want, and returns a reference to that pass. For example: 548 | 549 | ```c++ 550 | bool LICM::runOnFunction(Function &F) { 551 | LoopInfo &LI = getAnalysis().getLoopInfo(); 552 | //... 553 | } 554 | ``` 555 | 556 | 此方法调用返回对所需传递的引用。 如果您尝试获取未在[getAnalysisUsage](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysisusage)实现中声明的分析,则可能会导致运行时断言失败。 此方法可以由run *方法实现调用,也可以由run *方法调用的任何其他本地方法调用。 557 | 558 | 模块级别传递可以使用此接口使用功能级别分析信息。 例如: 559 | 560 | ```c++ 561 | bool ModuleLevelPass::runOnModule(Module &M) { 562 | //... 563 | DominatorTree &DT = getAnalysis(Func); 564 | //... 565 | } 566 | ``` 567 | 568 | 在上面的示例中,在返回对所需传递的引用之前,传递管理器调用runOnFunction for DominatorTree。 569 | 570 | 如果您的传递能够更新分析(如上所述),则可以使用getAnalysisIfAvailable方法,该方法返回指向分析的指针(如果它处于活动状态)。 例如: 571 | 572 | ``` 573 | if (DominatorSet *DS = getAnalysisIfAvailable()) { 574 | // A DominatorSet is active. This code will update it. 575 | } 576 | ``` 577 | 578 | ### Implementing Analysis Groups 579 | 580 | 现在我们已经了解了如何定义传球,如何使用它们以及如何从其他传球中获得传球的基础知识,现在是时候让它变得更有趣了。到目前为止,我们看到的所有传递关系都非常简单:一次传递依赖于另一个特定传递,在它可以运行之前运行。对于许多应用来说,这很好,对于其他应用,需要更大的灵活性。 581 | 582 | 特别是,定义了一些分析,使得分析结果只有一个简单的界面,但有多种计算方法。例如,考虑别名分析。最琐碎的别名分析为任何别名查询返回“may alias”。最复杂的分析是流量敏感的,上下文敏感的过程间分析,可能需要花费大量的时间来执行(显然,这两个极端之间有很大空间用于其他实现)。为了干净地支持这种情况,LLVM Pass Infrastructure支持分析组的概念。 583 | 584 | #### Analysis Group Concepts 585 | 586 | Analysis Group是一个简单的界面,可以通过多个不同的传递来实现。分析组可以像传球一样被赋予人类可读的名称,但与传递不同,它们不需要从Pass类派生。分析组可以具有一个或多个实现,其中之一是“默认”实现。 587 | 588 | 客户端传递使用分析组,就像其他传递一样:AnalysisUsage :: addRequired()和Pass :: getAnalysis()方法。为了解决此要求, [PassManager](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-passmanager) 会扫描可用的传递以查看是否有任何分析组的实现可用。如果没有,则为要使用的传递创建默认实现。 [interaction between passes](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-interaction) 的所有标准规则仍然适用。 589 | 590 | 虽然 [Pass Registration](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-registration)对于正常传递是可选的,但是必须注册所有分析组实现,并且必须使用 [INITIALIZE_AG_PASS](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-registeranalysisgroup)模板来加入实现池。此外,必须使用 [RegisterAnalysisGroup](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-registeranalysisgroup)注册接口的默认实现。 591 | 592 | 作为分析组的具体实例,请考虑 [AliasAnalysis](http://llvm.org/doxygen/classllvm_1_1AliasAnalysis.html)分析组。别名分析界面( [basicaa](http://llvm.org/doxygen/structBasicAliasAnalysis.html) pass)的默认实现只做了一些简单的检查,不需要进行大量的计算分析(例如:两个不同的全局变量永远不能互为别名等)。使用 [AliasAnalysis](http://llvm.org/doxygen/classllvm_1_1AliasAnalysis.html)接口的传递(例如 [gvn](http://llvm.org/doxygen/classllvm_1_1GVN.html))不关心实际提供别名分析的实现,它们只使用指定的接口。 593 | 594 | 从用户的角度来看,命令就像正常一样工作。发出命令opt -gvn ...将导致basicaa类被实例化并添加到传递序列中。发出命令opt -somefancyaa -gvn ...将导致gvn传递使用somefancyaa别名分析(实际上并不存在,它只是一个假设的例子)。 595 | 596 | #### Using RegisterAnalysisGroup 597 | 598 | RegisterAnalysisGroup模板用于注册分析组本身,而INITIALIZE_AG_PASS用于将传递实现添加到分析组。 首先,应该注册一个分析组,并为其提供一个人类可读的名称。 与传递注册不同,没有为分析组接口本身指定命令行参数,因为它是“抽象的”: 599 | 600 | ```C++ 601 | static RegisterAnalysisGroup A("Alias Analysis"); 602 | ``` 603 | 604 | 注册分析后,pass可以使用以下代码声明它们是接口的有效实现: 605 | 606 | ```c++ 607 | namespace { 608 | // Declare that we implement the AliasAnalysis interface 609 | INITIALIZE_AG_PASS(FancyAA, AliasAnalysis , "somefancyaa", 610 | "A more complex alias analysis implementation", 611 | false, // Is CFG Only? 612 | true, // Is Analysis? 613 | false); // Is default Analysis Group implementation? 614 | } 615 | ``` 616 | 617 | 这只显示了一个类FancyAA,它使用INITIALIZE_AG_PASS宏来注册和“加入”AliasAnalysis分析组。 分析组的每个实现都应该使用此宏加入。 618 | 619 | ```c++ 620 | namespace { 621 | // Declare that we implement the AliasAnalysis interface 622 | INITIALIZE_AG_PASS(BasicAA, AliasAnalysis, "basicaa", 623 | "Basic Alias Analysis (default AA impl)", 624 | false, // Is CFG Only? 625 | true, // Is Analysis? 626 | true); // Is default Analysis Group implementation? 627 | } 628 | ``` 629 | 630 | 这里我们展示如何指定默认实现(使用INITIALIZE_AG_PASS模板的最后一个参数)。 对于要使用的分析组,必须始终只有一个默认实现可用。 只有默认实现可以从ImmutablePass派生。 这里我们声明BasicAliasAnalysis传递是接口的默认实现。 631 | 632 | ## Pass Statistics 633 | 634 | [Statistic](http://llvm.org/doxygen/Statistic_8h_source.html)类旨在通过传递方式公开各种成功指标。 在命令行上启用[`-stats`](https://llvm.org/docs/CommandGuide/lli.html#cmdoption-stats)命令行选项时,将在运行结束时打印这些统计信息。 有关详细信息,请参阅“程序员手册”中的“统计”部分。 635 | 636 | ### What PassManager does 637 | 638 | [PassManager](http://llvm.org/doxygen/PassManager_8h_source.html) 类获取传递列表,确保正确设置其[prerequisites](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-interaction) ,然后调度传递以高效运行。所有运行传递的LLVM工具都使用PassManager来执行这些传递。 639 | 640 | PassManager做了两件主要的事情来尝试减少一系列传递的执行时间: 641 | 642 | - 分享分析结果。 PassManager尝试尽可能避免重新计算分析结果。这意味着要跟踪哪些分析已经可用,哪些分析失效,以及需要为通过运行哪些分析。工作的一个重要部分是PassManager跟踪所有分析结果的确切生命周期,允许它在不再需要时释放分配给保存分析结果的内存 [free memory](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-releasememory)。 643 | 644 | - 管道程序执行传递。 PassManager尝试通过将传递流水线化,从而在一系列传递中获得更好的缓存和内存使用行为。这意味着,给定一系列连续的[FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass),它将执行第一个函数上的所有[FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass),然后执行第二个函数上的所有[FunctionPass](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-functionpass)等等,直到整个程序运行完遍。 645 | 646 | 这改进了编译器的缓存行为,因为它一次只触及单个函数的LLVM程序表示,而不是遍历整个程序。它减少了编译器的内存消耗,因为,例如,一次只需要计算一个 [DominatorSet](http://llvm.org/doxygen/classllvm_1_1DominatorSet.html) 。这也使得将来可以实现一些 [interesting enhancements](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-smp) 功能。 647 | 648 | PassManager的有效性直接受到它所调度的传递行为的信息量的影响。例如,面对未实现的[getAnalysisUsage](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysisusage)方法,“保留”集合是故意保守的。如果不实施它将不会允许任何分析结果贯穿执行传递。 649 | 650 | PassManager类公开了一个--debug-pass命令行选项,这些选项对于调试传递执行,查看工作原理以及诊断何时应该保留比当前更多的分析非常有用。 (要获取有关--debug-pass选项的所有变体的信息,只需键入“opt -help-hidden”)。 651 | 652 | 例如,通过使用-debug-pass = Structure选项,我们可以看到 [Hello World](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basiccode)传递如何与其他传递进行交互。让我们尝试使用gvn和licm传递: 653 | 654 | ``` 655 | $ opt -load lib/LLVMHello.so -gvn -licm --debug-pass=Structure < hello.bc > /dev/null 656 | ModulePass Manager 657 | FunctionPass Manager 658 | Dominator Tree Construction 659 | Basic Alias Analysis (stateless AA impl) 660 | Function Alias Analysis Results 661 | Memory Dependence Analysis 662 | Global Value Numbering 663 | Natural Loop Information 664 | Canonicalize natural loops 665 | Loop-Closed SSA Form Pass 666 | Basic Alias Analysis (stateless AA impl) 667 | Function Alias Analysis Results 668 | Scalar Evolution Analysis 669 | Loop Pass Manager 670 | Loop Invariant Code Motion 671 | Module Verifier 672 | Bitcode Writer 673 | ``` 674 | 675 | 此输出显示构建通道的时间。 在这里,我们看到GVN使用支配树信息来完成它的工作。 LICM传递使用自然循环信息,它也使用支配树。 676 | 677 | 在LICM传递之后,模块验证程序运行(由opt工具自动添加),它使用支配树来检查生成的LLVM代码是否格式正确。 注意,支配树计算一次,并由三遍共享。 678 | 679 | 让我们看看当我们在两次传递之间运行 [Hello World](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basiccode)传递时这会如何变化: 680 | 681 | ``` 682 | $ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null 683 | ModulePass Manager 684 | FunctionPass Manager 685 | Dominator Tree Construction 686 | Basic Alias Analysis (stateless AA impl) 687 | Function Alias Analysis Results 688 | Memory Dependence Analysis 689 | Global Value Numbering 690 | Hello World Pass 691 | Dominator Tree Construction 692 | Natural Loop Information 693 | Canonicalize natural loops 694 | Loop-Closed SSA Form Pass 695 | Basic Alias Analysis (stateless AA impl) 696 | Function Alias Analysis Results 697 | Scalar Evolution Analysis 698 | Loop Pass Manager 699 | Loop Invariant Code Motion 700 | Module Verifier 701 | Bitcode Writer 702 | Hello: __main 703 | Hello: puts 704 | Hello: main 705 | ``` 706 | 707 | 在这里,我们看到 [Hello World](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basiccode)传递已经杀死了Dominator Tree传递,即使它根本不修改代码! 要解决此问题,我们需要在pass中添加以下 [getAnalysisUsage](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysisusage)方法: 708 | 709 | ``` 710 | // We don't modify the program, so we preserve all analyses 711 | void getAnalysisUsage(AnalysisUsage &AU) const override { 712 | AU.setPreservesAll(); 713 | } 714 | ``` 715 | 716 | 现在当我们运行pass时,我们得到这个输出: 717 | 718 | ``` 719 | $ opt -load lib/LLVMHello.so -gvn -hello -licm --debug-pass=Structure < hello.bc > /dev/null 720 | Pass Arguments: -gvn -hello -licm 721 | ModulePass Manager 722 | FunctionPass Manager 723 | Dominator Tree Construction 724 | Basic Alias Analysis (stateless AA impl) 725 | Function Alias Analysis Results 726 | Memory Dependence Analysis 727 | Global Value Numbering 728 | Hello World Pass 729 | Natural Loop Information 730 | Canonicalize natural loops 731 | Loop-Closed SSA Form Pass 732 | Basic Alias Analysis (stateless AA impl) 733 | Function Alias Analysis Results 734 | Scalar Evolution Analysis 735 | Loop Pass Manager 736 | Loop Invariant Code Motion 737 | Module Verifier 738 | Bitcode Writer 739 | Hello: __main 740 | Hello: puts 741 | Hello: main 742 | ``` 743 | 744 | 这表明我们不会意外地使支配者信息无效,因此不必计算两次。 745 | 746 | #### The releaseMemory method 747 | 748 | ```c++ 749 | virtual void releaseMemory(); 750 | ``` 751 | 752 | PassManager会自动确定何时计算分析结果,以及保留它们的时间。 因为传递对象本身的生命周期实际上是编译过程的整个持续时间,所以当它们不再有用时,我们需要一些方法来释放分析结果。 releaseMemory虚拟方法是执行此操作的方法。 753 | 754 | 如果您正在编写分析或任何其他保留大量状态的传递(供另一个“需要”传递并使用[getAnalysis](https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-getanalysis) 方法的pass),您应该实现releaseMemory,以便释放分配的内存来维护 内部状态。 在传递中下一次调用run *之前,在类的run *方法之后调用此方法。 755 | 756 | ## Registering dynamically loaded passes 757 | 758 | 在使用LLVM构建生产质量工具时,大小很重要,既用于分发,也用于在目标系统上运行时调整驻留代码大小。因此,期望选择性地使用一些通道,同时省略其他通道并保持稍后改变配置的灵活性。您希望能够完成所有这些,并向用户提供反馈。这是通行证登记发挥作用的地方。 759 | 760 | 传递注册的基本机制是MachinePassRegistry类和MachinePassRegistryNode的子类。 761 | 762 | MachinePassRegistry的实例用于维护MachinePassRegistryNode对象的列表。此实例维护列表并向命令行界面传达添加和删除。 763 | 764 | MachinePassRegistryNode子类的实例用于维护有关特定传递的信息。此信息包括命令行名称,命令帮助字符串以及用于创建传递实例的函数的地址。其中一个实例的全局静态构造函数向对应的MachinePassRegistry注册,静态析构函数取消注册。因此,在工具中静态链接的传递将在启动时注册。动态加载的传递将在加载时注册,并在卸载时注销。 765 | 766 | ### Using existing registries 767 | 768 | 有预定义的注册表来跟踪指令调度(RegisterScheduler)和寄存器分配(RegisterRegAlloc)机器通过。 这里我们将描述如何注册寄存器分配器机器通过。 769 | 770 | 实现你的寄存器分配器机器通行证。 在您的register allocator .cpp文件中添加以下include: 771 | 772 | ``` 773 | #include "llvm/CodeGen/RegAllocRegistry.h" 774 | ``` 775 | 776 | 同样在您的register allocator .cpp文件中,以下列形式定义创建者函数: 777 | 778 | ``` 779 | FunctionPass *createMyRegisterAllocator() { 780 | return new MyRegisterAllocator(); 781 | } 782 | ``` 783 | 784 | 请注意,此函数的签名应与RegisterRegAlloc :: FunctionPassCtor的类型匹配。 在同一个文件中添加“安装”声明,格式如下: 785 | 786 | ``` 787 | static RegisterRegAlloc myRegAlloc("myregalloc", 788 | "my register allocator help string", 789 | createMyRegisterAllocator); 790 | ``` 791 | 792 | 请注意,帮助字符串之前的两个空格在 [`-help`](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-help)查询上产生了整洁的结果。 793 | 794 | ``` 795 | $ llc -help 796 | ... 797 | -regalloc - Register allocator to use (default=linearscan) 798 | =linearscan - linear scan register allocator 799 | =local - local register allocator 800 | =simple - simple register allocator 801 | =myregalloc - my register allocator help string 802 | ... 803 | ``` 804 | 805 | 就是这样。 用户现在可以自由使用-regalloc = myregalloc作为选项。 除了使用RegisterScheduler类之外,注册指令调度程序是类似的。 请注意,RegisterScheduler :: FunctionPassCtor与RegisterRegAlloc :: FunctionPassCtor明显不同。 806 | 807 | 要强制将寄存器分配器加载/链接到llc / lli工具,请将创建者函数的全局声明添加到Passes.h,并将“伪”调用行添加到llvm / Codegen / LinkAllCodegenComponents.h。 808 | 809 | ### Creating new registries 810 | 811 | 最简单的入门方法是克隆一个现有的注册表; 我们推荐llvm / CodeGen / RegAllocRegistry.h。 要修改的关键是类名和FunctionPassCtor类型。 812 | 813 | 然后你需要声明注册表。 示例:如果您的pass注册表是RegisterMyPasses,则定义: 814 | 815 | ```c++ 816 | MachinePassRegistry RegisterMyPasses::Registry; 817 | ``` 818 | 819 | 最后,为你的传递声明命令行选项。 例: 820 | 821 | ``` 822 | cl::opt > 824 | MyPassOpt("mypass", 825 | cl::init(&createDefaultMyPass), 826 | cl::desc("my pass option help")); 827 | ``` 828 | 829 | 这里的命令选项是“mypass”,createDefaultMyPass是默认创建者。 830 | 831 | ### Using GDB with dynamically loaded passes 832 | 833 | 不幸的是,使用带有动态加载传递的GDB并不像应该的那样容易。 首先,您不能在尚未加载的共享对象中设置断点,其次在共享对象中存在内联函数的问题。 以下是使用GDB调试传递的一些建议。 834 | 835 | 为了便于讨论,我将假设您正在调试由opt调用的转换,尽管此处描述的内容不依赖于此。 836 | 837 | #### Setting a breakpoint in your pass 838 | 839 | 你要做的第一件事就是在opt过程中启动gdb: 840 | 841 | ``` 842 | gdb opt 843 | GNU gdb 5.0 844 | Copyright 2000 Free Software Foundation, Inc. 845 | GDB is free software, covered by the GNU General Public License, and you are 846 | welcome to change it and/or distribute copies of it under certain conditions. 847 | Type "show copying" to see the conditions. 848 | There is absolutely no warranty for GDB. Type "show warranty" for details. 849 | This GDB was configured as "sparc-sun-solaris2.6"... 850 | (gdb) 851 | ``` 852 | 853 | 请注意,opt中包含大量调试信息,因此加载需要时间。 耐心点。 由于我们无法在传递中设置断点(共享对象直到运行时才加载),我们必须执行该过程,并在它调用我们的传递之前停止它,但是在它加载了共享对象之后。 最简单的方法是在PassManager :: run中设置断点,然后使用您想要的参数运行该进程: 854 | 855 | ``` 856 | $ (gdb) break llvm::PassManager::run 857 | Breakpoint 1 at 0x2413bc: file Pass.cpp, line 70. 858 | (gdb) run test.bc -load $(LLVMTOP)/llvm/Debug+Asserts/lib/[libname].so -[passoption] 859 | Starting program: opt test.bc -load $(LLVMTOP)/llvm/Debug+Asserts/lib/[libname].so -[passoption] 860 | Breakpoint 1, PassManager::run (this=0xffbef174, M=@0x70b298) at Pass.cpp:70 861 | 70 bool PassManager::run(Module &M) { return PM->run(M); } 862 | (gdb) 863 | ``` 864 | 865 | 一旦opt在PassManager :: run方法中停止,您现在可以在传递中自由设置断点,以便您可以跟踪执行或执行其他标准调试。 866 | 867 | #### Miscellaneous Problems 868 | 869 | 一旦掌握了基础知识,GDB就会遇到一些问题,一些是解决方案,一些是没有解决方案。 870 | 871 | 内联函数具有伪造的堆栈信息。通常,GDB在获取堆栈跟踪和单步执行内联函数方面做得非常好。但是,当动态加载传递时,它会以某种方式完全失去此功能。我所知道的唯一解决方案是取消内联函数(将其从类的主体移动到.cpp文件)。 872 | 重新启动程序会破坏断点。按照上述信息后,您已成功获得通行证中的一些断点。接下来你知道,你重新启动程序(即你再次键入“run”),然后开始得到关于断点不可设置的错误。我发现“修复”此问题的唯一方法是删除已在传递中设置的断点,运行程序,并在PassManager :: run中执行停止后重新设置断点。 873 | 希望这些技巧可以帮助解决常见的案例调试问题。如果您想提供自己的一些提示,请联系 [Chris](mailto:sabre%40nondot.org)。 874 | 875 | ### Future extensions planned 876 | 877 | 尽管LLVM Pass基础设施非常强大,并且做了一些漂亮的东西,但我们希望将来添加一些东西。 这是我们要去的地方: 878 | 879 | #### Multithreaded LLVM 880 | 881 | 多CPU机器变得越来越普遍,编译永远不够快:显然我们应该允许多线程编译器。 由于为上面的传递定义了语义(特别是它们不能在其run *方法的调用中维护状态),实现多线程编译器的一种很好的干净方法是让PassManager类创建每个传递对象的多个实例,并允许 单独的实例同时攻击程序的不同部分。 882 | 883 | 此实现将阻止每个传递必须实现多线程构造,只需要LLVM核心在几个位置(对于全局资源)具有锁定。 虽然这是一个简单的扩展,但我们根本没有时间(或多处理器机器,因此有理由)来实现它。 尽管如此,我们仍然保持LLVM准备好SMP,你也应该这样做。 -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/InstallTime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/InstallTime.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/LLVMCompiler1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/LLVMCompiler1.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/LTO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/LTO.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/PassLinkage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/PassLinkage.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/RetargetableCompiler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/RetargetableCompiler.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/SimpleCompiler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/SimpleCompiler.png -------------------------------------------------------------------------------- /doc/image/Intro to LLVM/X86Target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/Intro to LLVM/X86Target.png -------------------------------------------------------------------------------- /doc/image/SSA/SSA_example1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/SSA/SSA_example1.1.png -------------------------------------------------------------------------------- /doc/image/SSA/SSA_example1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/SSA/SSA_example1.2.png -------------------------------------------------------------------------------- /doc/image/SSA/SSA_example1.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/doc/image/SSA/SSA_example1.3.png -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Kaleidoscope_tutorial) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(llvm_tutorial) 2 | set_target_properties(llvm_tutorial PROPERTIES FOLDER Examples) 3 | 4 | 5 | macro(add_kaleidoscope_chapter name) 6 | add_dependencies(llvm_tutorial ${name}) 7 | add_llvm_example(${name} ${ARGN}) 8 | endmacro(add_kaleidoscope_chapter name) 9 | 10 | add_subdirectory(src/BuildingAJIT) 11 | add_subdirectory(src/Chapter02) 12 | add_subdirectory(src/Chapter03) 13 | add_subdirectory(src/Chapter04) 14 | add_subdirectory(src/Chapter05) 15 | add_subdirectory(src/Chapter06) 16 | add_subdirectory(src/Chapter07) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/include/KaleidoscopeJIT.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 2 | #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 3 | 4 | #include "llvm/ADT/STLExtras.h" 5 | #include "llvm/ADT/iterator_range.h" 6 | #include "llvm/ExecutionEngine/ExecutionEngine.h" 7 | #include "llvm/ExecutionEngine/JITSymbol.h" 8 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 9 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 10 | #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" 11 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 12 | #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" 13 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" 14 | #include "llvm/IR/DataLayout.h" 15 | #include "llvm/IR/Mangler.h" 16 | #include "llvm/Support/DynamicLibrary.h" 17 | #include "llvm/Support/raw_ostream.h" 18 | #include "llvm/Target/TargetMachine.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace llvm { 26 | namespace orc { 27 | 28 | class KaleidoscopeJIT { 29 | public: 30 | using ObjLayerT = RTDyldObjectLinkingLayer; 31 | using CompileLayerT = IRCompileLayer; 32 | 33 | KaleidoscopeJIT() 34 | : Resolver(createLegacyLookupResolver( 35 | ES, 36 | [this](const std::string &Name) { 37 | return ObjectLayer.findSymbol(Name, true); 38 | }, 39 | [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), 40 | 41 | TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), 42 | ObjectLayer(ES, 43 | [this](VModuleKey) { 44 | return ObjLayerT::Resources{ 45 | std::make_shared(), Resolver}; 46 | }), 47 | CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { 48 | llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 49 | } 50 | 51 | TargetMachine &getTargetMachine() { return *TM; } 52 | 53 | VModuleKey addModule(std::unique_ptr M) { 54 | auto K = ES.allocateVModule(); 55 | cantFail(CompileLayer.addModule(K, std::move(M))); 56 | ModuleKeys.push_back(K); 57 | return K; 58 | } 59 | 60 | void removeModule(VModuleKey K) { 61 | ModuleKeys.erase(find(ModuleKeys, K)); 62 | cantFail(CompileLayer.removeModule(K)); 63 | } 64 | 65 | JITSymbol findSymbol(const std::string Name) { 66 | return findMangledSymbol(mangle(Name)); 67 | } 68 | 69 | private: 70 | std::string mangle(const std::string &Name) { 71 | std::string MangledName; 72 | { 73 | raw_string_ostream MangledNameStream(MangledName); 74 | Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 75 | } 76 | return MangledName; 77 | } 78 | 79 | JITSymbol findMangledSymbol(const std::string &Name) { 80 | #ifdef _WIN32 81 | // The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported 82 | // flag to decide whether a symbol will be visible or not, when we call 83 | // IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true. 84 | // 85 | // But for Windows COFF objects, this flag is currently never set. 86 | // For a potential solution see: https://reviews.llvm.org/rL258665 87 | // For now, we allow non-exported symbols on Windows as a workaround. 88 | const bool ExportedSymbolsOnly = false; 89 | #else 90 | const bool ExportedSymbolsOnly = true; 91 | #endif 92 | 93 | // Search modules in reverse order: from last added to first added. 94 | // This is the opposite of the usual search order for dlsym, but makes more 95 | // sense in a REPL where we want to bind to the newest available definition. 96 | for (auto H : make_range(ModuleKeys.rbegin(), ModuleKeys.rend())) 97 | if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly)) 98 | return Sym; 99 | 100 | // If we can't find the symbol in the JIT, try looking in the host process. 101 | if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name)) 102 | return JITSymbol(SymAddr, JITSymbolFlags::Exported); 103 | 104 | #ifdef _WIN32 105 | // For Windows retry without "_" at beginning, as RTDyldMemoryManager uses 106 | // GetProcAddress and standard libraries like msvcrt.dll use names 107 | // with and without "_" (for example "_itoa" but "sin"). 108 | if (Name.length() > 2 && Name[0] == '_') 109 | if (auto SymAddr = 110 | RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1))) 111 | return JITSymbol(SymAddr, JITSymbolFlags::Exported); 112 | #endif 113 | 114 | return nullptr; 115 | } 116 | 117 | ExecutionSession ES; 118 | std::shared_ptr Resolver; 119 | std::unique_ptr TM; 120 | const DataLayout DL; 121 | ObjLayerT ObjectLayer; 122 | CompileLayerT CompileLayer; 123 | std::vector ModuleKeys; 124 | }; 125 | 126 | } // end namespace orc 127 | } // end namespace llvm 128 | 129 | #endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/BuildingAJIT/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Chapter01) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/BuildingAJIT/Chapter01/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Analysis 3 | Core 4 | ExecutionEngine 5 | InstCombine 6 | Object 7 | OrcJIT 8 | RuntimeDyld 9 | ScalarOpts 10 | Support 11 | native 12 | ) 13 | add_kaleidoscope_chapter(BuildingAJIT-Ch1 toy.cpp) 14 | export_executable_symbols(BuildingAJIT-Ch1) 15 | -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/BuildingAJIT/Chapter01/KaleidoscopeJIT.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cyoung on 18-9-10. 3 | // 4 | 5 | #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 6 | #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 7 | 8 | #include "llvm/ADT/STLExtras.h" 9 | #include "llvm/ExecutionEngine/ExecutionEngine.h" 10 | #include "llvm/ExecutionEngine/JITSymbol.h" 11 | #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" 12 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" 13 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 14 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 15 | #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" 16 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 17 | #include "llvm/IR/DataLayout.h" 18 | #include "llvm/IR/Mangler.h" 19 | #include "llvm/Support/DynamicLibrary.h" 20 | #include "llvm/Support/raw_ostream.h" 21 | #include "llvm/Target/TargetMachine.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace llvm { 28 | namespace orc { 29 | 30 | class KaleidoscopeJIT { 31 | private: 32 | ExecutionSession ES; 33 | std::shared_ptr Resolver; 34 | std::unique_ptr TM; 35 | const DataLayout DL; 36 | RTDyldObjectLinkingLayer ObjectLayer; 37 | IRCompileLayer CompileLayer; 38 | 39 | public: 40 | KaleidoscopeJIT() 41 | : Resolver(createLegacyLookupResolver( 42 | ES, 43 | [this](const std::string &Name) -> JITSymbol { 44 | if (auto Sym = CompileLayer.findSymbol(Name, false)) 45 | return Sym; 46 | else if (auto Err = Sym.takeError()) 47 | return std::move(Err); 48 | if (auto SymAddr = 49 | RTDyldMemoryManager::getSymbolAddressInProcess(Name)) 50 | return JITSymbol(SymAddr, JITSymbolFlags::Exported); 51 | return nullptr; 52 | }, 53 | [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), 54 | TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), 55 | ObjectLayer(ES, 56 | [this](VModuleKey) { 57 | return RTDyldObjectLinkingLayer::Resources{ 58 | std::make_shared(), Resolver}; 59 | }), 60 | CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { 61 | llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 62 | } 63 | 64 | TargetMachine &getTargetMachine() { return *TM; } 65 | 66 | VModuleKey addModule(std::unique_ptr M) { 67 | // Add the module to the JIT with a new VModuleKey. 68 | auto K = ES.allocateVModule(); 69 | cantFail(CompileLayer.addModule(K, std::move(M))); 70 | return K; 71 | } 72 | 73 | JITSymbol findSymbol(const std::string Name) { 74 | std::string MangledName; 75 | raw_string_ostream MangledNameStream(MangledName); 76 | Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 77 | return CompileLayer.findSymbol(MangledNameStream.str(), true); 78 | } 79 | 80 | JITTargetAddress getSymbolAddress(const std::string Name) { 81 | return cantFail(findSymbol(Name).getAddress()); 82 | } 83 | 84 | void removeModule(VModuleKey K) { 85 | cantFail(CompileLayer.removeModule(K)); 86 | } 87 | }; 88 | 89 | } // end namespace orc 90 | } // end namespace llvm 91 | 92 | #endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter02/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS Support) 2 | 3 | add_kaleidoscope_chapter(Kaleidoscope-Ch2 toy.cpp) 4 | export_executable_symbols(Kaleidoscope-Ch2) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter02/toy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cyoung on 18-9-11. 3 | // 4 | 5 | #include "llvm/ADT/STLExtras.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | //===----------------------------------------------------------------------===// 16 | // Lexer 17 | //===----------------------------------------------------------------------===// 18 | 19 | // The lexer(词法分析器) returns tokens [0-255] if it is an unknown character, otherwise one 20 | // of these for known things. 21 | enum Token { 22 | tok_eof = -1, 23 | 24 | // command 25 | tok_def = -2, 26 | tok_extern = -3, 27 | 28 | // primary 29 | //标识符:自定义的变量名或函数名 30 | tok_identifier = -4, 31 | tok_number = -5 32 | }; 33 | 34 | 35 | // 保存标识符名称 36 | static std::string IdentifierStr; // Filled in if tok_identifier 37 | //保存其值 38 | static double NumVal; // Filled in if tok_number 39 | 40 | /// gettok - Return the next token from standard input. 41 | //词法分析器的实际实现 42 | static int gettok() { 43 | //读取但未处理 44 | static int LastChar = ' '; 45 | 46 | // Skip any whitespace. 47 | while (isspace(LastChar)) 48 | LastChar = getchar(); 49 | //标识符:自定义变量名,函数名或者关键字 50 | if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* 51 | IdentifierStr = LastChar; 52 | while (isalnum((LastChar = getchar()))) 53 | IdentifierStr += LastChar; 54 | // 55 | if (IdentifierStr == "def") 56 | return tok_def; 57 | if (IdentifierStr == "extern") 58 | return tok_extern; 59 | return tok_identifier; 60 | } 61 | 62 | if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ 63 | std::string NumStr; 64 | do { 65 | NumStr += LastChar; 66 | LastChar = getchar(); 67 | } while (isdigit(LastChar) || LastChar == '.'); 68 | 69 | NumVal = strtod(NumStr.c_str(), nullptr); 70 | return tok_number; 71 | } 72 | 73 | //忽略掉注释行,找到下一个需要解析的标识符 74 | if (LastChar == '#') { 75 | // Comment until end of line. 76 | do 77 | LastChar = getchar(); 78 | while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); 79 | 80 | // 继续解析下一行文本 81 | if (LastChar != EOF) 82 | return gettok(); 83 | } 84 | 85 | // Check for end of file. Don't eat the EOF. 86 | if (LastChar == EOF) 87 | return tok_eof; 88 | 89 | // Otherwise, just return the character as its ascii value. 90 | int ThisChar = LastChar; 91 | LastChar = getchar(); 92 | return ThisChar; 93 | } 94 | 95 | //===----------------------------------------------------------------------===// 96 | // Abstract Syntax Tree (aka Parse Tree) 97 | //===----------------------------------------------------------------------===// 98 | 99 | namespace { 100 | 101 | /// ExprAST - Base class for all expression nodes. 102 | class ExprAST { 103 | public: 104 | virtual ~ExprAST() = default; 105 | }; 106 | 107 | /// NumberExprAST - Expression class for numeric literals like "1.0". 108 | class NumberExprAST : public ExprAST { 109 | double Val; 110 | 111 | public: 112 | explicit NumberExprAST(double Val) : Val(Val) {} 113 | }; 114 | 115 | /// VariableExprAST - Expression class for referencing a variable, like "a". 116 | class VariableExprAST : public ExprAST { 117 | std::string Name; 118 | 119 | public: 120 | explicit VariableExprAST(const std::string &Name) : Name(Name) {} 121 | }; 122 | 123 | /// BinaryExprAST - Expression class for a binary operator. 124 | class BinaryExprAST : public ExprAST { 125 | char Op; 126 | std::unique_ptr LHS, RHS; 127 | 128 | public: 129 | BinaryExprAST(char Op, std::unique_ptr LHS, 130 | std::unique_ptr RHS) 131 | : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} 132 | }; 133 | 134 | /// CallExprAST - Expression class for function calls. 135 | class CallExprAST : public ExprAST { 136 | std::string Callee; 137 | std::vector> Args; 138 | 139 | public: 140 | CallExprAST(std::string Callee, 141 | std::vector> Args) 142 | : Callee(std::move(Callee)), Args(std::move(Args)) {} 143 | }; 144 | 145 | /// PrototypeAST - This class represents the "prototype" for a function, 146 | /// which captures its name, and its argument names (thus implicitly the number 147 | /// of arguments the function takes). 148 | ///函数声明 149 | class PrototypeAST { 150 | //函数名 151 | std::string Name; 152 | //vector的长度就是参数数量 153 | std::vector Args; 154 | 155 | public: 156 | PrototypeAST(std::string Name, std::vector Args) 157 | : Name(std::move(Name)), Args(std::move(Args)) {} 158 | 159 | const std::string &getName() const { return Name; } 160 | }; 161 | 162 | /// FunctionAST - This class represents a function definition itself. 163 | ///函数定义 164 | class FunctionAST { 165 | //函数名 166 | std::unique_ptr Proto; 167 | //函数体 168 | std::unique_ptr Body; 169 | 170 | public: 171 | FunctionAST(std::unique_ptr Proto, 172 | std::unique_ptr Body) 173 | : Proto(std::move(Proto)), Body(std::move(Body)) {} 174 | }; 175 | 176 | } // end anonymous namespace 177 | 178 | //===----------------------------------------------------------------------===// 179 | // Parser,解析部分 180 | //===----------------------------------------------------------------------===// 181 | 182 | /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current 183 | /// token the parser is looking at. getNextToken reads another token from the 184 | /// lexer and updates CurTok with its results. 185 | //解析器当前所解析的标识符类型 186 | static int CurTok; 187 | static int getNextToken() { return CurTok = gettok(); } 188 | 189 | /// BinopPrecedence - This holds the precedence for each binary operator that is 190 | /// defined. 191 | ///定义二元操作符的优先级 192 | static std::map BinopPrecedence; 193 | 194 | /// GetTokPrecedence - Get the precedence of the pending binary operator token. 195 | static int GetTokPrecedence() { 196 | if (!isascii(CurTok)) 197 | return -1; 198 | 199 | // Make sure it's a declared binop. 200 | int TokPrec = BinopPrecedence[CurTok]; 201 | if (TokPrec <= 0) 202 | return -1; 203 | return TokPrec; 204 | } 205 | 206 | /// LogError* - These are little helper functions for error handling. 207 | std::unique_ptr LogError(const char *Str) { 208 | fprintf(stderr, "Error: %s\n", Str); 209 | return nullptr; 210 | } 211 | std::unique_ptr LogErrorP(const char *Str) { 212 | LogError(Str); 213 | return nullptr; 214 | } 215 | 216 | static std::unique_ptr ParseExpression(); 217 | 218 | /// numberexpr ::= number 219 | static std::unique_ptr ParseNumberExpr() { 220 | //创建一个数值节点 221 | auto Result = llvm::make_unique(NumVal); 222 | //词法解析器前进到下一个字符 223 | getNextToken(); // consume the number 224 | return std::move(Result); 225 | } 226 | 227 | /// parenexpr ::= '(' expression ')' 228 | static std::unique_ptr ParseParenExpr() { 229 | //吃掉(,移向括号右边的下一个字符 230 | getNextToken(); // eat (. 231 | auto V = ParseExpression(); 232 | if (!V) 233 | return nullptr; 234 | 235 | if (CurTok != ')') 236 | return LogError("expected ')'"); 237 | getNextToken(); // eat ). 238 | return V; 239 | } 240 | 241 | /// identifierexpr 242 | /// ::= identifier 243 | /// ::= identifier '(' expression* ')' 244 | ///处理标识符 245 | static std::unique_ptr ParseIdentifierExpr() { 246 | std::string IdName = IdentifierStr; 247 | 248 | getNextToken(); // eat identifier. 249 | 250 | //如果后边不带(,则认为是一个单独变量,否则认为是一个函数名 251 | if (CurTok != '(') // Simple variable ref. 252 | return llvm::make_unique(IdName); 253 | 254 | // Call.函数名 255 | getNextToken(); // eat ( 256 | //解析函数参数 257 | std::vector> Args; 258 | if (CurTok != ')') { 259 | while (true) { 260 | if (auto Arg = ParseExpression()) 261 | Args.push_back(std::move(Arg)); 262 | else 263 | return nullptr; 264 | 265 | if (CurTok == ')') 266 | break; 267 | 268 | if (CurTok != ',') 269 | return LogError("Expected ')' or ',' in argument list"); 270 | getNextToken(); 271 | } 272 | } 273 | 274 | // Eat the ')'. 275 | getNextToken(); 276 | 277 | return llvm::make_unique(IdName, std::move(Args)); 278 | } 279 | 280 | /// primary 281 | /// ::= identifierexpr 282 | /// ::= numberexpr 283 | /// ::= parenexpr 284 | ///主表达式 285 | static std::unique_ptr ParsePrimary() { 286 | //有了curTok:可以采用预测的方式检查后面表达式的类型 287 | switch (CurTok) { 288 | default: 289 | return LogError("unknown token when expecting an expression"); 290 | case tok_identifier: 291 | return ParseIdentifierExpr(); 292 | case tok_number: 293 | return ParseNumberExpr(); 294 | case '(': 295 | return ParseParenExpr(); 296 | } 297 | } 298 | 299 | /// binoprhs 300 | /// ::= ('+' primary)* 301 | ///处理二元表达式对序,这个程序好好理解 302 | static std::unique_ptr ParseBinOpRHS(int ExprPrec, 303 | std::unique_ptr LHS) { 304 | // If this is a binop, find its precedence(优先级). 305 | //可以一直重复合并 306 | while (true) { 307 | int TokPrec = GetTokPrecedence(); 308 | 309 | // If this is a binop that binds at least as tightly as the current binop, 310 | // consume it, otherwise we are done. 311 | if (TokPrec < ExprPrec) 312 | return LHS; 313 | 314 | // Okay, we know this is a binop. 315 | int BinOp = CurTok; 316 | getNextToken(); // eat binop 317 | 318 | // Parse the primary expression after the binary operator. 319 | //所有标识符被解析之后均会被吃掉,curTok移向下一个待被解析的标识符 320 | auto RHS = ParsePrimary(); 321 | if (!RHS) 322 | return nullptr; 323 | 324 | // If BinOp binds less tightly with RHS than the operator after RHS, let 325 | // the pending operator take RHS as its LHS. 326 | int NextPrec = GetTokPrecedence(); 327 | if (TokPrec < NextPrec) { 328 | RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); 329 | if (!RHS) 330 | return nullptr; 331 | } 332 | 333 | // Merge LHS/RHS. 334 | LHS = llvm::make_unique(BinOp, std::move(LHS), 335 | std::move(RHS)); 336 | } 337 | } 338 | 339 | /// expression 340 | /// ::= primary binoprhs 341 | ///解析二元表达式 342 | static std::unique_ptr ParseExpression() { 343 | auto LHS = ParsePrimary(); 344 | if (!LHS) 345 | return nullptr; 346 | //0:目前表达式的优先级 347 | return ParseBinOpRHS(0, std::move(LHS)); 348 | } 349 | 350 | /// prototype 351 | /// ::= id '(' id* ')' 352 | static std::unique_ptr ParsePrototype() { 353 | if (CurTok != tok_identifier) 354 | return LogErrorP("Expected function name in prototype"); 355 | 356 | std::string FnName = IdentifierStr; 357 | getNextToken(); 358 | 359 | if (CurTok != '(') 360 | return LogErrorP("Expected '(' in prototype"); 361 | 362 | std::vector ArgNames; 363 | while (getNextToken() == tok_identifier) 364 | ArgNames.push_back(IdentifierStr); 365 | if (CurTok != ')') 366 | return LogErrorP("Expected ')' in prototype"); 367 | 368 | // success. 369 | getNextToken(); // eat ')'. 370 | 371 | return llvm::make_unique(FnName, std::move(ArgNames)); 372 | } 373 | 374 | /// definition ::= 'def' prototype expression 375 | static std::unique_ptr ParseDefinition() { 376 | getNextToken(); // eat def. 377 | auto Proto = ParsePrototype(); 378 | if (!Proto) 379 | return nullptr; 380 | //现在函数仅仅包含了表达式 381 | if (auto E = ParseExpression()) 382 | return llvm::make_unique(std::move(Proto), std::move(E)); 383 | return nullptr; 384 | } 385 | 386 | /// toplevelexpr ::= expression 387 | static std::unique_ptr ParseTopLevelExpr() { 388 | if (auto E = ParseExpression()) { 389 | // Make an anonymous proto. 390 | auto Proto = llvm::make_unique("__anon_expr", 391 | std::vector()); 392 | return llvm::make_unique(std::move(Proto), std::move(E)); 393 | } 394 | return nullptr; 395 | } 396 | 397 | /// external ::= 'extern' prototype 398 | static std::unique_ptr ParseExtern() { 399 | getNextToken(); // eat extern. 400 | return ParsePrototype(); 401 | } 402 | 403 | //===----------------------------------------------------------------------===// 404 | // Top-Level parsing 405 | //===----------------------------------------------------------------------===// 406 | 407 | static void HandleDefinition() { 408 | if (ParseDefinition()) { 409 | fprintf(stderr, "Parsed a function definition.\n"); 410 | } else { 411 | // Skip token for error recovery. 412 | getNextToken(); 413 | } 414 | } 415 | 416 | static void HandleExtern() { 417 | if (ParseExtern()) { 418 | fprintf(stderr, "Parsed an extern\n"); 419 | } else { 420 | // Skip token for error recovery. 421 | getNextToken(); 422 | } 423 | } 424 | 425 | static void HandleTopLevelExpression() { 426 | // Evaluate a top-level expression into an anonymous function. 427 | if (ParseTopLevelExpr()) { 428 | fprintf(stderr, "Parsed a top-level expr\n"); 429 | } else { 430 | // Skip token for error recovery. 431 | getNextToken(); 432 | } 433 | } 434 | 435 | /// top ::= definition | external | expression | ';' 436 | ///驱动小程序 437 | static void MainLoop() { 438 | while (true) { 439 | fprintf(stderr, "ready> "); 440 | switch (CurTok) { 441 | case tok_eof: 442 | return; 443 | case ';': // ignore top-level semicolons. 444 | getNextToken(); 445 | break; 446 | case tok_def: 447 | HandleDefinition(); 448 | break; 449 | case tok_extern: 450 | HandleExtern(); 451 | break; 452 | default: 453 | HandleTopLevelExpression(); 454 | break; 455 | } 456 | } 457 | } 458 | 459 | //===----------------------------------------------------------------------===// 460 | // Main driver code. 461 | //===----------------------------------------------------------------------===// 462 | 463 | int main() { 464 | // Install standard binary operators. 465 | // 1 is lowest precedence. 466 | BinopPrecedence['<'] = 10; 467 | BinopPrecedence['+'] = 20; 468 | BinopPrecedence['-'] = 20; 469 | BinopPrecedence['*'] = 40; // highest. 470 | 471 | // Prime the first token. 472 | fprintf(stderr, "ready> "); 473 | getNextToken(); 474 | 475 | // Run the main "interpreter loop" now. 476 | MainLoop(); 477 | 478 | return 0; 479 | } -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter03/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS Analysis 2 | Core 3 | Support 4 | ) 5 | 6 | add_kaleidoscope_chapter(Kaleidoscope-Ch3 toy.cpp) 7 | #export_executable_symbols(Kaleidoscope-Ch3) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter03/toy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cyoung on 18-9-15. 3 | // 4 | 5 | #include "llvm/ADT/APFloat.h" 6 | #include "llvm/ADT/STLExtras.h" 7 | #include "llvm/IR/BasicBlock.h" 8 | #include "llvm/IR/Constants.h" 9 | #include "llvm/IR/DerivedTypes.h" 10 | #include "llvm/IR/Function.h" 11 | #include "llvm/IR/IRBuilder.h" 12 | #include "llvm/IR/LLVMContext.h" 13 | #include "llvm/IR/Module.h" 14 | #include "llvm/IR/Type.h" 15 | #include "llvm/IR/Verifier.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace llvm; 27 | 28 | //===----------------------------------------------------------------------===// 29 | // Lexer 30 | //===----------------------------------------------------------------------===// 31 | 32 | // The lexer returns tokens [0-255] if it is an unknown character, otherwise one 33 | // of these for known things. 34 | enum Token { 35 | tok_eof = -1, 36 | 37 | // commands 38 | tok_def = -2, 39 | tok_extern = -3, 40 | 41 | // primary 42 | tok_identifier = -4, 43 | tok_number = -5 44 | }; 45 | 46 | static std::string IdentifierStr; // Filled in if tok_identifier 47 | static double NumVal; // Filled in if tok_number 48 | 49 | /// gettok - Return the next token from standard input. 50 | static int gettok() { 51 | static int LastChar = ' '; 52 | 53 | // Skip any whitespace. 54 | while (isspace(LastChar)) 55 | LastChar = getchar(); 56 | 57 | if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* 58 | IdentifierStr = LastChar; 59 | while (isalnum((LastChar = getchar()))) 60 | IdentifierStr += LastChar; 61 | 62 | if (IdentifierStr == "def") 63 | return tok_def; 64 | if (IdentifierStr == "extern") 65 | return tok_extern; 66 | return tok_identifier; 67 | } 68 | 69 | if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ 70 | std::string NumStr; 71 | do { 72 | NumStr += LastChar; 73 | LastChar = getchar(); 74 | } while (isdigit(LastChar) || LastChar == '.'); 75 | 76 | NumVal = strtod(NumStr.c_str(), nullptr); 77 | return tok_number; 78 | } 79 | 80 | if (LastChar == '#') { 81 | // Comment until end of line. 82 | do 83 | LastChar = getchar(); 84 | while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); 85 | 86 | if (LastChar != EOF) 87 | return gettok(); 88 | } 89 | 90 | // Check for end of file. Don't eat the EOF. 91 | if (LastChar == EOF) 92 | return tok_eof; 93 | 94 | // Otherwise, just return the character as its ascii value. 95 | int ThisChar = LastChar; 96 | LastChar = getchar(); 97 | return ThisChar; 98 | } 99 | 100 | //===----------------------------------------------------------------------===// 101 | // Abstract Syntax Tree (aka Parse Tree) 102 | //===----------------------------------------------------------------------===// 103 | 104 | namespace { 105 | 106 | /// ExprAST - Base class for all expression nodes. 107 | class ExprAST { 108 | public: 109 | virtual ~ExprAST() = default; 110 | 111 | virtual Value *codegen() = 0; 112 | }; 113 | 114 | /// NumberExprAST - Expression class for numeric literals like "1.0". 115 | class NumberExprAST : public ExprAST { 116 | double Val; 117 | 118 | public: 119 | explicit NumberExprAST(double Val) : Val(Val) {} 120 | 121 | Value *codegen() override; 122 | }; 123 | 124 | /// VariableExprAST - Expression class for referencing a variable, like "a". 125 | class VariableExprAST : public ExprAST { 126 | std::string Name; 127 | 128 | public: 129 | explicit VariableExprAST(std::string Name) : Name(std::move(Name)) {} 130 | 131 | Value *codegen() override; 132 | }; 133 | 134 | /// BinaryExprAST - Expression class for a binary operator. 135 | class BinaryExprAST : public ExprAST { 136 | char Op; 137 | std::unique_ptr LHS, RHS; 138 | 139 | public: 140 | BinaryExprAST(char Op, std::unique_ptr LHS, 141 | std::unique_ptr RHS) 142 | : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} 143 | 144 | Value *codegen() override; 145 | }; 146 | 147 | /// CallExprAST - Expression class for function calls. 148 | class CallExprAST : public ExprAST { 149 | std::string Callee; 150 | std::vector> Args; 151 | 152 | public: 153 | CallExprAST(std::string Callee, 154 | std::vector> Args) 155 | : Callee(std::move(Callee)), Args(std::move(Args)) {} 156 | 157 | Value *codegen() override; 158 | }; 159 | 160 | //表达式解析可能返回以上四种类型的解析节点,所以这四类节点都会在codegen阶段返回value 161 | 162 | /// PrototypeAST - This class represents the "prototype" for a function, 163 | /// which captures its name, and its argument names (thus implicitly the number 164 | /// of arguments the function takes). 165 | class PrototypeAST { 166 | std::string Name; 167 | std::vector Args; 168 | 169 | public: 170 | PrototypeAST(std::string Name, std::vector Args) 171 | : Name(std::move(Name)), Args(std::move(Args)) {} 172 | 173 | Function *codegen() ; 174 | const std::string &getName() const { return Name; } 175 | }; 176 | 177 | /// FunctionAST - This class represents a function definition itself. 178 | class FunctionAST { 179 | std::unique_ptr Proto; 180 | std::unique_ptr Body; 181 | 182 | public: 183 | FunctionAST(std::unique_ptr Proto, 184 | std::unique_ptr Body) 185 | : Proto(std::move(Proto)), Body(std::move(Body)) {} 186 | 187 | Function *codegen(); 188 | }; 189 | 190 | } // end anonymous namespace 191 | 192 | //===----------------------------------------------------------------------===// 193 | // Parser 194 | //===----------------------------------------------------------------------===// 195 | 196 | /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current 197 | /// token the parser is looking at. getNextToken reads another token from the 198 | /// lexer and updates CurTok with its results. 199 | static int CurTok; 200 | static int getNextToken() { return CurTok = gettok(); } 201 | 202 | /// BinopPrecedence - This holds the precedence for each binary operator that is 203 | /// defined. 204 | static std::map BinopPrecedence; 205 | 206 | /// GetTokPrecedence - Get the precedence of the pending binary operator token. 207 | static int GetTokPrecedence() { 208 | if (!isascii(CurTok)) 209 | return -1; 210 | 211 | // Make sure it's a declared binop. 212 | int TokPrec = BinopPrecedence[CurTok]; 213 | if (TokPrec <= 0) 214 | return -1; 215 | return TokPrec; 216 | } 217 | 218 | /// LogError* - These are little helper functions for error handling. 219 | std::unique_ptr LogError(const char *Str) { 220 | fprintf(stderr, "Error: %s\n", Str); 221 | return nullptr; 222 | } 223 | 224 | std::unique_ptr LogErrorP(const char *Str) { 225 | LogError(Str); 226 | return nullptr; 227 | } 228 | 229 | static std::unique_ptr ParseExpression(); 230 | 231 | /// numberexpr ::= number 232 | static std::unique_ptr ParseNumberExpr() { 233 | auto Result = llvm::make_unique(NumVal); 234 | getNextToken(); // consume the number 235 | return std::move(Result); 236 | } 237 | 238 | /// parenexpr ::= '(' expression ')' 239 | static std::unique_ptr ParseParenExpr() { 240 | getNextToken(); // eat (. 241 | auto V = ParseExpression(); 242 | if (!V) 243 | return nullptr; 244 | 245 | if (CurTok != ')') 246 | return LogError("expected ')'"); 247 | getNextToken(); // eat ). 248 | return V; 249 | } 250 | 251 | /// identifierexpr 252 | /// ::= identifier 253 | /// ::= identifier '(' expression* ')' 254 | static std::unique_ptr ParseIdentifierExpr() { 255 | std::string IdName = IdentifierStr; 256 | 257 | getNextToken(); // eat identifier. 258 | 259 | if (CurTok != '(') // Simple variable ref. 260 | return llvm::make_unique(IdName); 261 | 262 | // Call. 263 | getNextToken(); // eat ( 264 | std::vector> Args; 265 | if (CurTok != ')') { 266 | while (true) { 267 | if (auto Arg = ParseExpression()) 268 | Args.push_back(std::move(Arg)); 269 | else 270 | return nullptr; 271 | 272 | if (CurTok == ')') 273 | break; 274 | 275 | if (CurTok != ',') 276 | return LogError("Expected ')' or ',' in argument list"); 277 | getNextToken(); 278 | } 279 | } 280 | 281 | // Eat the ')'. 282 | getNextToken(); 283 | 284 | return llvm::make_unique(IdName, std::move(Args)); 285 | } 286 | 287 | /// primary 288 | /// ::= identifierexpr 289 | /// ::= numberexpr 290 | /// ::= parenexpr 291 | static std::unique_ptr ParsePrimary() { 292 | switch (CurTok) { 293 | default: 294 | return LogError("unknown token when expecting an expression"); 295 | case tok_identifier: 296 | return ParseIdentifierExpr(); 297 | case tok_number: 298 | return ParseNumberExpr(); 299 | case '(': 300 | return ParseParenExpr(); 301 | } 302 | } 303 | 304 | /// binoprhs 305 | /// ::= ('+' primary)* 306 | static std::unique_ptr ParseBinOpRHS(int ExprPrec, 307 | std::unique_ptr LHS) { 308 | // If this is a binop, find its precedence. 309 | while (true) { 310 | int TokPrec = GetTokPrecedence(); 311 | 312 | // If this is a binop that binds at least as tightly as the current binop, 313 | // consume it, otherwise we are done. 314 | if (TokPrec < ExprPrec) 315 | return LHS; 316 | 317 | // Okay, we know this is a binop. 318 | int BinOp = CurTok; 319 | getNextToken(); // eat binop 320 | 321 | // Parse the primary expression after the binary operator. 322 | auto RHS = ParsePrimary(); 323 | if (!RHS) 324 | return nullptr; 325 | 326 | // If BinOp binds less tightly with RHS than the operator after RHS, let 327 | // the pending operator take RHS as its LHS. 328 | int NextPrec = GetTokPrecedence(); 329 | if (TokPrec < NextPrec) { 330 | RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); 331 | if (!RHS) 332 | return nullptr; 333 | } 334 | 335 | // Merge LHS/RHS. 336 | LHS = 337 | llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); 338 | } 339 | } 340 | 341 | /// expression 342 | /// ::= primary binoprhs 343 | /// 344 | static std::unique_ptr ParseExpression() { 345 | auto LHS = ParsePrimary(); 346 | if (!LHS) 347 | return nullptr; 348 | 349 | return ParseBinOpRHS(0, std::move(LHS)); 350 | } 351 | 352 | /// prototype 353 | /// ::= id '(' id* ')' 354 | static std::unique_ptr ParsePrototype() { 355 | if (CurTok != tok_identifier) 356 | return LogErrorP("Expected function name in prototype"); 357 | 358 | std::string FnName = IdentifierStr; 359 | getNextToken(); 360 | 361 | if (CurTok != '(') 362 | return LogErrorP("Expected '(' in prototype"); 363 | 364 | std::vector ArgNames; 365 | while (getNextToken() == tok_identifier) 366 | ArgNames.push_back(IdentifierStr); 367 | if (CurTok != ')') 368 | return LogErrorP("Expected ')' in prototype"); 369 | 370 | // success. 371 | getNextToken(); // eat ')'. 372 | 373 | return llvm::make_unique(FnName, std::move(ArgNames)); 374 | } 375 | 376 | /// definition ::= 'def' prototype expression 377 | static std::unique_ptr ParseDefinition() { 378 | getNextToken(); // eat def. 379 | auto Proto = ParsePrototype(); 380 | if (!Proto) 381 | return nullptr; 382 | 383 | if (auto E = ParseExpression()) 384 | return llvm::make_unique(std::move(Proto), std::move(E)); 385 | return nullptr; 386 | } 387 | 388 | /// toplevelexpr ::= expression 389 | static std::unique_ptr ParseTopLevelExpr() { 390 | if (auto E = ParseExpression()) { 391 | // Make an anonymous proto. 392 | auto Proto = llvm::make_unique("__anon_expr", 393 | std::vector()); 394 | return llvm::make_unique(std::move(Proto), std::move(E)); 395 | } 396 | return nullptr; 397 | } 398 | 399 | /// external ::= 'extern' prototype 400 | static std::unique_ptr ParseExtern() { 401 | getNextToken(); // eat extern. 402 | return ParsePrototype(); 403 | } 404 | 405 | //===----------------------------------------------------------------------===// 406 | // Code Generation 407 | //===----------------------------------------------------------------------===// 408 | 409 | static LLVMContext TheContext; 410 | //builder:生成LLVM指令 411 | static IRBuilder<> Builder(TheContext); 412 | //存储生成的所有IR 413 | static std::unique_ptr TheModule; 414 | //代码符号表,存函数参数 415 | static std::map NamedValues; 416 | 417 | Value *LogErrorV(const char *Str) { 418 | LogError(Str); 419 | return nullptr; 420 | } 421 | 422 | Value *NumberExprAST::codegen() { 423 | return ConstantFP::get(TheContext, APFloat(Val)); 424 | } 425 | 426 | Value *VariableExprAST::codegen() { 427 | // Look this variable up in the function. 428 | Value *V = NamedValues[Name]; 429 | if (!V) 430 | return LogErrorV("Unknown variable name"); 431 | return V; 432 | } 433 | 434 | Value *BinaryExprAST::codegen() { 435 | Value *L = LHS->codegen(); 436 | Value *R = RHS->codegen(); 437 | if (!L || !R) 438 | return nullptr; 439 | 440 | switch (Op) { 441 | case '+': 442 | // addtmp:指令名称 443 | return Builder.CreateFAdd(L, R, "addtmp"); 444 | case '-': 445 | return Builder.CreateFSub(L, R, "subtmp"); 446 | case '*': 447 | return Builder.CreateFMul(L, R, "multmp"); 448 | case '<': 449 | L = Builder.CreateFCmpULT(L, R, "cmptmp"); 450 | // Convert bool 0/1 to double 0.0 or 1.0 451 | return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); 452 | default: 453 | return LogErrorV("invalid binary operator"); 454 | } 455 | } 456 | 457 | Value *CallExprAST::codegen() { 458 | // Look up the name in the global module table. 459 | Function *CalleeF = TheModule->getFunction(Callee); 460 | if (!CalleeF) 461 | return LogErrorV("Unknown function referenced"); 462 | 463 | // If argument mismatch error. 464 | if (CalleeF->arg_size() != Args.size()) 465 | return LogErrorV("Incorrect # arguments passed"); 466 | 467 | std::vector ArgsV; 468 | for (unsigned i = 0, e = static_cast(Args.size()); i != e; ++i) { 469 | ArgsV.push_back(Args[i]->codegen()); 470 | // 471 | if (!ArgsV.back()) 472 | return nullptr; 473 | } 474 | //创建一个调用指令.疑惑:所有指令结果都是一个value? 475 | return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); 476 | } 477 | 478 | Function *PrototypeAST::codegen() { 479 | // Make the function type: double(double,double) etc. 480 | std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); 481 | //函数类型也是一个常量 482 | FunctionType *FT = 483 | FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); 484 | //要使用的类型,链接和名称,以及要插入的模块(module)。 485 | // “外部链接”意味着该函数可以在当前模块外部定义和/或可以由模块外部的函数调用。 486 | Function *F = 487 | Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); 488 | 489 | // Set names for all arguments. 490 | unsigned Idx = 0; 491 | for (auto &Arg : F->args()) 492 | Arg.setName(Args[Idx++]); 493 | 494 | return F; 495 | } 496 | 497 | //函数定义的代码生成 498 | Function *FunctionAST::codegen() { 499 | // First, check for an existing function from a previous 'extern' declaration. 500 | Function *TheFunction = TheModule->getFunction(Proto->getName()); 501 | 502 | if (!TheFunction) 503 | TheFunction = Proto->codegen(); 504 | 505 | if (!TheFunction) 506 | return nullptr; 507 | //定义之前希望之前未被定义过 508 | if (!TheFunction->empty()) 509 | return (Function*)LogErrorV("Function cannot be redefined."); 510 | 511 | // Create a new basic block to start insertion into. 512 | BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); 513 | //后面生成的指令插入到当前BB块中 514 | Builder.SetInsertPoint(BB); 515 | 516 | // Record the function arguments in the NamedValues map. 517 | NamedValues.clear(); 518 | for (auto &Arg : TheFunction->args()) 519 | NamedValues[Arg.getName()] = &Arg; 520 | //body代码生成会将表达式所计算的值添加到基础块中,并返回计算值 521 | if (Value *RetVal = Body->codegen()) { 522 | // Finish off the function. 523 | Builder.CreateRet(RetVal); 524 | 525 | // Validate the generated code, checking for consistency. 526 | verifyFunction(*TheFunction); 527 | 528 | return TheFunction; 529 | } 530 | 531 | // Error reading body, remove function. 532 | TheFunction->eraseFromParent(); 533 | return nullptr; 534 | } 535 | 536 | //===----------------------------------------------------------------------===// 537 | // Top-Level parsing and JIT Driver 538 | //===----------------------------------------------------------------------===// 539 | static void HandleDefinition() { 540 | if (auto FnAST = ParseDefinition()) { 541 | if (auto *FnIR = FnAST->codegen()) { 542 | fprintf(stderr, "Read function definition:"); 543 | FnIR->print(errs()); 544 | fprintf(stderr, "\n"); 545 | } 546 | } else { 547 | // Skip token for error recovery. 548 | getNextToken(); 549 | } 550 | } 551 | 552 | static void HandleExtern() { 553 | if (auto ProtoAST = ParseExtern()) { 554 | if (auto *FnIR = ProtoAST->codegen()) { 555 | fprintf(stderr, "Read extern: "); 556 | FnIR->print(errs()); 557 | fprintf(stderr, "\n"); 558 | } 559 | } else { 560 | // Skip token for error recovery. 561 | getNextToken(); 562 | } 563 | } 564 | 565 | static void HandleTopLevelExpression() { 566 | // Evaluate a top-level expression into an anonymous function. 567 | if (auto FnAST = ParseTopLevelExpr()) { 568 | if (auto *FnIR = FnAST->codegen()) { 569 | fprintf(stderr, "Read top-level expression:"); 570 | FnIR->print(errs()); 571 | fprintf(stderr, "\n"); 572 | } 573 | } else { 574 | // Skip token for error recovery. 575 | getNextToken(); 576 | } 577 | } 578 | 579 | /// top ::= definition | external | expression | ';' 580 | static void MainLoop() { 581 | while (true) { 582 | fprintf(stderr, "ready> "); 583 | switch (CurTok) { 584 | case tok_eof: 585 | return; 586 | case ';': // ignore top-level semicolons. 587 | getNextToken(); 588 | break; 589 | case tok_def: 590 | HandleDefinition(); 591 | break; 592 | case tok_extern: 593 | HandleExtern(); 594 | break; 595 | default: 596 | HandleTopLevelExpression(); 597 | break; 598 | } 599 | } 600 | } 601 | 602 | //===----------------------------------------------------------------------===// 603 | // Main driver code. 604 | //===----------------------------------------------------------------------===// 605 | 606 | int main() { 607 | // Install standard binary operators. 608 | // 1 is lowest precedence. 609 | BinopPrecedence['<'] = 10; 610 | BinopPrecedence['+'] = 20; 611 | BinopPrecedence['-'] = 20; 612 | BinopPrecedence['*'] = 40; // highest. 613 | 614 | // Prime the first token. 615 | fprintf(stderr, "ready(chapter03)> "); 616 | getNextToken(); 617 | 618 | // Make the module, which holds all the code. 619 | TheModule = llvm::make_unique("my cool jit", TheContext); 620 | 621 | // Run the main "interpreter loop" now. 622 | MainLoop(); 623 | 624 | // Print out all of the generated code. 625 | TheModule->print(errs(), nullptr); 626 | 627 | return 0; 628 | } -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter04/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Analysis Core ExecutionEngine InstCombine Object OrcJIT RuntimeDyld ScalarOpts Support native) 3 | 4 | add_kaleidoscope_chapter(Kaleidoscope-Ch4 toy.cpp) 5 | export_executable_symbols(Kaleidoscope-Ch4) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter04/toy.cpp: -------------------------------------------------------------------------------- 1 | #include "../../include/KaleidoscopeJIT.h" 2 | #include "llvm/ADT/APFloat.h" 3 | #include "llvm/ADT/STLExtras.h" 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/Constants.h" 6 | #include "llvm/IR/DerivedTypes.h" 7 | #include "llvm/IR/Function.h" 8 | #include "llvm/IR/IRBuilder.h" 9 | #include "llvm/IR/LLVMContext.h" 10 | #include "llvm/IR/LegacyPassManager.h" 11 | #include "llvm/IR/Module.h" 12 | #include "llvm/IR/Type.h" 13 | #include "llvm/IR/Verifier.h" 14 | #include "llvm/Support/TargetSelect.h" 15 | #include "llvm/Target/TargetMachine.h" 16 | #include "llvm/Transforms/InstCombine/InstCombine.h" 17 | #include "llvm/Transforms/Scalar.h" 18 | #include "llvm/Transforms/Scalar/GVN.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | using namespace llvm; 32 | using namespace llvm::orc; 33 | 34 | //===----------------------------------------------------------------------===// 35 | // Lexer 36 | //===----------------------------------------------------------------------===// 37 | 38 | // The lexer returns tokens [0-255] if it is an unknown character, otherwise one 39 | // of these for known things. 40 | // 其他字符返回其对应的ascii 41 | enum Token { 42 | tok_eof = -1, 43 | 44 | // commands 45 | tok_def = -2, 46 | tok_extern = -3, 47 | 48 | // primary 49 | tok_identifier = -4, 50 | tok_number = -5 51 | }; 52 | 53 | static std::string IdentifierStr; // Filled in if tok_identifier 54 | static double NumVal; // Filled in if tok_number 55 | 56 | /// gettok - Return the next token from standard input. 57 | static int gettok() { 58 | //首先将读取的char设为space 59 | static int LastChar = ' '; 60 | 61 | //跳过所有的whitespace 62 | while (isspace(LastChar)) 63 | LastChar = getchar(); 64 | //跳出循环已经读取了非空格的第一个字符 65 | 66 | //识别identifier(标识符),首字母不能为数字 67 | if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* 68 | IdentifierStr = LastChar; 69 | while (isalnum((LastChar = getchar()))) 70 | IdentifierStr += LastChar; 71 | 72 | if (IdentifierStr == "def") 73 | return tok_def; 74 | if (IdentifierStr == "extern") 75 | return tok_extern; 76 | return tok_identifier; 77 | } 78 | 79 | //识别数字,添加flag,只能出现一个小数点 80 | if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ 81 | std::string NumStr; 82 | do { 83 | NumStr += LastChar; 84 | LastChar = getchar(); 85 | } while (isdigit(LastChar) || LastChar == '.'); 86 | 87 | //将字符串转换为浮点数, 88 | //string.c_str()返回指向字符串的指针 89 | NumVal = strtod(NumStr.c_str(), nullptr); 90 | return tok_number; 91 | } 92 | //识别注释,跳过本行注释,进行下一行有效字符的识别 93 | if (LastChar == '#') { 94 | // Comment until end of line. 95 | do 96 | LastChar = getchar(); 97 | while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); 98 | 99 | if (LastChar != EOF) 100 | return gettok(); 101 | } 102 | 103 | // Check for end of file. Don't eat the EOF. 104 | if (LastChar == EOF) 105 | return tok_eof; 106 | 107 | // Otherwise, just return the character as its ascii value. 108 | // 否则返回该字符的ascii码 109 | int ThisChar = LastChar; 110 | //这里是什么意思?需要读入下一个字符 111 | LastChar = getchar(); 112 | return ThisChar; 113 | } 114 | 115 | //===----------------------------------------------------------------------===// 116 | // Abstract Syntax Tree (aka Parse Tree) 117 | //===----------------------------------------------------------------------===// 118 | 119 | namespace { 120 | 121 | /// ExprAST - Base class for all expression nodes. 122 | class ExprAST { 123 | public: 124 | //virtual:基类的指针可以执行派生类,virtual告诉编译器调用派生类的相应函数 125 | virtual ~ExprAST() = default; 126 | 127 | virtual Value *codegen() = 0; 128 | }; 129 | 130 | /// NumberExprAST - Expression class for numeric literals like "1.0". 131 | class NumberExprAST : public ExprAST { 132 | double Val; 133 | 134 | public: 135 | NumberExprAST(double Val) : Val(Val) {} 136 | 137 | Value *codegen() override; 138 | }; 139 | 140 | /// VariableExprAST - Expression class for referencing a variable, like "a". 141 | class VariableExprAST : public ExprAST { 142 | std::string Name; 143 | 144 | public: 145 | VariableExprAST(std::string Name) : Name(std::move(Name)) {} 146 | 147 | Value *codegen() override; 148 | }; 149 | 150 | /// BinaryExprAST - Expression class for a binary operator. 151 | class BinaryExprAST : public ExprAST { 152 | char Op; 153 | std::unique_ptr LHS, RHS; 154 | 155 | public: 156 | BinaryExprAST(char Op, std::unique_ptr LHS, 157 | std::unique_ptr RHS) 158 | : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} 159 | 160 | Value *codegen() override; 161 | }; 162 | 163 | /// CallExprAST - Expression class for function calls. 164 | class CallExprAST : public ExprAST { 165 | std::string Callee; 166 | //每一个参数可以是一个表达式,所以这里参数是一系列节点 167 | std::vector> Args; 168 | 169 | public: 170 | CallExprAST(std::string Callee, 171 | std::vector> Args) 172 | : Callee(std::move(Callee)), Args(std::move(Args)) {} 173 | 174 | Value *codegen() override; 175 | }; 176 | 177 | /// PrototypeAST - This class represents the "prototype" for a function, 178 | /// which captures its name, and its argument names (thus implicitly the number 179 | /// of arguments the function takes). 180 | class PrototypeAST { 181 | std::string Name; 182 | std::vector Args; 183 | 184 | public: 185 | PrototypeAST(const std::string &Name, std::vector Args) 186 | : Name(Name), Args(std::move(Args)) {} 187 | 188 | Function *codegen(); 189 | const std::string &getName() const { return Name; } 190 | }; 191 | 192 | /// FunctionAST - This class represents a function definition itself. 193 | class FunctionAST { 194 | std::unique_ptr Proto; 195 | std::unique_ptr Body; 196 | 197 | public: 198 | FunctionAST(std::unique_ptr Proto, 199 | std::unique_ptr Body) 200 | : Proto(std::move(Proto)), Body(std::move(Body)) {} 201 | 202 | Function *codegen(); 203 | }; 204 | 205 | } // end anonymous namespace 206 | 207 | //===----------------------------------------------------------------------===// 208 | // Parser 209 | //===----------------------------------------------------------------------===// 210 | 211 | /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current 212 | /// token the parser is looking at. getNextToken reads another token from the 213 | /// lexer and updates CurTok with its results. 214 | // 当前标识符的标记 215 | static int CurTok; 216 | static int getNextToken() { return CurTok = gettok(); } 217 | 218 | /// BinopPrecedence - This holds the precedence for each binary operator that is 219 | /// defined. 220 | //二元操作符的优先级 221 | static std::map BinopPrecedence; 222 | 223 | /// GetTokPrecedence - Get the precedence of the pending binary operator token. 224 | static int GetTokPrecedence() { 225 | //该标识符的标记不再ascii范围内,一定是上面几种特殊标识符 226 | if (!isascii(CurTok)) 227 | return -1; 228 | 229 | // Make sure it's a declared binop. 230 | int TokPrec = BinopPrecedence[CurTok]; 231 | //没有该二元操作符 232 | if (TokPrec <= 0) 233 | return -1; 234 | return TokPrec; 235 | } 236 | 237 | /// LogError* - These are little helper functions for error handling. 238 | std::unique_ptr LogError(const char *Str) { 239 | fprintf(stderr, "Error: %s\n", Str); 240 | return nullptr; 241 | } 242 | 243 | std::unique_ptr LogErrorP(const char *Str) { 244 | LogError(Str); 245 | return nullptr; 246 | } 247 | //声明解析表达式的函数 248 | static std::unique_ptr ParseExpression(); 249 | 250 | /// numberexpr ::= number 251 | //数值解析 252 | static std::unique_ptr ParseNumberExpr() { 253 | //auto:根据变量初始值的类型自动为此变量选择匹配的类型,必须在定义时初始化 254 | auto Result = llvm::make_unique(NumVal); 255 | getNextToken(); // consume the number 256 | //这里是创建一个result节点,然后将result的指针返回 257 | return std::move(Result); 258 | } 259 | 260 | /// parenexpr ::= '(' expression ')' 261 | //解析()中的表达式 262 | static std::unique_ptr ParseParenExpr() { 263 | getNextToken(); // eat (. 264 | //在解析表达式时,统一标准是要吃掉表达式的所有标识符,并移动到下一个标识符 265 | auto V = ParseExpression(); 266 | if (!V) 267 | return nullptr; 268 | //这里的下一个标识符必须是 ) 269 | if (CurTok != ')') 270 | return LogError("expected ')'"); 271 | getNextToken(); // eat ). 272 | return V; 273 | } 274 | 275 | /// identifierexpr 276 | /// ::= identifier 277 | /// ::= identifier '(' expression* ')' 278 | //解析一个标识符,后边如果有(),就是函数函数调用 279 | static std::unique_ptr ParseIdentifierExpr() { 280 | //当前读入的标识符 281 | std::string IdName = IdentifierStr; 282 | 283 | getNextToken(); // eat identifier. 284 | //简单的变量标识符 285 | if (CurTok != '(') // Simple variable ref. 286 | return llvm::make_unique(IdName); 287 | 288 | //函数调用 289 | getNextToken(); // eat ( 290 | std::vector> Args; 291 | //函数带参数 292 | if (CurTok != ')') { 293 | while (true) { 294 | if (auto Arg = ParseExpression()) 295 | Args.push_back(std::move(Arg)); 296 | else 297 | return nullptr; 298 | //所有参数解析完毕 299 | if (CurTok == ')') 300 | break; 301 | //表达式解析之后既不是,又不是) ,输入有误 302 | if (CurTok != ',') 303 | return LogError("Expected ')' or ',' in argument list"); 304 | //吃掉, 305 | getNextToken(); 306 | } 307 | } 308 | 309 | // Eat the ')'. 310 | getNextToken(); 311 | 312 | return llvm::make_unique(IdName, std::move(Args)); 313 | } 314 | 315 | /// primary 316 | /// ::= identifierexpr 317 | /// ::= numberexpr 318 | /// ::= parenexpr 319 | static std::unique_ptr ParsePrimary() { 320 | switch (CurTok) { 321 | default: 322 | return LogError("unknown token when expecting an expression"); 323 | //当前是一个标识符,其可能是一个普通标识符,也可能是一个函数调用标识符 324 | case tok_identifier: 325 | return ParseIdentifierExpr(); 326 | case tok_number: 327 | return ParseNumberExpr(); 328 | case '(': 329 | return ParseParenExpr(); 330 | } 331 | } 332 | 333 | /// binoprhs 334 | /// ::= ('+' primary)* 335 | static std::unique_ptr ParseBinOpRHS(int ExprPrec, 336 | std::unique_ptr LHS) { 337 | // If this is a binop, find its precedence. 338 | while (true) { 339 | int TokPrec = GetTokPrecedence(); 340 | 341 | // If this is a binop that binds at least as tightly as the current binop, 342 | // consume it, otherwise we are done. 343 | //当前op优先级小于之前所有op的优先级,返回当前op之前的表达式 344 | if (TokPrec < ExprPrec) 345 | return LHS; 346 | 347 | // Okay, we know this is a binop. 348 | //拿到当前操作符 349 | int BinOp = CurTok; 350 | getNextToken(); // eat binop 351 | 352 | // Parse the primary expression after the binary operator. 353 | //到此CurTok已经来到下一个op 354 | //拿到下一个op的优先级 355 | auto RHS = ParsePrimary(); 356 | if (!RHS) 357 | return nullptr; 358 | 359 | // If BinOp binds less tightly with RHS than the operator after RHS, let 360 | // the pending operator take RHS as its LHS. 361 | int NextPrec = GetTokPrecedence(); 362 | if (TokPrec < NextPrec) { 363 | //进入递归 364 | RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); 365 | if (!RHS) 366 | return nullptr; 367 | } 368 | 369 | // Merge LHS/RHS. 370 | LHS = 371 | llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); 372 | } 373 | } 374 | 375 | /// expression 376 | /// ::= primary binoprhs 377 | ///解析整表达式 378 | static std::unique_ptr ParseExpression() { 379 | auto LHS = ParsePrimary(); 380 | if (!LHS) 381 | return nullptr; 382 | 383 | return ParseBinOpRHS(0, std::move(LHS)); 384 | } 385 | 386 | /// prototype 387 | /// ::= id '(' id* ')' 388 | //解析函数原型 389 | static std::unique_ptr ParsePrototype() { 390 | if (CurTok != tok_identifier) 391 | return LogErrorP("Expected function name in prototype"); 392 | 393 | std::string FnName = IdentifierStr; 394 | getNextToken(); 395 | 396 | if (CurTok != '(') 397 | return LogErrorP("Expected '(' in prototype"); 398 | 399 | std::vector ArgNames; 400 | //这里为了简单起见,参数之间以空格间隔,而不是, 401 | while (getNextToken() == tok_identifier) 402 | ArgNames.push_back(IdentifierStr); 403 | if (CurTok != ')') 404 | return LogErrorP("Expected ')' in prototype"); 405 | 406 | // success. 407 | getNextToken(); // eat ')'. 408 | 409 | return llvm::make_unique(FnName, std::move(ArgNames)); 410 | } 411 | 412 | /// definition ::= 'def' prototype expression 413 | //函数定义解析 414 | static std::unique_ptr ParseDefinition() { 415 | getNextToken(); // eat def. 416 | auto Proto = ParsePrototype(); 417 | if (!Proto) 418 | return nullptr; 419 | 420 | if (auto E = ParseExpression()) 421 | return llvm::make_unique(std::move(Proto), std::move(E)); 422 | return nullptr; 423 | } 424 | 425 | /// toplevelexpr ::= expression 426 | //将所有的顶层表达式写成函数的形式 427 | static std::unique_ptr ParseTopLevelExpr() { 428 | if (auto E = ParseExpression()) { 429 | // Make an anonymous proto. 430 | auto Proto = llvm::make_unique("__anon_expr", 431 | std::vector()); 432 | return llvm::make_unique(std::move(Proto), std::move(E)); 433 | } 434 | return nullptr; 435 | } 436 | 437 | /// external ::= 'extern' prototype 438 | static std::unique_ptr ParseExtern() { 439 | getNextToken(); // eat extern. 440 | return ParsePrototype(); 441 | } 442 | 443 | //===----------------------------------------------------------------------===// 444 | // Code Generation 445 | //===----------------------------------------------------------------------===// 446 | 447 | static LLVMContext TheContext; 448 | static IRBuilder<> Builder(TheContext); 449 | static std::unique_ptr TheModule; 450 | static std::map NamedValues; 451 | static std::unique_ptr TheFPM; 452 | static std::unique_ptr TheJIT; 453 | static std::map> FunctionProtos; 454 | 455 | Value *LogErrorV(const char *Str) { 456 | LogError(Str); 457 | return nullptr; 458 | } 459 | 460 | //函数是声明的代码生成 461 | Function *getFunction(const std::string &Name) { 462 | // First, see if the function has already been added to the current module. 463 | if (auto *F = TheModule->getFunction(Name)) 464 | return F; 465 | 466 | // If not, check whether we can codegen the declaration from some existing 467 | // prototype. 468 | auto FI = FunctionProtos.find(Name); 469 | if (FI != FunctionProtos.end()) 470 | return FI->second->codegen(); 471 | 472 | // If no existing prototype exists, return null. 473 | return nullptr; 474 | } 475 | 476 | //数值代码生成 477 | Value *NumberExprAST::codegen() { 478 | return ConstantFP::get(TheContext, APFloat(Val)); 479 | } 480 | 481 | //变量代码生成 482 | Value *VariableExprAST::codegen() { 483 | // Look this variable up in the function. 484 | Value *V = NamedValues[Name]; 485 | if (!V) 486 | return LogErrorV("Unknown variable name"); 487 | return V; 488 | } 489 | 490 | //二元表达式的代码生成 491 | Value *BinaryExprAST::codegen() { 492 | Value *L = LHS->codegen(); 493 | Value *R = RHS->codegen(); 494 | if (!L || !R) 495 | return nullptr; 496 | 497 | switch (Op) { 498 | case '+': 499 | return Builder.CreateFAdd(L, R, "addtmp"); 500 | case '-': 501 | return Builder.CreateFSub(L, R, "subtmp"); 502 | case '*': 503 | return Builder.CreateFMul(L, R, "multmp"); 504 | case '<': 505 | L = Builder.CreateFCmpULT(L, R, "cmptmp"); 506 | // Convert bool 0/1 to double 0.0 or 1.0 507 | return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); 508 | default: 509 | return LogErrorV("invalid binary operator"); 510 | } 511 | } 512 | 513 | //函数调用代码生成 514 | Value *CallExprAST::codegen() { 515 | // Look up the name in the global module table. 516 | Function *CalleeF = getFunction(Callee); 517 | if (!CalleeF) 518 | return LogErrorV("Unknown function referenced"); 519 | 520 | // If argument mismatch error. 521 | //声明函数与调用函数参数个数不匹配 522 | if (CalleeF->arg_size() != Args.size()) 523 | return LogErrorV("Incorrect # arguments passed"); 524 | 525 | std::vector ArgsV; 526 | for (unsigned i = 0, e = static_cast(Args.size()); i != e; ++i) { 527 | ArgsV.push_back(Args[i]->codegen()); 528 | if (!ArgsV.back()) 529 | return nullptr; 530 | } 531 | 532 | return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); 533 | } 534 | 535 | //函数声明的代码生成 536 | Function *PrototypeAST::codegen() { 537 | // Make the function type: double(double,double) etc. 538 | //所有的参数类型均为double 539 | std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); 540 | //函数类型,需要其返回值类型,和参数类型,这个false什么意思 541 | FunctionType *FT = 542 | FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); 543 | //此函数为外部可见函数,并将函数存入theModel 544 | Function *F = 545 | Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); 546 | 547 | // Set names for all arguments. 548 | unsigned Idx = 0; 549 | //为参数附上参数名 550 | for (auto &Arg : F->args()) 551 | Arg.setName(Args[Idx++]); 552 | 553 | return F; 554 | } 555 | 556 | //函数定义代码生成 557 | Function *FunctionAST::codegen() { 558 | // Transfer ownership of the prototype to the FunctionProtos map, but keep a 559 | // reference to it for use below. 560 | //引用只是起一个别名 561 | auto &P = *Proto; 562 | //在函数表里注册 563 | FunctionProtos[Proto->getName()] = std::move(Proto); 564 | Function *TheFunction = getFunction(P.getName()); 565 | if (!TheFunction) 566 | return nullptr; 567 | //希望在此之前函数是没被定义过的 568 | if (!TheFunction->empty()) 569 | return (Function*)LogErrorV("Function cannot be redefined."); 570 | 571 | // Create a new basic block to start insertion into. 572 | //将BB插入到theFunction中 573 | BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); 574 | //将新指令插入到基础块的末尾,现在没有控制流,所以只有一个块 575 | Builder.SetInsertPoint(BB); 576 | 577 | // Record the function arguments in the NamedValues map. 578 | //这不是很理解 579 | NamedValues.clear(); 580 | //将函数参数添加到nameValue中,以便被VariableAST节点访问 581 | for (auto &Arg : TheFunction->args()) 582 | NamedValues[Arg.getName()] = &Arg; 583 | 584 | if (Value *RetVal = Body->codegen()) { 585 | // Finish off the function. 586 | //创建一个ret指令,表示函数结束 587 | Builder.CreateRet(RetVal); 588 | 589 | // Validate the generated code, checking for consistency. 590 | verifyFunction(*TheFunction); 591 | //对函数进行优化,这一句是本章的重点!!!!!! 592 | // Run the optimizer on the function. 593 | TheFPM->run(*TheFunction); 594 | 595 | return TheFunction; 596 | } 597 | 598 | // Error reading body, remove function. 599 | //body为空指针,取消theFunction在Module中的注册 600 | TheFunction->eraseFromParent(); 601 | return nullptr; 602 | } 603 | 604 | //===----------------------------------------------------------------------===// 605 | // Top-Level parsing and JIT Driver 606 | //===----------------------------------------------------------------------===// 607 | //为JIT设置布局 608 | static void InitializeModuleAndPassManager() { 609 | // Open a new module. 610 | //开一个新module 611 | TheModule = llvm::make_unique("my cool jit", TheContext); 612 | TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); 613 | 614 | // Create a new pass manager attached to it. 615 | //创建一个新pass manager来跟踪,管理函数pass和基础块pass 616 | TheFPM = llvm::make_unique(TheModule.get()); 617 | //添加各种各样的pass,这是一组标准的cleanup优化 618 | // Do simple "peephole" optimizations and bit-twiddling optzns. 619 | TheFPM->add(createInstructionCombiningPass()); 620 | // Reassociate expressions. 621 | // 重新关联表达式。 622 | TheFPM->add(createReassociatePass()); 623 | // Eliminate Common SubExpressions. 624 | // 消除常见的子表达式。 625 | TheFPM->add(createGVNPass()); 626 | // Simplify the control flow graph (deleting unreachable blocks, etc). 627 | // 简化控制流程图(删除无法访问的块等)。 628 | TheFPM->add(createCFGSimplificationPass()); 629 | 630 | TheFPM->doInitialization(); 631 | } 632 | 633 | static void HandleDefinition() { 634 | if (auto FnAST = ParseDefinition()) { 635 | //在代码生成过程中已经执行了当前module的代码优化 636 | if (auto *FnIR = FnAST->codegen()) { 637 | fprintf(stderr, "Read function definition:"); 638 | // 打印中间生成代码 639 | FnIR->print(errs()); 640 | fprintf(stderr, "\n"); 641 | TheJIT->addModule(std::move(TheModule)); 642 | InitializeModuleAndPassManager(); 643 | } 644 | } else { 645 | // Skip token for error recovery. 646 | getNextToken(); 647 | } 648 | } 649 | 650 | static void HandleExtern() { 651 | if (auto ProtoAST = ParseExtern()) { 652 | if (auto *FnIR = ProtoAST->codegen()) { 653 | fprintf(stderr, "Read extern: "); 654 | FnIR->print(errs()); 655 | fprintf(stderr, "\n"); 656 | FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); 657 | } 658 | } else { 659 | // Skip token for error recovery. 660 | getNextToken(); 661 | } 662 | } 663 | 664 | static void HandleTopLevelExpression() { 665 | // Evaluate a top-level expression into an anonymous function. 666 | if (auto FnAST = ParseTopLevelExpr()) { 667 | if (auto *FnIR = FnAST->codegen()) { 668 | fprintf(stderr, "Read top-level expression:"); 669 | FnIR->print(errs()); 670 | fprintf(stderr, "\n"); 671 | 672 | // JIT the module containing the anonymous expression, keeping a handle so 673 | // we can free it later. 674 | //返回添加模块的句柄,用来删除模块用 675 | //触发所有函数代码生成 676 | auto H = TheJIT->addModule(std::move(TheModule)); 677 | //添加到JIT,就无法修改,需要新开一个module,调用此函数来保存后续代码 678 | InitializeModuleAndPassManager(); 679 | 680 | // Search the JIT for the __anon_expr symbol. 681 | auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); 682 | assert(ExprSymbol && "Function not found"); 683 | 684 | // Get the symbol's address and cast it to the right type (takes no 685 | // arguments, returns a double) so we can call it as a native function. 686 | // 获取内存中地址,为什么在这一句常常回报错呢??找不到已定义函数的地址? 687 | // Failure value returned from cantFail wrapped call 688 | // UNREACHABLE executed at /home/cyoung/llvm/build_install/include/llvm/Support/Error.h:729! 689 | 690 | double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); 691 | fprintf(stderr, "Evaluated to %f\n", FP()); 692 | 693 | // Delete the anonymous expression module from the JIT. 694 | TheJIT->removeModule(H); 695 | } 696 | } else { 697 | // Skip token for error recovery. 698 | getNextToken(); 699 | } 700 | } 701 | 702 | /// top ::= definition | external | expression | ';' 703 | static void MainLoop() { 704 | while (true) { 705 | fprintf(stderr, "ready> "); 706 | switch (CurTok) { 707 | case tok_eof: 708 | return; 709 | case ';': // ignore top-level semicolons. 710 | getNextToken(); 711 | break; 712 | case tok_def: 713 | HandleDefinition(); 714 | break; 715 | case tok_extern: 716 | HandleExtern(); 717 | break; 718 | default: 719 | HandleTopLevelExpression(); 720 | break; 721 | } 722 | } 723 | } 724 | 725 | //===----------------------------------------------------------------------===// 726 | // "Library" functions that can be "extern'd" from user code. 727 | //===----------------------------------------------------------------------===// 728 | 729 | #ifdef _WIN32 730 | #define DLLEXPORT __declspec(dllexport) 731 | #else 732 | #define DLLEXPORT 733 | #endif 734 | 735 | /// putchard - putchar that takes a double and returns 0. 736 | extern "C" DLLEXPORT double putchard(double X) { 737 | fputc((char)X, stderr); 738 | return 0; 739 | } 740 | 741 | /// printd - printf that takes a double prints it as "%f\n", returning 0. 742 | extern "C" DLLEXPORT double printd(double X) { 743 | fprintf(stderr, "%f\n", X); 744 | return 0; 745 | } 746 | 747 | //===----------------------------------------------------------------------===// 748 | // Main driver code. 749 | //===----------------------------------------------------------------------===// 750 | 751 | int main() { 752 | InitializeNativeTarget(); 753 | InitializeNativeTargetAsmPrinter(); 754 | InitializeNativeTargetAsmParser(); 755 | 756 | // Install standard binary operators. 757 | // 1 is lowest precedence. 758 | BinopPrecedence['<'] = 10; 759 | BinopPrecedence['+'] = 20; 760 | BinopPrecedence['-'] = 20; 761 | BinopPrecedence['*'] = 40; // highest. 762 | 763 | // Prime the first token. 764 | fprintf(stderr, "ready(chapter04)> "); 765 | getNextToken(); 766 | 767 | TheJIT = llvm::make_unique(); 768 | 769 | InitializeModuleAndPassManager(); 770 | 771 | // Run the main "interpreter loop" now. 772 | MainLoop(); 773 | 774 | return 0; 775 | } 776 | -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter05/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Analysis 3 | Core 4 | ExecutionEngine 5 | InstCombine 6 | Object 7 | OrcJIT 8 | RuntimeDyld 9 | ScalarOpts 10 | Support 11 | native 12 | ) 13 | 14 | add_kaleidoscope_chapter(Kaleidoscope-Ch5 15 | toy.cpp) 16 | 17 | export_executable_symbols(Kaleidoscope-Ch5) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter05/toy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cyoung on 18-9-26. 3 | // 4 | 5 | #include "../../include/KaleidoscopeJIT.h" 6 | #include "llvm/ADT/APFloat.h" 7 | #include "llvm/ADT/STLExtras.h" 8 | #include "llvm/IR/BasicBlock.h" 9 | #include "llvm/IR/Constants.h" 10 | #include "llvm/IR/DerivedTypes.h" 11 | #include "llvm/IR/Function.h" 12 | #include "llvm/IR/IRBuilder.h" 13 | #include "llvm/IR/Instructions.h" 14 | #include "llvm/IR/LLVMContext.h" 15 | #include "llvm/IR/LegacyPassManager.h" 16 | #include "llvm/IR/Module.h" 17 | #include "llvm/IR/Type.h" 18 | #include "llvm/IR/Verifier.h" 19 | #include "llvm/Support/TargetSelect.h" 20 | #include "llvm/Target/TargetMachine.h" 21 | #include "llvm/Transforms/InstCombine/InstCombine.h" 22 | #include "llvm/Transforms/Scalar.h" 23 | #include "llvm/Transforms/Scalar/GVN.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using namespace llvm; 37 | using namespace llvm::orc; 38 | 39 | //===----------------------------------------------------------------------===// 40 | // Lexer 41 | //===----------------------------------------------------------------------===// 42 | 43 | // The lexer returns tokens [0-255] if it is an unknown character, otherwise one 44 | // of these for known things. 45 | enum Token { 46 | tok_eof = -1, 47 | 48 | // commands 49 | tok_def = -2, 50 | tok_extern = -3, 51 | 52 | // primary 53 | tok_identifier = -4, 54 | tok_number = -5, 55 | 56 | // control 57 | tok_if = -6, 58 | tok_then = -7, 59 | tok_else = -8, 60 | tok_for = -9, 61 | tok_in = -10 62 | }; 63 | 64 | static std::string IdentifierStr; // Filled in if tok_identifier 65 | static double NumVal; // Filled in if tok_number 66 | 67 | /// gettok - Return the next token from standard input. 68 | static int gettok() { 69 | static int LastChar = ' '; 70 | 71 | // Skip any whitespace. 72 | while (isspace(LastChar)) 73 | LastChar = getchar(); 74 | 75 | if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* 76 | IdentifierStr = LastChar; 77 | while (isalnum((LastChar = getchar()))) 78 | IdentifierStr += LastChar; 79 | 80 | if (IdentifierStr == "def") 81 | return tok_def; 82 | if (IdentifierStr == "extern") 83 | return tok_extern; 84 | //添加新的关键字解析 85 | if (IdentifierStr == "if") 86 | return tok_if; 87 | if (IdentifierStr == "then") 88 | return tok_then; 89 | if (IdentifierStr == "else") 90 | return tok_else; 91 | if (IdentifierStr == "for") 92 | return tok_for; 93 | if (IdentifierStr == "in") 94 | return tok_in; 95 | return tok_identifier; 96 | } 97 | 98 | if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ 99 | std::string NumStr; 100 | do { 101 | NumStr += LastChar; 102 | LastChar = getchar(); 103 | } while (isdigit(LastChar) || LastChar == '.'); 104 | 105 | NumVal = strtod(NumStr.c_str(), nullptr); 106 | return tok_number; 107 | } 108 | 109 | if (LastChar == '#') { 110 | // Comment until end of line. 111 | do 112 | LastChar = getchar(); 113 | while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); 114 | 115 | if (LastChar != EOF) 116 | return gettok(); 117 | } 118 | 119 | // Check for end of file. Don't eat the EOF. 120 | if (LastChar == EOF) 121 | return tok_eof; 122 | 123 | // Otherwise, just return the character as its ascii value. 124 | int ThisChar = LastChar; 125 | LastChar = getchar(); 126 | return ThisChar; 127 | } 128 | 129 | //===----------------------------------------------------------------------===// 130 | // Abstract Syntax Tree (aka Parse Tree) 131 | //===----------------------------------------------------------------------===// 132 | 133 | namespace { 134 | 135 | /// ExprAST - Base class for all expression nodes. 136 | class ExprAST { 137 | public: 138 | virtual ~ExprAST() = default; 139 | 140 | virtual Value *codegen() = 0; 141 | }; 142 | 143 | /// NumberExprAST - Expression class for numeric literals like "1.0". 144 | class NumberExprAST : public ExprAST { 145 | double Val; 146 | 147 | public: 148 | NumberExprAST(double Val) : Val(Val) {} 149 | 150 | Value *codegen() override; 151 | }; 152 | 153 | /// VariableExprAST - Expression class for referencing a variable, like "a". 154 | class VariableExprAST : public ExprAST { 155 | std::string Name; 156 | 157 | public: 158 | VariableExprAST(std::string Name) : Name(std::move(Name)) {} 159 | 160 | Value *codegen() override; 161 | }; 162 | 163 | /// BinaryExprAST - Expression class for a binary operator. 164 | class BinaryExprAST : public ExprAST { 165 | char Op; 166 | std::unique_ptr LHS, RHS; 167 | 168 | public: 169 | BinaryExprAST(char Op, std::unique_ptr LHS, 170 | std::unique_ptr RHS) 171 | : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} 172 | 173 | Value *codegen() override; 174 | }; 175 | 176 | /// CallExprAST - Expression class for function calls. 177 | class CallExprAST : public ExprAST { 178 | std::string Callee; 179 | std::vector> Args; 180 | 181 | public: 182 | CallExprAST(const std::string &Callee, 183 | std::vector> Args) 184 | : Callee(Callee), Args(std::move(Args)) {} 185 | 186 | Value *codegen() override; 187 | }; 188 | 189 | /// IfExprAST - Expression class for if/then/else. 190 | class IfExprAST : public ExprAST { 191 | std::unique_ptr Cond, Then, Else; 192 | 193 | public: 194 | IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, 195 | std::unique_ptr Else) 196 | : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} 197 | 198 | Value *codegen() override; 199 | }; 200 | 201 | /// ForExprAST - Expression class for for/in. 202 | class ForExprAST : public ExprAST { 203 | std::string VarName; 204 | std::unique_ptr Start, End, Step, Body; 205 | 206 | public: 207 | ForExprAST(std::string VarName, std::unique_ptr Start, 208 | std::unique_ptr End, std::unique_ptr Step, 209 | std::unique_ptr Body) 210 | : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), 211 | Step(std::move(Step)), Body(std::move(Body)) {} 212 | 213 | Value *codegen() override; 214 | }; 215 | 216 | /// PrototypeAST - This class represents the "prototype" for a function, 217 | /// which captures its name, and its argument names (thus implicitly the number 218 | /// of arguments the function takes). 219 | class PrototypeAST { 220 | std::string Name; 221 | std::vector Args; 222 | 223 | public: 224 | PrototypeAST(std::string Name, std::vector Args) 225 | : Name(std::move(Name)), Args(std::move(Args)) {} 226 | 227 | Function *codegen(); 228 | const std::string &getName() const { return Name; } 229 | }; 230 | 231 | /// FunctionAST - This class represents a function definition itself. 232 | class FunctionAST { 233 | std::unique_ptr Proto; 234 | std::unique_ptr Body; 235 | 236 | public: 237 | FunctionAST(std::unique_ptr Proto, 238 | std::unique_ptr Body) 239 | : Proto(std::move(Proto)), Body(std::move(Body)) {} 240 | 241 | Function *codegen(); 242 | }; 243 | 244 | } // end anonymous namespace 245 | 246 | //===----------------------------------------------------------------------===// 247 | // Parser 248 | //===----------------------------------------------------------------------===// 249 | 250 | /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current 251 | /// token the parser is looking at. getNextToken reads another token from the 252 | /// lexer and updates CurTok with its results. 253 | static int CurTok; 254 | static int getNextToken() { return CurTok = gettok(); } 255 | 256 | /// BinopPrecedence - This holds the precedence for each binary operator that is 257 | /// defined. 258 | static std::map BinopPrecedence; 259 | 260 | /// GetTokPrecedence - Get the precedence of the pending binary operator token. 261 | static int GetTokPrecedence() { 262 | if (!isascii(CurTok)) 263 | return -1; 264 | 265 | // Make sure it's a declared binop. 266 | int TokPrec = BinopPrecedence[CurTok]; 267 | if (TokPrec <= 0) 268 | return -1; 269 | return TokPrec; 270 | } 271 | 272 | /// LogError* - These are little helper functions for error handling. 273 | std::unique_ptr LogError(const char *Str) { 274 | fprintf(stderr, "Error: %s\n", Str); 275 | return nullptr; 276 | } 277 | 278 | std::unique_ptr LogErrorP(const char *Str) { 279 | LogError(Str); 280 | return nullptr; 281 | } 282 | 283 | static std::unique_ptr ParseExpression(); 284 | 285 | /// numberexpr ::= number 286 | static std::unique_ptr ParseNumberExpr() { 287 | auto Result = llvm::make_unique(NumVal); 288 | getNextToken(); // consume the number 289 | return std::move(Result); 290 | } 291 | 292 | /// parenexpr ::= '(' expression ')' 293 | static std::unique_ptr ParseParenExpr() { 294 | getNextToken(); // eat (. 295 | auto V = ParseExpression(); 296 | if (!V) 297 | return nullptr; 298 | 299 | if (CurTok != ')') 300 | return LogError("expected ')'"); 301 | getNextToken(); // eat ). 302 | return V; 303 | } 304 | 305 | /// identifierexpr 306 | /// ::= identifier 307 | /// ::= identifier '(' expression* ')' 308 | static std::unique_ptr ParseIdentifierExpr() { 309 | std::string IdName = IdentifierStr; 310 | 311 | getNextToken(); // eat identifier. 312 | 313 | if (CurTok != '(') // Simple variable ref. 314 | return llvm::make_unique(IdName); 315 | 316 | // Call. 317 | getNextToken(); // eat ( 318 | std::vector> Args; 319 | if (CurTok != ')') { 320 | while (true) { 321 | if (auto Arg = ParseExpression()) 322 | Args.push_back(std::move(Arg)); 323 | else 324 | return nullptr; 325 | 326 | if (CurTok == ')') 327 | break; 328 | 329 | if (CurTok != ',') 330 | return LogError("Expected ')' or ',' in argument list"); 331 | getNextToken(); 332 | } 333 | } 334 | 335 | // Eat the ')'. 336 | getNextToken(); 337 | 338 | return llvm::make_unique(IdName, std::move(Args)); 339 | } 340 | 341 | /// ifexpr ::= 'if' expression 'then' expression 'else' expression 342 | // if表达式的解析 343 | static std::unique_ptr ParseIfExpr() { 344 | getNextToken(); // eat the if. 345 | 346 | // condition. 347 | auto Cond = ParseExpression(); 348 | if (!Cond) 349 | return nullptr; 350 | 351 | if (CurTok != tok_then) 352 | return LogError("expected then"); 353 | getNextToken(); // eat the then 354 | 355 | auto Then = ParseExpression(); 356 | if (!Then) 357 | return nullptr; 358 | 359 | if (CurTok != tok_else) 360 | return LogError("expected else"); 361 | // 吃掉 else 362 | getNextToken(); 363 | 364 | auto Else = ParseExpression(); 365 | if (!Else) 366 | return nullptr; 367 | 368 | return llvm::make_unique(std::move(Cond), std::move(Then), 369 | std::move(Else)); 370 | } 371 | 372 | /// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression 373 | // for循环的解析 374 | static std::unique_ptr ParseForExpr() { 375 | getNextToken(); // eat the for. 376 | 377 | if (CurTok != tok_identifier) 378 | return LogError("expected identifier after for"); 379 | //循环变量 380 | std::string IdName = IdentifierStr; 381 | getNextToken(); // eat identifier. 382 | 383 | if (CurTok != '=') 384 | return LogError("expected '=' after for"); 385 | getNextToken(); // eat '='. 386 | 387 | auto Start = ParseExpression(); 388 | if (!Start) 389 | return nullptr; 390 | if (CurTok != ',') 391 | return LogError("expected ',' after for start value"); 392 | // 吃掉, 393 | getNextToken(); 394 | 395 | auto End = ParseExpression(); 396 | if (!End) 397 | return nullptr; 398 | 399 | // The step value is optional. 400 | //step可以忽略 401 | std::unique_ptr Step; 402 | if (CurTok == ',') { 403 | getNextToken(); 404 | Step = ParseExpression(); 405 | if (!Step) 406 | return nullptr; 407 | } 408 | 409 | if (CurTok != tok_in) 410 | return LogError("expected 'in' after for"); 411 | getNextToken(); // eat 'in'. 412 | 413 | //循环体也作为一个表达式看待 414 | auto Body = ParseExpression(); 415 | if (!Body) 416 | return nullptr; 417 | 418 | return llvm::make_unique(IdName, std::move(Start), std::move(End), 419 | std::move(Step), std::move(Body)); 420 | } 421 | 422 | /// primary 423 | /// ::= identifierexpr 424 | /// ::= numberexpr 425 | /// ::= parenexpr 426 | /// ::= ifexpr 427 | /// ::= forexpr 428 | // ParsePrimary 和 ParseExpression 429 | static std::unique_ptr ParsePrimary() { 430 | switch (CurTok) { 431 | default: 432 | return LogError("unknown token when expecting an expression"); 433 | case tok_identifier: 434 | return ParseIdentifierExpr(); 435 | case tok_number: 436 | return ParseNumberExpr(); 437 | case '(': 438 | return ParseParenExpr(); 439 | // if语句也可以是一个主表达式 440 | case tok_if: 441 | return ParseIfExpr(); 442 | // for也是一个主表达式 443 | case tok_for: 444 | return ParseForExpr(); 445 | } 446 | } 447 | 448 | /// binoprhs 449 | /// ::= ('+' primary)* 450 | static std::unique_ptr ParseBinOpRHS(int ExprPrec, 451 | std::unique_ptr LHS) { 452 | // If this is a binop, find its precedence. 453 | while (true) { 454 | int TokPrec = GetTokPrecedence(); 455 | 456 | // If this is a binop that binds at least as tightly as the current binop, 457 | // consume it, otherwise we are done. 458 | if (TokPrec < ExprPrec) 459 | return LHS; 460 | 461 | // Okay, we know this is a binop. 462 | int BinOp = CurTok; 463 | getNextToken(); // eat binop 464 | 465 | // Parse the primary expression after the binary operator. 466 | auto RHS = ParsePrimary(); 467 | if (!RHS) 468 | return nullptr; 469 | 470 | // If BinOp binds less tightly with RHS than the operator after RHS, let 471 | // the pending operator take RHS as its LHS. 472 | int NextPrec = GetTokPrecedence(); 473 | if (TokPrec < NextPrec) { 474 | RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); 475 | if (!RHS) 476 | return nullptr; 477 | } 478 | 479 | // Merge LHS/RHS. 480 | LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); 481 | } 482 | } 483 | 484 | /// expression 485 | /// ::= primary binoprhs 486 | /// 487 | static std::unique_ptr ParseExpression() { 488 | auto LHS = ParsePrimary(); 489 | if (!LHS) 490 | return nullptr; 491 | 492 | return ParseBinOpRHS(0, std::move(LHS)); 493 | } 494 | 495 | /// prototype 496 | /// ::= id '(' id* ')' 497 | static std::unique_ptr ParsePrototype() { 498 | if (CurTok != tok_identifier) 499 | return LogErrorP("Expected function name in prototype"); 500 | 501 | std::string FnName = IdentifierStr; 502 | getNextToken(); 503 | 504 | if (CurTok != '(') 505 | return LogErrorP("Expected '(' in prototype"); 506 | 507 | std::vector ArgNames; 508 | while (getNextToken() == tok_identifier) 509 | ArgNames.push_back(IdentifierStr); 510 | if (CurTok != ')') 511 | return LogErrorP("Expected ')' in prototype"); 512 | 513 | // success. 514 | getNextToken(); // eat ')'. 515 | 516 | return llvm::make_unique(FnName, std::move(ArgNames)); 517 | } 518 | 519 | /// definition ::= 'def' prototype expression 520 | static std::unique_ptr ParseDefinition() { 521 | getNextToken(); // eat def. 522 | auto Proto = ParsePrototype(); 523 | if (!Proto) 524 | return nullptr; 525 | 526 | if (auto E = ParseExpression()) 527 | return llvm::make_unique(std::move(Proto), std::move(E)); 528 | return nullptr; 529 | } 530 | 531 | /// toplevelexpr ::= expression 532 | static std::unique_ptr ParseTopLevelExpr() { 533 | if (auto E = ParseExpression()) { 534 | // Make an anonymous proto. 535 | auto Proto = llvm::make_unique("__anon_expr", 536 | std::vector()); 537 | return llvm::make_unique(std::move(Proto), std::move(E)); 538 | } 539 | return nullptr; 540 | } 541 | 542 | /// external ::= 'extern' prototype 543 | static std::unique_ptr ParseExtern() { 544 | getNextToken(); // eat extern. 545 | return ParsePrototype(); 546 | } 547 | 548 | //===----------------------------------------------------------------------===// 549 | // Code Generation 550 | //===----------------------------------------------------------------------===// 551 | 552 | static LLVMContext TheContext; 553 | static IRBuilder<> Builder(TheContext); 554 | static std::unique_ptr TheModule; 555 | static std::map NamedValues; 556 | static std::unique_ptr TheFPM; 557 | static std::unique_ptr TheJIT; 558 | static std::map> FunctionProtos; 559 | 560 | Value *LogErrorV(const char *Str) { 561 | LogError(Str); 562 | return nullptr; 563 | } 564 | 565 | Function *getFunction(std::string Name) { 566 | // First, see if the function has already been added to the current module. 567 | if (auto *F = TheModule->getFunction(Name)) 568 | return F; 569 | 570 | // If not, check whether we can codegen the declaration from some existing 571 | // prototype. 572 | auto FI = FunctionProtos.find(Name); 573 | if (FI != FunctionProtos.end()) 574 | return FI->second->codegen(); 575 | 576 | // If no existing prototype exists, return null. 577 | return nullptr; 578 | } 579 | 580 | Value *NumberExprAST::codegen() { 581 | return ConstantFP::get(TheContext, APFloat(Val)); 582 | } 583 | 584 | Value *VariableExprAST::codegen() { 585 | // Look this variable up in the function. 586 | Value *V = NamedValues[Name]; 587 | if (!V) 588 | return LogErrorV("Unknown variable name"); 589 | return V; 590 | } 591 | 592 | Value *BinaryExprAST::codegen() { 593 | Value *L = LHS->codegen(); 594 | Value *R = RHS->codegen(); 595 | if (!L || !R) 596 | return nullptr; 597 | 598 | switch (Op) { 599 | case '+': 600 | return Builder.CreateFAdd(L, R, "addtmp"); 601 | case '-': 602 | return Builder.CreateFSub(L, R, "subtmp"); 603 | case '*': 604 | return Builder.CreateFMul(L, R, "multmp"); 605 | case '<': 606 | L = Builder.CreateFCmpULT(L, R, "cmptmp"); 607 | // Convert bool 0/1 to double 0.0 or 1.0 608 | return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); 609 | default: 610 | return LogErrorV("invalid binary operator"); 611 | } 612 | } 613 | 614 | Value *CallExprAST::codegen() { 615 | // Look up the name in the global module table. 616 | Function *CalleeF = getFunction(Callee); 617 | if (!CalleeF) 618 | return LogErrorV("Unknown function referenced"); 619 | 620 | // If argument mismatch error. 621 | if (CalleeF->arg_size() != Args.size()) 622 | return LogErrorV("Incorrect # arguments passed"); 623 | 624 | std::vector ArgsV; 625 | for (unsigned i = 0, e = static_cast(Args.size()); i != e; ++i) { 626 | ArgsV.push_back(Args[i]->codegen()); 627 | if (!ArgsV.back()) 628 | return nullptr; 629 | } 630 | 631 | return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); 632 | } 633 | 634 | // if 语句的代码生成 635 | Value *IfExprAST::codegen() { 636 | Value *CondV = Cond->codegen(); 637 | if (!CondV) 638 | return nullptr; 639 | 640 | // Convert condition to a bool by comparing non-equal to 0.0. 641 | //返回一位的bool值 642 | CondV = Builder.CreateFCmpONE( 643 | CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); 644 | 645 | //获取当前正在构建的function对象,构建器当前的BB的"父",当前块嵌入的函数 646 | Function *TheFunction = Builder.GetInsertBlock()->getParent(); 647 | 648 | // Create blocks for the then and else cases. Insert the 'then' block at the 649 | // end of the function. 650 | // 构造函数会自动将新块插入到函数中 651 | BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); 652 | BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); 653 | 654 | BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); 655 | 656 | //根据条件创建条件分支 657 | Builder.CreateCondBr(CondV, ThenBB, ElseBB); 658 | 659 | // Emit then value.现在then 块是空的 660 | // 设置代码块的插入点,后面插入代码会根据此插入点插入代码块 661 | Builder.SetInsertPoint(ThenBB); 662 | 663 | Value *ThenV = Then->codegen(); 664 | if (!ThenV) 665 | return nullptr; 666 | // 为了完成“then”块 667 | // 我们为合并块创建了一个无条件分支,llvm需要一个控制流来终止所有的基本块 668 | Builder.CreateBr(MergeBB); 669 | // Codegen of 'Then' can change the current block, update ThenBB for the PHI. 670 | //这一句话非常重要,需要获取phi节点的最新值 671 | //需要在Then生成代码之后,更新ThenBB的代码块 672 | ThenBB = Builder.GetInsertBlock(); 673 | 674 | // Emit else block. 675 | // 将else块加入到函数中 676 | TheFunction->getBasicBlockList().push_back(ElseBB); 677 | //将插入点设置到ElseBB之后 678 | Builder.SetInsertPoint(ElseBB); 679 | 680 | Value *ElseV = Else->codegen(); 681 | if (!ElseV) 682 | return nullptr; 683 | 684 | Builder.CreateBr(MergeBB); 685 | // Codegen of 'Else' can change the current block, update ElseBB for the PHI. 686 | ElseBB = Builder.GetInsertBlock(); 687 | 688 | // Emit merge block. 689 | // 将merge块添加到Function对象,之前是浮动的 690 | TheFunction->getBasicBlockList().push_back(MergeBB); 691 | //更改插入点 692 | Builder.SetInsertPoint(MergeBB); 693 | //创建phi节点,这个不知道啥意思,也是一个value 694 | PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); 695 | //前面的创建条件分支和这里的phi节点有何关系 696 | //phi节点如何知道该进入哪个块,以返回对应块的值 697 | PN->addIncoming(ThenV, ThenBB); 698 | PN->addIncoming(ElseV, ElseBB); 699 | return PN; 700 | } 701 | 702 | // Output for-loop as: 703 | // ... 704 | // start = startexpr 705 | // goto loop 706 | // loop: 707 | // variable = phi [start, loopheader], [nextvariable, loopend] 708 | // ... 709 | // bodyexpr 710 | // ... 711 | // loopend: 712 | // step = stepexpr 713 | // nextvariable = variable + step 714 | // endcond = endexpr 715 | // br endcond, loop, endloop 716 | // outloop: 717 | Value *ForExprAST::codegen() { 718 | // Emit the start code first, without 'variable' in scope. 719 | Value *StartVal = Start->codegen(); 720 | if (!StartVal) 721 | return nullptr; 722 | 723 | // Make the new basic block for the loop header, inserting after current 724 | // block. 725 | Function *TheFunction = Builder.GetInsertBlock()->getParent(); 726 | // 启动循环体的块,进入到循环,start表达式生成的BB 727 | BasicBlock *PreheaderBB = Builder.GetInsertBlock(); 728 | // 循环体内部的块 729 | BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); 730 | 731 | // Insert an explicit fall through from the current block to the LoopBB. 732 | // 从cur block(PreheaderBB)到LoopBB之间创建一个分支 733 | Builder.CreateBr(LoopBB); 734 | 735 | // Start insertion in LoopBB. 736 | // 将代码插入点更换到LoopBB块的末尾 737 | Builder.SetInsertPoint(LoopBB); 738 | 739 | // Start the PHI node with an entry for Start. 740 | PHINode *Variable = 741 | Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); 742 | // 循环变量赋值初始值 743 | Variable->addIncoming(StartVal, PreheaderBB); 744 | 745 | // Within the loop, the variable is defined equal to the PHI node. If it 746 | // shadows an existing variable, we have to restore it, so save it now. 747 | Value *OldVal = NamedValues[VarName]; 748 | // 包含函数参数和循环变量,将现在循环变量值加入其中 749 | NamedValues[VarName] = Variable; 750 | 751 | // Emit the body of the loop. This, like any other expr, can change the 752 | // current BB. Note that we ignore the value computed by the body, but don't 753 | // allow an error. 754 | // 循环变量有了初始状态,就可以为循环体生成代码了 755 | if (!Body->codegen()) 756 | return nullptr; 757 | 758 | // Emit the step value. 759 | Value *StepVal = nullptr; 760 | if (Step) { 761 | StepVal = Step->codegen(); 762 | if (!StepVal) 763 | return nullptr; 764 | } else { 765 | // If not specified, use 1.0. 766 | // 默认步长为1 767 | StepVal = ConstantFP::get(TheContext, APFloat(1.0)); 768 | } 769 | 770 | //计算下一次循环变量的值 771 | Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); 772 | 773 | // Compute the end condition. 774 | Value *EndCond = End->codegen(); 775 | if (!EndCond) 776 | return nullptr; 777 | 778 | // Convert condition to a bool by comparing non-equal to 0.0. 779 | EndCond = Builder.CreateFCmpONE( 780 | EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); 781 | 782 | // Create the "after loop" block and insert it. 783 | // 这个block是 End->codegen()时生成的 784 | BasicBlock *LoopEndBB = Builder.GetInsertBlock(); 785 | //循环结束后的一个代码块 786 | BasicBlock *AfterBB = 787 | BasicBlock::Create(TheContext, "afterloop", TheFunction); 788 | 789 | // Insert the conditional branch into the end of LoopEndBB. 790 | Builder.CreateCondBr(EndCond, LoopBB, AfterBB); 791 | 792 | // Any new code will be inserted in AfterBB. 793 | Builder.SetInsertPoint(AfterBB); 794 | 795 | // Add a new entry to the PHI node for the backedge. 796 | // 将更新的循环变量添加到循环phi节点 797 | Variable->addIncoming(NextVar, LoopEndBB); 798 | 799 | // Restore the unshadowed variable. 800 | if (OldVal) 801 | NamedValues[VarName] = OldVal; 802 | else 803 | NamedValues.erase(VarName); 804 | 805 | // for expr always returns 0.0. 806 | return Constant::getNullValue(Type::getDoubleTy(TheContext)); 807 | } 808 | 809 | Function *PrototypeAST::codegen() { 810 | // Make the function type: double(double,double) etc. 811 | std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); 812 | FunctionType *FT = 813 | FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); 814 | 815 | Function *F = 816 | Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); 817 | 818 | // Set names for all arguments. 819 | unsigned Idx = 0; 820 | for (auto &Arg : F->args()) 821 | Arg.setName(Args[Idx++]); 822 | 823 | return F; 824 | } 825 | 826 | Function *FunctionAST::codegen() { 827 | // Transfer ownership of the prototype to the FunctionProtos map, but keep a 828 | // reference to it for use below. 829 | auto &P = *Proto; 830 | FunctionProtos[Proto->getName()] = std::move(Proto); 831 | Function *TheFunction = getFunction(P.getName()); 832 | if (!TheFunction) 833 | return nullptr; 834 | 835 | // Create a new basic block to start insertion into. 836 | BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); 837 | Builder.SetInsertPoint(BB); 838 | 839 | // Record the function arguments in the NamedValues map. 840 | NamedValues.clear(); 841 | for (auto &Arg : TheFunction->args()) 842 | NamedValues[Arg.getName()] = &Arg; 843 | 844 | if (Value *RetVal = Body->codegen()) { 845 | // Finish off the function. 846 | Builder.CreateRet(RetVal); 847 | 848 | // Validate the generated code, checking for consistency. 849 | verifyFunction(*TheFunction); 850 | 851 | // Run the optimizer on the function. 852 | TheFPM->run(*TheFunction); 853 | 854 | return TheFunction; 855 | } 856 | 857 | // Error reading body, remove function. 858 | TheFunction->eraseFromParent(); 859 | return nullptr; 860 | } 861 | 862 | //===----------------------------------------------------------------------===// 863 | // Top-Level parsing and JIT Driver 864 | //===----------------------------------------------------------------------===// 865 | 866 | static void InitializeModuleAndPassManager() { 867 | // Open a new module. 868 | TheModule = llvm::make_unique("my cool jit", TheContext); 869 | TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); 870 | 871 | // Create a new pass manager attached to it. 872 | TheFPM = llvm::make_unique(TheModule.get()); 873 | 874 | // Do simple "peephole" optimizations and bit-twiddling optzns. 875 | TheFPM->add(createInstructionCombiningPass()); 876 | // Reassociate expressions. 877 | TheFPM->add(createReassociatePass()); 878 | // Eliminate Common SubExpressions. 879 | TheFPM->add(createGVNPass()); 880 | // Simplify the control flow graph (deleting unreachable blocks, etc). 881 | TheFPM->add(createCFGSimplificationPass()); 882 | 883 | TheFPM->doInitialization(); 884 | } 885 | 886 | static void HandleDefinition() { 887 | if (auto FnAST = ParseDefinition()) { 888 | if (auto *FnIR = FnAST->codegen()) { 889 | fprintf(stderr, "Read function definition:"); 890 | FnIR->print(errs()); 891 | fprintf(stderr, "\n"); 892 | TheJIT->addModule(std::move(TheModule)); 893 | InitializeModuleAndPassManager(); 894 | } 895 | } else { 896 | // Skip token for error recovery. 897 | getNextToken(); 898 | } 899 | } 900 | 901 | static void HandleExtern() { 902 | if (auto ProtoAST = ParseExtern()) { 903 | if (auto *FnIR = ProtoAST->codegen()) { 904 | fprintf(stderr, "Read extern: "); 905 | FnIR->print(errs()); 906 | fprintf(stderr, "\n"); 907 | FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); 908 | } 909 | } else { 910 | // Skip token for error recovery. 911 | getNextToken(); 912 | } 913 | } 914 | 915 | static void HandleTopLevelExpression() { 916 | // Evaluate a top-level expression into an anonymous function. 917 | if (auto FnAST = ParseTopLevelExpr()) { 918 | if (FnAST->codegen()) { 919 | // JIT the module containing the anonymous expression, keeping a handle so 920 | // we can free it later. 921 | auto H = TheJIT->addModule(std::move(TheModule)); 922 | InitializeModuleAndPassManager(); 923 | 924 | // Search the JIT for the __anon_expr symbol. 925 | auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); 926 | assert(ExprSymbol && "Function not found"); 927 | 928 | // Get the symbol's address and cast it to the right type (takes no 929 | // arguments, returns a double) so we can call it as a native function. 930 | double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); 931 | fprintf(stderr, "Evaluated to %f\n", FP()); 932 | 933 | // Delete the anonymous expression module from the JIT. 934 | TheJIT->removeModule(H); 935 | } 936 | } else { 937 | // Skip token for error recovery. 938 | getNextToken(); 939 | } 940 | } 941 | 942 | /// top ::= definition | external | expression | ';' 943 | static void MainLoop() { 944 | while (true) { 945 | fprintf(stderr, "ready> "); 946 | switch (CurTok) { 947 | case tok_eof: 948 | return; 949 | case ';': // ignore top-level semicolons. 950 | getNextToken(); 951 | break; 952 | case tok_def: 953 | HandleDefinition(); 954 | break; 955 | case tok_extern: 956 | HandleExtern(); 957 | break; 958 | default: 959 | HandleTopLevelExpression(); 960 | break; 961 | } 962 | } 963 | } 964 | 965 | //===----------------------------------------------------------------------===// 966 | // "Library" functions that can be "extern'd" from user code. 967 | //===----------------------------------------------------------------------===// 968 | 969 | #ifdef _WIN32 970 | #define DLLEXPORT __declspec(dllexport) 971 | #else 972 | #define DLLEXPORT 973 | #endif 974 | 975 | /// putchard - putchar that takes a double and returns 0. 976 | extern "C" DLLEXPORT double putchard(double X) { 977 | fputc((char)X, stderr); 978 | return 0; 979 | } 980 | 981 | /// printd - printf that takes a double prints it as "%f\n", returning 0. 982 | extern "C" DLLEXPORT double printd(double X) { 983 | fprintf(stderr, "%f\n", X); 984 | return 0; 985 | } 986 | 987 | //===----------------------------------------------------------------------===// 988 | // Main driver code. 989 | //===----------------------------------------------------------------------===// 990 | 991 | int main() { 992 | InitializeNativeTarget(); 993 | InitializeNativeTargetAsmPrinter(); 994 | InitializeNativeTargetAsmParser(); 995 | 996 | // Install standard binary operators. 997 | // 1 is lowest precedence. 998 | BinopPrecedence['<'] = 10; 999 | BinopPrecedence['+'] = 20; 1000 | BinopPrecedence['-'] = 20; 1001 | BinopPrecedence['*'] = 40; // highest. 1002 | 1003 | // Prime the first token. 1004 | fprintf(stderr, "ready(chapter05)> "); 1005 | getNextToken(); 1006 | 1007 | TheJIT = llvm::make_unique(); 1008 | 1009 | InitializeModuleAndPassManager(); 1010 | 1011 | // Run the main "interpreter loop" now. 1012 | MainLoop(); 1013 | 1014 | return 0; 1015 | } -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter06/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Analysis 3 | Core 4 | ExecutionEngine 5 | InstCombine 6 | Object 7 | OrcJIT 8 | RuntimeDyld 9 | ScalarOpts 10 | Support 11 | native 12 | ) 13 | 14 | add_kaleidoscope_chapter(Kaleidoscope-Ch6 15 | toy.cpp 16 | ) 17 | 18 | export_executable_symbols(Kaleidoscope-Ch6) -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter06/toy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cyoung on 18-10-9. 3 | // 4 | 5 | #include "../../include/KaleidoscopeJIT.h" 6 | #include "llvm/ADT/APFloat.h" 7 | #include "llvm/ADT/STLExtras.h" 8 | #include "llvm/IR/BasicBlock.h" 9 | #include "llvm/IR/Constants.h" 10 | #include "llvm/IR/DerivedTypes.h" 11 | #include "llvm/IR/Function.h" 12 | #include "llvm/IR/IRBuilder.h" 13 | #include "llvm/IR/Instructions.h" 14 | #include "llvm/IR/LLVMContext.h" 15 | #include "llvm/IR/LegacyPassManager.h" 16 | #include "llvm/IR/Module.h" 17 | #include "llvm/IR/Type.h" 18 | #include "llvm/IR/Verifier.h" 19 | #include "llvm/Support/TargetSelect.h" 20 | #include "llvm/Target/TargetMachine.h" 21 | #include "llvm/Transforms/InstCombine/InstCombine.h" 22 | #include "llvm/Transforms/Scalar.h" 23 | #include "llvm/Transforms/Scalar/GVN.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using namespace llvm; 37 | using namespace llvm::orc; 38 | 39 | //===----------------------------------------------------------------------===// 40 | // Lexer 41 | //===----------------------------------------------------------------------===// 42 | 43 | // The lexer returns tokens [0-255] if it is an unknown character, otherwise one 44 | // of these for known things. 45 | enum Token { 46 | tok_eof = -1, 47 | 48 | // commands 49 | tok_def = -2, 50 | tok_extern = -3, 51 | 52 | // primary 53 | tok_identifier = -4, 54 | tok_number = -5, 55 | 56 | // control 57 | tok_if = -6, 58 | tok_then = -7, 59 | tok_else = -8, 60 | tok_for = -9, 61 | tok_in = -10, 62 | 63 | // operators,新的二元,一元操作符 64 | tok_binary = -11, 65 | tok_unary = -12 66 | }; 67 | 68 | static std::string IdentifierStr; // Filled in if tok_identifier 69 | static double NumVal; // Filled in if tok_number 70 | 71 | /// gettok - Return the next token from standard input. 72 | static int gettok() { 73 | // 这里的static是关键,只有第一次执行gettok才会初始化LastChar 74 | // 后面gettok调用不会再初始化,而是继续保留上次的结果 75 | static int LastChar = ' '; 76 | 77 | // Skip any whitespace. 78 | while (isspace(LastChar)) 79 | LastChar = getchar(); 80 | 81 | if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* 82 | IdentifierStr = LastChar; 83 | while (isalnum((LastChar = getchar()))) 84 | IdentifierStr += LastChar; 85 | 86 | if (IdentifierStr == "def") 87 | return tok_def; 88 | if (IdentifierStr == "extern") 89 | return tok_extern; 90 | if (IdentifierStr == "if") 91 | return tok_if; 92 | if (IdentifierStr == "then") 93 | return tok_then; 94 | if (IdentifierStr == "else") 95 | return tok_else; 96 | if (IdentifierStr == "for") 97 | return tok_for; 98 | if (IdentifierStr == "in") 99 | return tok_in; 100 | if (IdentifierStr == "binary") 101 | return tok_binary; 102 | if (IdentifierStr == "unary") 103 | return tok_unary; 104 | return tok_identifier; 105 | } 106 | 107 | if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ 108 | std::string NumStr; 109 | do { 110 | NumStr += LastChar; 111 | LastChar = getchar(); 112 | } while (isdigit(LastChar) || LastChar == '.'); 113 | 114 | NumVal = strtod(NumStr.c_str(), nullptr); 115 | return tok_number; 116 | } 117 | 118 | if (LastChar == '#') { 119 | // Comment until end of line. 120 | do 121 | LastChar = getchar(); 122 | while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); 123 | 124 | if (LastChar != EOF) 125 | return gettok(); 126 | } 127 | 128 | // Check for end of file. Don't eat the EOF. 129 | if (LastChar == EOF) 130 | return tok_eof; 131 | 132 | // Otherwise, just return the character as its ascii value. 133 | int ThisChar = LastChar; 134 | // LastChar指向下一个字符,供下一次gettok调用使用 135 | // LastChar为静态变量,会保存到下一次调用 136 | LastChar = getchar(); 137 | return ThisChar; 138 | } 139 | 140 | //===----------------------------------------------------------------------===// 141 | // Abstract Syntax Tree (aka Parse Tree) 142 | //===----------------------------------------------------------------------===// 143 | 144 | namespace { 145 | 146 | /// ExprAST - Base class for all expression nodes. 147 | class ExprAST { 148 | public: 149 | virtual ~ExprAST() = default; 150 | 151 | virtual Value *codegen() = 0; 152 | }; 153 | 154 | /// NumberExprAST - Expression class for numeric literals like "1.0". 155 | class NumberExprAST : public ExprAST { 156 | double Val; 157 | 158 | public: 159 | NumberExprAST(double Val) : Val(Val) {} 160 | 161 | Value *codegen() override; 162 | }; 163 | 164 | /// VariableExprAST - Expression class for referencing a variable, like "a". 165 | class VariableExprAST : public ExprAST { 166 | std::string Name; 167 | 168 | public: 169 | VariableExprAST(std::string Name) : Name(std::move(Name)) {} 170 | 171 | Value *codegen() override; 172 | }; 173 | 174 | /// UnaryExprAST - Expression class for a unary operator. 175 | class UnaryExprAST : public ExprAST { 176 | char Opcode; 177 | //一元表达式对应的一个操作数, 它可以是一个表达式 178 | std::unique_ptr Operand; 179 | 180 | public: 181 | UnaryExprAST(char Opcode, std::unique_ptr Operand) 182 | : Opcode(Opcode), Operand(std::move(Operand)) {} 183 | 184 | Value *codegen() override; 185 | }; 186 | 187 | /// BinaryExprAST - Expression class for a binary operator. 188 | class BinaryExprAST : public ExprAST { 189 | char Op; 190 | std::unique_ptr LHS, RHS; 191 | 192 | public: 193 | BinaryExprAST(char Op, std::unique_ptr LHS, 194 | std::unique_ptr RHS) 195 | : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} 196 | 197 | Value *codegen() override; 198 | }; 199 | 200 | /// CallExprAST - Expression class for function calls. 201 | class CallExprAST : public ExprAST { 202 | std::string Callee; 203 | std::vector> Args; 204 | 205 | public: 206 | CallExprAST(std::string Callee, 207 | std::vector> Args) 208 | : Callee(std::move(Callee)), Args(std::move(Args)) {} 209 | 210 | Value *codegen() override; 211 | }; 212 | 213 | /// IfExprAST - Expression class for if/then/else. 214 | class IfExprAST : public ExprAST { 215 | std::unique_ptr Cond, Then, Else; 216 | 217 | public: 218 | IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, 219 | std::unique_ptr Else) 220 | : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} 221 | 222 | Value *codegen() override; 223 | }; 224 | 225 | /// ForExprAST - Expression class for for/in. 226 | class ForExprAST : public ExprAST { 227 | std::string VarName; 228 | std::unique_ptr Start, End, Step, Body; 229 | 230 | public: 231 | ForExprAST(std::string VarName, std::unique_ptr Start, 232 | std::unique_ptr End, std::unique_ptr Step, 233 | std::unique_ptr Body) 234 | : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), 235 | Step(std::move(Step)), Body(std::move(Body)) {} 236 | 237 | Value *codegen() override; 238 | }; 239 | 240 | /// PrototypeAST - This class represents the "prototype" for a function, 241 | /// which captures its name, and its argument names (thus implicitly the number 242 | /// of arguments the function takes), as well as if it is an operator. 243 | //扩展为自定义运算符 244 | class PrototypeAST { 245 | std::string Name; 246 | std::vector Args; 247 | bool IsOperator; 248 | unsigned Precedence; // Precedence if a binary op. 249 | 250 | public: 251 | PrototypeAST(std::string Name, std::vector Args, 252 | bool IsOperator = false, unsigned Prec = 0) 253 | : Name(std::move(Name)), Args(std::move(Args)), IsOperator(IsOperator), 254 | Precedence(Prec) {} 255 | 256 | Function *codegen(); 257 | const std::string &getName() const { return Name; } 258 | 259 | bool isUnaryOp() const { return IsOperator && Args.size() == 1; } 260 | bool isBinaryOp() const { return IsOperator && Args.size() == 2; } 261 | 262 | char getOperatorName() const { 263 | assert(isUnaryOp() || isBinaryOp()); 264 | return Name[Name.size() - 1]; 265 | } 266 | 267 | unsigned getBinaryPrecedence() const { return Precedence; } 268 | }; 269 | 270 | /// FunctionAST - This class represents a function definition itself. 271 | class FunctionAST { 272 | std::unique_ptr Proto; 273 | std::unique_ptr Body; 274 | 275 | public: 276 | FunctionAST(std::unique_ptr Proto, 277 | std::unique_ptr Body) 278 | : Proto(std::move(Proto)), Body(std::move(Body)) {} 279 | 280 | Function *codegen(); 281 | }; 282 | 283 | } // end anonymous namespace 284 | 285 | //===----------------------------------------------------------------------===// 286 | // Parser 287 | //===----------------------------------------------------------------------===// 288 | 289 | /// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current 290 | /// token the parser is looking at. getNextToken reads another token from the 291 | /// lexer and updates CurTok with its results. 292 | static int CurTok; 293 | static int getNextToken() { return CurTok = gettok(); } 294 | 295 | /// BinopPrecedence - This holds the precedence for each binary operator that is 296 | /// defined. 297 | static std::map BinopPrecedence; 298 | 299 | /// GetTokPrecedence - Get the precedence of the pending binary operator token. 300 | static int GetTokPrecedence() { 301 | if (!isascii(CurTok)) 302 | return -1; 303 | 304 | // Make sure it's a declared binop. 305 | int TokPrec = BinopPrecedence[CurTok]; 306 | if (TokPrec <= 0) 307 | return -1; 308 | return TokPrec; 309 | } 310 | 311 | /// Error* - These are little helper functions for error handling. 312 | std::unique_ptr LogError(const char *Str) { 313 | fprintf(stderr, "Error: %s\n", Str); 314 | return nullptr; 315 | } 316 | 317 | std::unique_ptr LogErrorP(const char *Str) { 318 | LogError(Str); 319 | return nullptr; 320 | } 321 | 322 | static std::unique_ptr ParseExpression(); 323 | 324 | /// numberexpr ::= number 325 | static std::unique_ptr ParseNumberExpr() { 326 | auto Result = llvm::make_unique(NumVal); 327 | getNextToken(); // consume the number 328 | return std::move(Result); 329 | } 330 | 331 | /// parenexpr ::= '(' expression ')' 332 | static std::unique_ptr ParseParenExpr() { 333 | getNextToken(); // eat (. 334 | auto V = ParseExpression(); 335 | if (!V) 336 | return nullptr; 337 | 338 | if (CurTok != ')') 339 | return LogError("expected ')'"); 340 | getNextToken(); // eat ). 341 | return V; 342 | } 343 | 344 | /// identifierexpr 345 | /// ::= identifier 346 | /// ::= identifier '(' expression* ')' 347 | static std::unique_ptr ParseIdentifierExpr() { 348 | std::string IdName = IdentifierStr; 349 | 350 | getNextToken(); // eat identifier. 351 | 352 | if (CurTok != '(') // Simple variable ref. 353 | return llvm::make_unique(IdName); 354 | 355 | // Call. 356 | getNextToken(); // eat ( 357 | std::vector> Args; 358 | if (CurTok != ')') { 359 | while (true) { 360 | if (auto Arg = ParseExpression()) 361 | Args.push_back(std::move(Arg)); 362 | else 363 | return nullptr; 364 | 365 | if (CurTok == ')') 366 | break; 367 | 368 | if (CurTok != ',') 369 | return LogError("Expected ')' or ',' in argument list"); 370 | getNextToken(); 371 | } 372 | } 373 | 374 | // Eat the ')'. 375 | getNextToken(); 376 | 377 | return llvm::make_unique(IdName, std::move(Args)); 378 | } 379 | 380 | /// ifexpr ::= 'if' expression 'then' expression 'else' expression 381 | /// 仅仅作为 ParsePrimary 的一部分 382 | static std::unique_ptr ParseIfExpr() { 383 | getNextToken(); // eat the if. 384 | 385 | // condition. 386 | auto Cond = ParseExpression(); 387 | if (!Cond) 388 | return nullptr; 389 | 390 | if (CurTok != tok_then) 391 | return LogError("expected then"); 392 | getNextToken(); // eat the then 393 | 394 | auto Then = ParseExpression(); 395 | if (!Then) 396 | return nullptr; 397 | 398 | if (CurTok != tok_else) 399 | return LogError("expected else"); 400 | 401 | getNextToken(); 402 | 403 | auto Else = ParseExpression(); 404 | if (!Else) 405 | return nullptr; 406 | 407 | return llvm::make_unique(std::move(Cond), std::move(Then), 408 | std::move(Else)); 409 | } 410 | 411 | /// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression 412 | /// 仅仅作为 ParsePrimary 的一部分 413 | static std::unique_ptr ParseForExpr() { 414 | getNextToken(); // eat the for. 415 | 416 | if (CurTok != tok_identifier) 417 | return LogError("expected identifier after for"); 418 | 419 | std::string IdName = IdentifierStr; 420 | getNextToken(); // eat identifier. 421 | 422 | if (CurTok != '=') 423 | return LogError("expected '=' after for"); 424 | getNextToken(); // eat '='. 425 | 426 | auto Start = ParseExpression(); 427 | if (!Start) 428 | return nullptr; 429 | if (CurTok != ',') 430 | return LogError("expected ',' after for start value"); 431 | getNextToken(); 432 | 433 | auto End = ParseExpression(); 434 | if (!End) 435 | return nullptr; 436 | 437 | // The step value is optional. 438 | std::unique_ptr Step; 439 | if (CurTok == ',') { 440 | getNextToken(); 441 | Step = ParseExpression(); 442 | if (!Step) 443 | return nullptr; 444 | } 445 | 446 | if (CurTok != tok_in) 447 | return LogError("expected 'in' after for"); 448 | getNextToken(); // eat 'in'. 449 | 450 | auto Body = ParseExpression(); 451 | if (!Body) 452 | return nullptr; 453 | 454 | return llvm::make_unique(IdName, std::move(Start), std::move(End), 455 | std::move(Step), std::move(Body)); 456 | } 457 | 458 | /// primary 459 | /// ::= identifierexpr 460 | /// ::= numberexpr 461 | /// ::= parenexpr 462 | /// ::= ifexpr 463 | /// ::= forexpr 464 | static std::unique_ptr ParsePrimary() { 465 | switch (CurTok) { 466 | default: 467 | return LogError("unknown token when expecting an expression"); 468 | case tok_identifier: 469 | return ParseIdentifierExpr(); 470 | case tok_number: 471 | return ParseNumberExpr(); 472 | case '(': 473 | return ParseParenExpr(); 474 | case tok_if: 475 | return ParseIfExpr(); 476 | case tok_for: 477 | return ParseForExpr(); 478 | } 479 | } 480 | 481 | /// unary 482 | /// ::= primary 483 | /// ::= '!' unary 484 | //这个函数包含了主表达式解析和一元表达式的解析 485 | //这里解析的一元操作符是在操作符定义好的前提下,程序调用一元操作符时的解析 486 | //和 ParsePrototype 有本质的区别,这个是解析操作符的定义 487 | static std::unique_ptr ParseUnary() { 488 | // If the current token is not an operator, it must be a primary expr. 489 | //这个,:什么意思? 逗号不能作为一元操作符,进入到主表达式会报错 490 | if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') 491 | return ParsePrimary(); 492 | 493 | // If this is a unary operator, read it. 494 | int Opc = CurTok; 495 | getNextToken(); 496 | //可以处理连续多个一元运算符 497 | if (auto Operand = ParseUnary()) 498 | return llvm::make_unique(Opc, std::move(Operand)); 499 | return nullptr; 500 | } 501 | 502 | /// binoprhs 503 | /// ::= ('+' unary)* 504 | static std::unique_ptr ParseBinOpRHS(int ExprPrec, 505 | std::unique_ptr LHS) { 506 | // If this is a binop, find its precedence. 507 | while (true) { 508 | int TokPrec = GetTokPrecedence(); 509 | 510 | // If this is a binop that binds at least as tightly as the current binop, 511 | // consume it, otherwise we are done. 512 | if (TokPrec < ExprPrec) 513 | return LHS; 514 | 515 | // Okay, we know this is a binop. 516 | int BinOp = CurTok; 517 | getNextToken(); // eat binop 518 | 519 | // Parse the unary expression after the binary operator. 520 | auto RHS = ParseUnary(); 521 | if (!RHS) 522 | return nullptr; 523 | 524 | // If BinOp binds less tightly with RHS than the operator after RHS, let 525 | // the pending operator take RHS as its LHS. 526 | int NextPrec = GetTokPrecedence(); 527 | if (TokPrec < NextPrec) { 528 | RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); 529 | if (!RHS) 530 | return nullptr; 531 | } 532 | 533 | // Merge LHS/RHS. 534 | LHS = 535 | llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); 536 | } 537 | } 538 | 539 | /// expression 540 | /// ::= unary binoprhs 541 | /// 最顶层的表达式,ParseUnary其次,ParsePrimary次之 542 | static std::unique_ptr ParseExpression() { 543 | auto LHS = ParseUnary(); 544 | if (!LHS) 545 | return nullptr; 546 | 547 | return ParseBinOpRHS(0, std::move(LHS)); 548 | } 549 | 550 | /// prototype 551 | /// ::= id '(' id* ')' 552 | /// ::= binary LETTER number? (id, id) 553 | /// ::= unary LETTER (id) 554 | // 解析函数声明,或自定义的一元,二元操作符 555 | //这里的操作符解析,主要解析操作符的定义(作为一个特殊的函数处理) 556 | static std::unique_ptr ParsePrototype() { 557 | std::string FnName; 558 | //现在原型的类型:函数声明?一元操作符?二元运算符? 559 | unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. 560 | unsigned BinaryPrecedence = 30; 561 | 562 | switch (CurTok) { 563 | default: 564 | return LogErrorP("Expected function name in prototype"); 565 | case tok_identifier: 566 | FnName = IdentifierStr; 567 | Kind = 0; 568 | getNextToken(); 569 | break; 570 | case tok_unary: 571 | getNextToken(); // eat "unary" 572 | //下一个必须是自定义操作符,操作符的CurTok是返回对应的ascii码,不能出现关键字等情况 573 | if (!isascii(CurTok)) 574 | return LogErrorP("Expected unary operator"); 575 | FnName = "unary"; 576 | FnName += (char)CurTok; 577 | Kind = 1; 578 | getNextToken(); //eat 一元操作符 579 | break; 580 | case tok_binary: 581 | getNextToken(); //eat "binary" 582 | if (!isascii(CurTok)) 583 | return LogErrorP("Expected binary operator"); 584 | FnName = "binary"; 585 | FnName += (char)CurTok; 586 | Kind = 2; 587 | getNextToken(); //eat二元运算符 588 | 589 | // Read the precedence if present. 590 | //只有二元运算符才会有优先级 591 | if (CurTok == tok_number) { 592 | if (NumVal < 1 || NumVal > 100) 593 | return LogErrorP("Invalid precedence: must be 1..100"); 594 | BinaryPrecedence = (unsigned)NumVal; 595 | getNextToken(); 596 | } 597 | break; 598 | } 599 | 600 | if (CurTok != '(') 601 | return LogErrorP("Expected '(' in prototype"); 602 | 603 | std::vector ArgNames; 604 | while (getNextToken() == tok_identifier) 605 | ArgNames.push_back(IdentifierStr); 606 | if (CurTok != ')') 607 | return LogErrorP("Expected ')' in prototype"); 608 | 609 | // success. 610 | getNextToken(); // eat ')'. 611 | 612 | // Verify right number of names for operator. 613 | // 这个很妙啊 614 | if (Kind && ArgNames.size() != Kind) 615 | return LogErrorP("Invalid number of operands for operator"); 616 | 617 | return llvm::make_unique(FnName, ArgNames, Kind != 0, 618 | BinaryPrecedence); 619 | } 620 | 621 | /// definition ::= 'def' prototype expression 622 | static std::unique_ptr ParseDefinition() { 623 | getNextToken(); // eat def. 624 | auto Proto = ParsePrototype(); 625 | if (!Proto) 626 | return nullptr; 627 | 628 | if (auto E = ParseExpression()) 629 | return llvm::make_unique(std::move(Proto), std::move(E)); 630 | return nullptr; 631 | } 632 | 633 | /// toplevelexpr ::= expression 634 | static std::unique_ptr ParseTopLevelExpr() { 635 | if (auto E = ParseExpression()) { 636 | // Make an anonymous proto. 637 | auto Proto = llvm::make_unique("__anon_expr", 638 | std::vector()); 639 | return llvm::make_unique(std::move(Proto), std::move(E)); 640 | } 641 | return nullptr; 642 | } 643 | 644 | /// external ::= 'extern' prototype 645 | static std::unique_ptr ParseExtern() { 646 | getNextToken(); // eat extern. 647 | return ParsePrototype(); 648 | } 649 | 650 | //===----------------------------------------------------------------------===// 651 | // Code Generation 652 | //===----------------------------------------------------------------------===// 653 | 654 | static LLVMContext TheContext; 655 | static IRBuilder<> Builder(TheContext); 656 | static std::unique_ptr TheModule; 657 | static std::map NamedValues; 658 | static std::unique_ptr TheFPM; 659 | static std::unique_ptr TheJIT; 660 | static std::map> FunctionProtos; 661 | 662 | Value *LogErrorV(const char *Str) { 663 | LogError(Str); 664 | return nullptr; 665 | } 666 | 667 | // 先去TheModule中找,再在FunctionProtos中生成 668 | Function *getFunction(std::string Name) { 669 | // First, see if the function has already been added to the current module. 670 | if (auto *F = TheModule->getFunction(Name)) 671 | return F; 672 | 673 | // If not, check whether we can codegen the declaration from some existing 674 | // prototype. 675 | auto FI = FunctionProtos.find(Name); 676 | // 677 | if (FI != FunctionProtos.end()) 678 | return FI->second->codegen(); 679 | 680 | // If no existing prototype exists, return null. 681 | return nullptr; 682 | } 683 | 684 | Value *NumberExprAST::codegen() { 685 | return ConstantFP::get(TheContext, APFloat(Val)); 686 | } 687 | 688 | Value *VariableExprAST::codegen() { 689 | // Look this variable up in the function. 690 | Value *V = NamedValues[Name]; 691 | if (!V) 692 | return LogErrorV("Unknown variable name"); 693 | return V; 694 | } 695 | 696 | // 一元运算符也是参数个数为1的函数:函数名:"unary" +Opcode 697 | Value *UnaryExprAST::codegen() { 698 | //计算一元表达式参数值 699 | Value *OperandV = Operand->codegen(); 700 | if (!OperandV) 701 | return nullptr; 702 | 703 | Function *F = getFunction(std::string("unary") + Opcode); 704 | if (!F) 705 | return LogErrorV("Unknown unary operator"); 706 | //调用一元表达式,计算一元表达式的值 707 | return Builder.CreateCall(F, OperandV, "unop"); 708 | } 709 | 710 | Value *BinaryExprAST::codegen() { 711 | Value *L = LHS->codegen(); 712 | Value *R = RHS->codegen(); 713 | if (!L || !R) 714 | return nullptr; 715 | 716 | switch (Op) { 717 | case '+': 718 | return Builder.CreateFAdd(L, R, "addtmp"); 719 | case '-': 720 | return Builder.CreateFSub(L, R, "subtmp"); 721 | case '*': 722 | return Builder.CreateFMul(L, R, "multmp"); 723 | case '<': 724 | L = Builder.CreateFCmpULT(L, R, "cmptmp"); 725 | // Convert bool 0/1 to double 0.0 or 1.0 726 | return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); 727 | default: 728 | break; 729 | } 730 | 731 | // 处理自定义的二元运算符 732 | // If it wasn't a builtin binary operator, it must be a user defined one. Emit 733 | // a call to it. 734 | Function *F = getFunction(std::string("binary") + Op); 735 | assert(F && "binary operator not found!"); 736 | 737 | Value *Ops[] = {L, R}; 738 | return Builder.CreateCall(F, Ops, "binop"); 739 | } 740 | 741 | Value *CallExprAST::codegen() { 742 | // Look up the name in the global module table. 743 | Function *CalleeF = getFunction(Callee); 744 | if (!CalleeF) 745 | return LogErrorV("Unknown function referenced"); 746 | 747 | // If argument mismatch error. 748 | if (CalleeF->arg_size() != Args.size()) 749 | return LogErrorV("Incorrect # arguments passed"); 750 | //计算函数所有参数的值 751 | std::vector ArgsV; 752 | for (unsigned i = 0, e = Args.size(); i != e; ++i) { 753 | ArgsV.push_back(Args[i]->codegen()); 754 | if (!ArgsV.back()) 755 | return nullptr; 756 | } 757 | //调用函数,计算值 758 | return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); 759 | } 760 | 761 | Value *IfExprAST::codegen() { 762 | Value *CondV = Cond->codegen(); 763 | if (!CondV) 764 | return nullptr; 765 | 766 | // Convert condition to a bool by comparing non-equal to 0.0. 767 | CondV = Builder.CreateFCmpONE( 768 | CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); 769 | 770 | Function *TheFunction = Builder.GetInsertBlock()->getParent(); 771 | 772 | // Create blocks for the then and else cases. Insert the 'then' block at the 773 | // end of the function. 774 | BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); 775 | BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); 776 | BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); 777 | 778 | Builder.CreateCondBr(CondV, ThenBB, ElseBB); 779 | 780 | // Emit then value. 781 | Builder.SetInsertPoint(ThenBB); 782 | 783 | Value *ThenV = Then->codegen(); 784 | if (!ThenV) 785 | return nullptr; 786 | 787 | Builder.CreateBr(MergeBB); 788 | // Codegen of 'Then' can change the current block, update ThenBB for the PHI. 789 | ThenBB = Builder.GetInsertBlock(); 790 | 791 | // Emit else block. 792 | TheFunction->getBasicBlockList().push_back(ElseBB); 793 | Builder.SetInsertPoint(ElseBB); 794 | 795 | Value *ElseV = Else->codegen(); 796 | if (!ElseV) 797 | return nullptr; 798 | 799 | Builder.CreateBr(MergeBB); 800 | // Codegen of 'Else' can change the current block, update ElseBB for the PHI. 801 | ElseBB = Builder.GetInsertBlock(); 802 | 803 | // Emit merge block. 804 | TheFunction->getBasicBlockList().push_back(MergeBB); 805 | Builder.SetInsertPoint(MergeBB); 806 | PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); 807 | 808 | PN->addIncoming(ThenV, ThenBB); 809 | PN->addIncoming(ElseV, ElseBB); 810 | return PN; 811 | } 812 | 813 | // Output for-loop as: 814 | // ... 815 | // start = startexpr 816 | // goto loop 817 | // loop: 818 | // variable = phi [start, loopheader], [nextvariable, loopend] 819 | // ... 820 | // bodyexpr 821 | // ... 822 | // loopend: 823 | // step = stepexpr 824 | // nextvariable = variable + step 825 | // endcond = endexpr 826 | // br endcond, loop, endloop 827 | // outloop: 828 | Value *ForExprAST::codegen() { 829 | // Emit the start code first, without 'variable' in scope. 830 | Value *StartVal = Start->codegen(); 831 | if (!StartVal) 832 | return nullptr; 833 | 834 | // Make the new basic block for the loop header, inserting after current 835 | // block. 836 | Function *TheFunction = Builder.GetInsertBlock()->getParent(); 837 | BasicBlock *PreheaderBB = Builder.GetInsertBlock(); 838 | BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); 839 | 840 | // Insert an explicit fall through from the current block to the LoopBB. 841 | Builder.CreateBr(LoopBB); 842 | 843 | // Start insertion in LoopBB. 844 | Builder.SetInsertPoint(LoopBB); 845 | 846 | // Start the PHI node with an entry for Start. 847 | PHINode *Variable = 848 | Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); 849 | Variable->addIncoming(StartVal, PreheaderBB); 850 | 851 | // Within the loop, the variable is defined equal to the PHI node. If it 852 | // shadows an existing variable, we have to restore it, so save it now. 853 | Value *OldVal = NamedValues[VarName]; 854 | NamedValues[VarName] = Variable; 855 | 856 | // Emit the body of the loop. This, like any other expr, can change the 857 | // current BB. Note that we ignore the value computed by the body, but don't 858 | // allow an error. 859 | if (!Body->codegen()) 860 | return nullptr; 861 | 862 | // Emit the step value. 863 | Value *StepVal = nullptr; 864 | if (Step) { 865 | StepVal = Step->codegen(); 866 | if (!StepVal) 867 | return nullptr; 868 | } else { 869 | // If not specified, use 1.0. 870 | StepVal = ConstantFP::get(TheContext, APFloat(1.0)); 871 | } 872 | 873 | Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); 874 | 875 | // Compute the end condition. 876 | Value *EndCond = End->codegen(); 877 | if (!EndCond) 878 | return nullptr; 879 | 880 | // Convert condition to a bool by comparing non-equal to 0.0. 881 | EndCond = Builder.CreateFCmpONE( 882 | EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); 883 | 884 | // Create the "after loop" block and insert it. 885 | BasicBlock *LoopEndBB = Builder.GetInsertBlock(); 886 | BasicBlock *AfterBB = 887 | BasicBlock::Create(TheContext, "afterloop", TheFunction); 888 | 889 | // Insert the conditional branch into the end of LoopEndBB. 890 | Builder.CreateCondBr(EndCond, LoopBB, AfterBB); 891 | 892 | // Any new code will be inserted in AfterBB. 893 | Builder.SetInsertPoint(AfterBB); 894 | 895 | // Add a new entry to the PHI node for the backedge. 896 | Variable->addIncoming(NextVar, LoopEndBB); 897 | 898 | // Restore the unshadowed variable. 899 | if (OldVal) 900 | NamedValues[VarName] = OldVal; 901 | else 902 | NamedValues.erase(VarName); 903 | 904 | // for expr always returns 0.0. 905 | return Constant::getNullValue(Type::getDoubleTy(TheContext)); 906 | } 907 | 908 | Function *PrototypeAST::codegen() { 909 | // Make the function type: double(double,double) etc. 910 | std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); 911 | FunctionType *FT = 912 | FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); 913 | //生成的函数会在TheModule中注册 914 | Function *F = 915 | Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); 916 | 917 | // Set names for all arguments. 918 | unsigned Idx = 0; 919 | for (auto &Arg : F->args()) 920 | Arg.setName(Args[Idx++]); 921 | 922 | return F; 923 | } 924 | 925 | Function *FunctionAST::codegen() { 926 | // Transfer ownership of the prototype to the FunctionProtos map, but keep a 927 | // reference to it for use below. 928 | auto &P = *Proto; 929 | FunctionProtos[Proto->getName()] = std::move(Proto); 930 | Function *TheFunction = getFunction(P.getName()); 931 | if (!TheFunction) 932 | return nullptr; 933 | 934 | // If this is an operator, install it. 935 | // 这里把二元操作符可以看成参数个数固定为2的函数,必函数多了优先级 936 | if (P.isBinaryOp()) 937 | BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); 938 | 939 | // Create a new basic block to start insertion into. 940 | BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); 941 | Builder.SetInsertPoint(BB); 942 | 943 | // Record the function arguments in the NamedValues map. 944 | NamedValues.clear(); 945 | for (auto &Arg : TheFunction->args()) 946 | NamedValues[Arg.getName()] = &Arg; 947 | 948 | if (Value *RetVal = Body->codegen()) { 949 | // Finish off the function. 950 | Builder.CreateRet(RetVal); 951 | 952 | // Validate the generated code, checking for consistency. 953 | verifyFunction(*TheFunction); 954 | 955 | // Run the optimizer on the function. 956 | TheFPM->run(*TheFunction); 957 | 958 | return TheFunction; 959 | } 960 | 961 | // Error reading body, remove function. 962 | TheFunction->eraseFromParent(); 963 | 964 | if (P.isBinaryOp()) 965 | BinopPrecedence.erase(P.getOperatorName()); 966 | return nullptr; 967 | } 968 | 969 | //===----------------------------------------------------------------------===// 970 | // Top-Level parsing and JIT Driver 971 | //===----------------------------------------------------------------------===// 972 | 973 | static void InitializeModuleAndPassManager() { 974 | // Open a new module. 975 | TheModule = llvm::make_unique("my cool jit", TheContext); 976 | TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); 977 | 978 | // Create a new pass manager attached to it. 979 | TheFPM = llvm::make_unique(TheModule.get()); 980 | 981 | // Do simple "peephole" optimizations and bit-twiddling optzns. 982 | TheFPM->add(createInstructionCombiningPass()); 983 | // Reassociate expressions. 984 | TheFPM->add(createReassociatePass()); 985 | // Eliminate Common SubExpressions. 986 | TheFPM->add(createGVNPass()); 987 | // Simplify the control flow graph (deleting unreachable blocks, etc). 988 | TheFPM->add(createCFGSimplificationPass()); 989 | 990 | TheFPM->doInitialization(); 991 | } 992 | 993 | static void HandleDefinition() { 994 | if (auto FnAST = ParseDefinition()) { 995 | if (auto *FnIR = FnAST->codegen()) { 996 | fprintf(stderr, "Read function definition:"); 997 | FnIR->print(errs()); 998 | fprintf(stderr, "\n"); 999 | TheJIT->addModule(std::move(TheModule)); 1000 | InitializeModuleAndPassManager(); 1001 | } 1002 | } else { 1003 | // Skip token for error recovery. 1004 | getNextToken(); 1005 | } 1006 | } 1007 | 1008 | static void HandleExtern() { 1009 | if (auto ProtoAST = ParseExtern()) { 1010 | if (auto *FnIR = ProtoAST->codegen()) { 1011 | fprintf(stderr, "Read extern: "); 1012 | FnIR->print(errs()); 1013 | fprintf(stderr, "\n"); 1014 | //在函数声明时,也会把函数名添加到查询表中 1015 | FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); 1016 | } 1017 | } else { 1018 | // Skip token for error recovery. 1019 | getNextToken(); 1020 | } 1021 | } 1022 | 1023 | static void HandleTopLevelExpression() { 1024 | // Evaluate a top-level expression into an anonymous function. 1025 | if (auto FnAST = ParseTopLevelExpr()) { 1026 | if (FnAST->codegen()) { 1027 | // JIT the module containing the anonymous expression, keeping a handle so 1028 | // we can free it later. 1029 | auto H = TheJIT->addModule(std::move(TheModule)); 1030 | InitializeModuleAndPassManager(); 1031 | 1032 | // Search the JIT for the __anon_expr symbol. 1033 | auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); 1034 | assert(ExprSymbol && "Function not found"); 1035 | 1036 | // Get the symbol's address and cast it to the right type (takes no 1037 | // arguments, returns a double) so we can call it as a native function. 1038 | double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress()); 1039 | fprintf(stderr, "Evaluated to %f\n", FP()); 1040 | 1041 | // Delete the anonymous expression module from the JIT. 1042 | TheJIT->removeModule(H); 1043 | } 1044 | } else { 1045 | // Skip token for error recovery. 1046 | getNextToken(); 1047 | } 1048 | } 1049 | 1050 | /// top ::= definition | external | expression | ';' 1051 | static void MainLoop() { 1052 | while (true) { 1053 | fprintf(stderr, "ready> "); 1054 | switch (CurTok) { 1055 | case tok_eof: 1056 | return; 1057 | case ';': // ignore top-level semicolons. 1058 | getNextToken(); 1059 | break; 1060 | //函数定义:必须包含函数体 1061 | case tok_def: 1062 | HandleDefinition(); 1063 | break; 1064 | //函数声明:没有函数体 1065 | case tok_extern: 1066 | HandleExtern(); 1067 | break; 1068 | default: 1069 | HandleTopLevelExpression(); 1070 | break; 1071 | } 1072 | } 1073 | } 1074 | 1075 | //===----------------------------------------------------------------------===// 1076 | // "Library" functions that can be "extern'd" from user code. 1077 | //===----------------------------------------------------------------------===// 1078 | 1079 | #ifdef _WIN32 1080 | #define DLLEXPORT __declspec(dllexport) 1081 | #else 1082 | #define DLLEXPORT 1083 | #endif 1084 | 1085 | /// putchard - putchar that takes a double and returns 0. 1086 | extern "C" DLLEXPORT double putchard(double X) { 1087 | fputc((char)X, stderr); 1088 | return 0; 1089 | } 1090 | 1091 | /// printd - printf that takes a double prints it as "%f\n", returning 0. 1092 | extern "C" DLLEXPORT double printd(double X) { 1093 | fprintf(stderr, "%f\n", X); 1094 | return 0; 1095 | } 1096 | 1097 | //===----------------------------------------------------------------------===// 1098 | // Main driver code. 1099 | //===----------------------------------------------------------------------===// 1100 | 1101 | int main() { 1102 | InitializeNativeTarget(); 1103 | InitializeNativeTargetAsmPrinter(); 1104 | InitializeNativeTargetAsmParser(); 1105 | 1106 | // Install standard binary operators. 1107 | // 1 is lowest precedence. 1108 | BinopPrecedence['<'] = 10; 1109 | BinopPrecedence['+'] = 20; 1110 | BinopPrecedence['-'] = 20; 1111 | BinopPrecedence['*'] = 40; // highest. 1112 | 1113 | // Prime the first token. 1114 | fprintf(stderr, "ready(chapter06)> "); 1115 | getNextToken(); 1116 | 1117 | TheJIT = llvm::make_unique(); 1118 | 1119 | InitializeModuleAndPassManager(); 1120 | 1121 | // Run the main "interpreter loop" now. 1122 | MainLoop(); 1123 | 1124 | return 0; 1125 | } -------------------------------------------------------------------------------- /lib/Kaleidoscope_tutorial/src/Chapter07/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Analysis 3 | Core 4 | ExecutionEngine 5 | InstCombine 6 | Object 7 | OrcJIT 8 | RuntimeDyld 9 | ScalarOpts 10 | Support 11 | TransformUtils 12 | native 13 | ) 14 | 15 | add_kaleidoscope_chapter(Kaleidoscope-Ch7 16 | toy.cpp) 17 | 18 | export_executable_symbols(Kaleidoscope-Ch7) -------------------------------------------------------------------------------- /lib/src_clang/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/lib/src_clang/CMakeLists.txt -------------------------------------------------------------------------------- /lib/src_llvm/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cyoung7/implement_llvm/504660969f6366f453a655a27ec337d6c3f739f0/lib/src_llvm/CMakeLists.txt -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/IR/Module.h" 2 | #include "llvm/IR/IRBuilder.h" 3 | #include "llvm/IR/LLVMContext.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static llvm::LLVMContext theContext; 12 | static llvm::IRBuilder<> builder(theContext); 13 | static std::unique_ptr theModule; 14 | static std::map nameValues; 15 | 16 | int main(){ 17 | theModule = llvm::make_unique("hello,llvm",theContext); 18 | theModule->dump(); 19 | std::cout << "hello" << std ::endl; 20 | return 0; 21 | 22 | } --------------------------------------------------------------------------------