简介

LLVM是一套提供编译器基础设施的开源项目,是用 C++ 编写,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。它是为了任意一种编程语言而写成的程序,利用虚拟技术创造出编译时期、链接时期、执行时期以及“闲置时期”的优化。

LLVM的命名源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,导致不了解它的人以为它是类似于 JVM(Java Virtual Machine) 的虚拟机,实际上这个项目的范围并不局限于创建一个虚拟机,而是包括 LLVM 中介码(LLVM IR)、LLVM调试工具、LLVM C++ 标准库等一系列编译工具及低端工具技术的集合。

传统的静态编译器设计是三阶段设计,其主要组件是前端、优化器和后端。

前端负责词法分析、语法分析、语义分析、生成中间代码等功能。

优化器负责进行各种转换以尝试提高代码的运行时间,例如消除冗余计算,并且通常或多或少独立于语言和目标。

后端(也称为代码生成器)负责将代码映射到目标指令集。除了编写正确的代码外,它还负责生成利用所支持架构的不寻常特性的良好代码。编译器后端的常见部分包括指令选择、寄存器分配和指令调度。

该模型同样适用于解释器和 JIT 编译器。JVM 也是该模型的一个实现,它使用 Java 字节码作为前端和优化器之间的接口。

而 LLVM 被设计为支持多种源语言或目标架构,它提供了一套适合编译器系统的中间语言,如果编译器在其优化器中使用这个中间语言表示,则可以为任何可以编译到它的语言编写前端,并且可以为任何可以从它编译的目标编写后端。

使用这种设计,移植编译器以支持新的源语言只需要实现新的前端,即可以重用现有的优化器和后端;同样想增加支持新的目标架构也只需要实现新的后端。而如果按传统设计,前端和后端实际是耦合在一起,实现新的源语言或支持新的目标架构将需要从头开始,要支持 N 目标和 M 源语言将需要 N*M 个编译器。

LLVM IR

LLVM提供了一套适合编译器系统的中间语言(Intermediate Representation,IR),有大量变换和优化都围绕其实现,经过变换和优化后的中间语言,可以转换为目标平台相关的汇编语言代码。

该中间语言与具体的语言、指令集、类型系统无关,其中每条指令都是静态单赋值形式(SSA), 即每个变量只能被赋值一次。这有助于简化变量之间的依赖分析。

以下是简单的 LLVM IR 代码:

define i32 @add1(i32 %a, i32 %b) {
entry:
%tmp1 = add i32 %a, %b
ret i32 %tmp1
} define i32 @add2(i32 %a, i32 %b) {
entry:
%tmp1 = icmp eq i32 %a, 0
br i1 %tmp1, label %done, label %recurse recurse:
%tmp2 = sub i32 %a, 1
%tmp3 = add i32 %b, 1
%tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3)
ret i32 %tmp4 done:
ret i32 %b
}

上述代码对应的 C 语言代码为:

unsigned add1(unsigned a, unsigned b) {
return a+b;
} unsigned add2(unsigned a, unsigned b) {
if (a == 0) return b;
return add2(a-1, b+1);
}

从这个例子可以看出,LLVM IR 是一种强类型的精简指令集( RISC )。像真正的 RISC 指令集一样,它支持简单指令的线性序列,如加法、减法、比较和分支。这些指令采用三地址形式,这意味着它们接受一定数量的输入并在不同的寄存器中产生结果。LLVM IR 支持标签,通常看起来像一种奇怪的汇编语言形式。

与大多数 RISC 指令集不同,LLVM 使用简单的类型系统进行强类型化(例如,i32 是一个 32 位整数,i32** 是一个指向 32 位整数的指针),并且机器的一些细节被抽象掉了。例如,调用约定是通过指令和显式参数 call 抽象出来的。ret 与机器代码的另一个显着区别是 LLVM IR 不使用一组固定的命名寄存器,它使用一组无限的以 % 字符命名的临时寄存器。

LLVM IR 支持三种表达形式:人类可读的汇编、在C++中对象形式、序列化后的 bitcode 形式。

编译

LLVM允许代码被静态的编译,包含在传统的GCC系统底下,者通过实时编译(JIT)机制将中间表示转换为机器码(类似 Java)。

LLVM 类型系统包含基本类型(整数或是浮点数)及五个复合类型(指针、数组、向量、结构及函数),在LLVM具体语言的类型建制可以以结合基本类型来表示,举例来说,C++所使用的class可以被表示为结构、函数及函数指针的数组所组成。

LLVM 提供了 Clang 作为官方的编译器前端,同时支持 C、C++、Objective-C 和 Objective-C++ 语言。主要来自 Apple 公司的赞助支持,Clang 的目的用以取代 GCC 系统底下的 C / Objective-C 编译器,在当代的系统,它较为容易与集成开发环境(IDE)集成,而且对于线程有更好的支持。许多 GCC 的前端也已经可以与其运行,LLVM目前支持 Ada、C语言、C++、D语言、Fortran、Haskell、Julia、Objective-C、Rust 及 Swift 等语言的编译。

认识 LLVM的更多相关文章

  1. LLVM 笔记(五)—— LLVM IR

    ilocker:关注 Android 安全(新手) QQ: 2597294287 LLVM 的 IR (Intermediate Representation) 是其设计中的最重要的部分.优化器在进行 ...

  2. LLVM 笔记(四)—— three-phase 设计的收益

    ilocker:关注 Android 安全(新手) QQ: 2597294287 采用 three-phase 的设计方式,便于编译器支持多种语言和多种目标平台. 如果在优化器阶段采用通用的 IR ( ...

  3. LLVM 笔记(二)—— PHI node

    ilocker:关注 Android 安全(新手) QQ: 2597294287 什么是 PHI node? 所有 LLVM 指令都使用 SSA (Static Single Assignment,静 ...

  4. [ZZ] A Proposal For Compiling Direct3D HLSL With LLVM (Written by Michael Larabel )

    http://www.phoronix.com/scan.php?page=news_item&px=OTI2NA Note:  Something very instersting to w ...

  5. LLVM与Clang的概述及关系

    LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time).链接时间(link-time).运行时间(run-time ...

  6. [llvm] Call the LLVM Jit from c program

    stackoverflow: http://stackoverflow.com/questions/1838304/call-the-llvm-jit-from-c-program Another t ...

  7. install LLVM

    version >= 3.8.0 $ cd llvm... $ mv someofClang ./tools $ mkdir build $ cd build $ cmake -DCMAKE_B ...

  8. LLVM example for main

    #include "llvm/IR/CallSite.h" #include "llvm/IR/Instruction.h" #include "ll ...

  9. clang LLVM 介绍和安装(Ubuntu10 64位)

    http://www.csdn.net/article/2013-11-27/2817632 的对Stanley B.Lippman采访提到clang的一些优点,以前程序员杂志也写过,为了提高系统的性 ...

  10. 转:GCC,LLVM,Clang编译器对比

    GCC,LLVM,Clang编译器对比   转自: http://www.cnblogs.com/qoakzmxncb/archive/2013/04/18/3029105.html 在XCode中, ...

随机推荐

  1. Solon Web 开发,七、视图模板与Mvc注解

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  2. [硬拆解]拆解一个USB转CAN-FD总线设备-PCAN-USB FD

    描述 CAN FD适配器PCAN-USB FD允许通过USB将CAN FD和CAN网络连接到计算机.高达500伏的电流隔离将PC与CAN总线分离.简单的操作及其紧凑的塑料外壳使该适配器适用于移动应用. ...

  3. [Altium Designer 学习]怎样添加3D模型

    对于为给PCB添加3D模型,很多人觉得这是个绣花针的活,中看不中用.在我看来这也未必,特别是常用的3D模型能在网上下载的今天,只需要几个简单的操作,就能使你的PCB更加赏心悦目.除此之外,3D模型还有 ...

  4. 【新手笔记】golang中使用protocol buffers 3

    主要参考了这篇帖子:https://segmentfault.com/a/1190000009277748 1.下载windows版本的PB https://github.com/protocolbu ...

  5. Nginx限制连接控制访问量

    目录 一:限制连接数模块(同时访问网址能访问多少次) 1.修改网址模块文件 2.测试 3.重启 4.增加解析ip 5.压力测试 二:控制Nginx访问量 1.连接池 2.限制数 3.测试 4.重启 5 ...

  6. kdj

    随机指标KDJ一般是用于股票分析的统计体系,根据统计学原理,通过一个特定的周期(常为9日.9周等)内出现过的最高价.最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成 ...

  7. plsql 数据库事件触发器

    --4.数据库事件触发器 需要超管的权限 /* 数据库事件触发器有数据库级和模式级两种. 前者定义在整个数据库上,触发事件是数据库事件,如数据库的启动.关闭,对数据库的登录或退出. 后者定义在模式上, ...

  8. c#代码设计:子类和父类

    哭辽,事情是这样的 我想写个产品类用来放点相机参数,想类似这种的使用方式:(时间关系不改了,产品=Zoo,animals=相机) Zoo Zooxx= new Zoo (); Zoo.Animals ...

  9. 设置鼠标光标与页面favicon

    鼠标光标 body{cursor: url('http://image.XXXX.com/ii.png'),default;} 2. favicon <link rel="shortc ...

  10. Redis为什么是单线程,高并发快的3大原因详解

    出处知乎:https://zhuanlan.zhihu.com/p/58038188 Redis的高并发和快速原因 1.redis是基于内存的,内存的读写速度非常快: 2.redis是单线程的,省去了 ...