什么是 LLVM?Swift, Rust, Clang等语言背后的支持

2018-02-27 11:27:48来源:https://www.oschina.net/translate/what-is-llvm-the-power-beh作者:开源中国翻译文章人点击

分享


要了解用于以编程方式生成机器原生代码的编译器框架是如何让新语言的推出以及对现有的语言进行增强比以往更加容易了。


新的语言,还有对现有语言的提升,在整个编程环境中正大行其道。 Mozilla 的 Rust 、 Apple 的 Swift 、 Jetbrains 的 Kotlin ,以及许多其它的语言都给开发者在速度、安全性、便利性、可移植性还有能力这些方面提供了新的选择。


为什么现在正当时呢?一个大因素就是那些用来构建语言的新工具,特别是编译器。它们中首当其冲就是 LLVM (底层虚拟机 Low-Level Virtual Machine),这是一个开源项目,最开始作为伊利诺伊州大学的一个研究项目由 Swift 语言的创始人 Chris Lattner 进行开发。


LLVM 使创建新语言变得更加容易,同时也可以增强现有语言的开发。它提供了一些工具,用于自动执行语言创建任务中最不讨人喜欢的部分:创建一个编译器,将输出的代码移植到多个平台和架构,编写代码来处理常见的语言隐喻,比如异常。它的自由授权意味着它可以自由地作为软件组件重用或作为服务部署。


使用 LLVM 的语言名册中有许多熟悉的名字。苹果的 Swift 语言使用 LLVM 作为它的编译器框架,而 Rust 则将 LLVM 作为其工具链的核心组件。而且,许多编译器都有一个 LLVM 版本,如 Clang、C/C++ 编译器(这个名称叫做“C-lang”),它本身就是一个与 LLVM 紧密相连的项目。而 Kotlin,名义上是一种 JVM 语言,正在开发一种名为 Kotlin Native 的语言版本,它使用 LLVM 来编译成机器原生代码。


LLVM 定义

在它的核心,LLVM 是一个以编程方式创建机器原生代码的库。开发人员使用该 API 以一种称为中间代理或 IR 的格式生成指令。然后 LLVM 可以将 IR 编译成一个独立的二进制文件,或者在另一个程序(如语言解释器)的上下文中执行 JIT (just-in-time) 编译。


LLVM 的 API 为开发在编程语言中发现的许多常见结构和模式提供了原始的方式。例如,几乎每种语言都有函数和全局变量的概念。LLVM 将函数和全局变量作为其 IR 中的标准元素,因此,你只需在意 LLVM 的实现,并关注需要注意的语言部分,而不是花费时间和精力重新创建这些特定的轮子。


这是一个 LLVM 中间代理(IR)的例子。右边是一个简单的 C 程序;左边是由 Clang 编译器翻译成 LLVM IR 的代码。



LLVM:专为可移植性而生

关于 LLVM 的一个说法是它像常提到的 C 编程语言:C 语言有时候被认为是一种便携式、高级的汇编语言,因为它可以紧密地映射到系统硬件的结构,而且它已经被移植到几乎所有的系统架构。但是,C 语言只是作为一种可移植的汇编语言,是其工作方式的另一种效果;这并不是它的设计目标之一。


相比之下,LLVM 的 IR 是从一开始就设计为可移植的组件。它实现这种可移植性的一种方法是提供独立于任何特定机器架构的原语。例如,整数类型不局限于底层硬件的最大位宽度(例如 32 或 64 位),您可以根据需要使用尽可能多的比特字节来创建基本的整数类型,比如 128 位整数。您也不必担心手工输出来匹配特定处理器的指令集;LLVM 也会为你处理这个问题。


如果你希望看到 LLVM IR 的现场示例,请访问 ELLCC 项目网站 ,并尝试在浏览器中将 C 代码转换为 LLVM IR 的 现场演示 Demo 。



编程语言是如何使用 LLVM 的

LLVM 最常见的用途就是被作为一个语言的提前(ahead-of-time,AOT)编译器。但 LLVM 也能让其它一些事情成为可能。


用 LLVM 进行即时编译

有些情况中需要代码在运行时动态生成,而非提前编译好的。比如Julia 语言,JIT 会编译其代码,因为它需要快速运行并通过 REPL (读取-执行-打印输出循环read-eval-print loop)或者是交互式提示来与用户进行交互。Mono 是 .Net 的实现,它有一个选项来 通过一个 LLVM 后端的方式编译成原生代码 。


Numba,一个 Python 的数学加速包,JIT 会将选好的 Python 函数编译成机器码,它也能对以Numba 包装的代码进行提前编译, 不过 (像 Julia 这种语言) Python 也可以作为一种解释型语言提供快速开发的能力。要使用JIT 编译来产生这样的代码组件, Python 的交互式工作流要比提前编译表现得更好。



其它人则用一些非正统的方式来把 LLVM 当作一个 JIT 使用,比如 编译 PostgreSQL 查询 ,据说对性能的提升有 5 倍。



Numba 使用 LLVM 来即时编译数字代码并加速其执行。JIT 加速过的 sum2d 函数完成其执行比起常规的 Python 代码要快上 139 倍。


使用 LLVM 进行自动代码优化

LLVM 不仅仅只是将 IR 编译成原生机器码。你也能以编程方式来指示其在整个链接过程中对代码进行高度精细的优化。这样的优化可以是相当积极主动的,能够实现包括像内敛函数、消除死代码(包括没用的类型声明以及函数参数)、还有展开循环这些事情。


这里再一次强调,LLVM 比较强大之处是你没必要自己去实现所有这些东西,它能为你处理它们, 或者你可以根据需要禁用它们。例如,如果你想要牺牲一点点性能换取一个更小的二进制包,就可以通过编译器前台告诉 LLVM 禁用循环展开。



使用 LLVM 的领域特定语言

LLVM 已被用于生成多种通用语言的编译器,但它也可用于生成高度垂直或排他性问题域的语言。从某种意义上说,这就是 LLVM 最闪光的地方,因为它在创造这样一类语言方面消除了诸多苦差事,并使其表现良好。


例如, Emscripten 项目采用 LLVM IR 代码并将其转换为 JavaScript,理论上支持使用 LLVM 作为后端的任何语言导出可在浏览器中运行的代码。长期规划是支持基于 LLVM 的后端并能够生成 WebAssembly 代码,Emscripten 是 LLVM 灵活性的一个很好的例子。


LLVM 可以被使用的另一种方法是将特定领域的扩展添加到现有语言。Nvidia 使用 LLVM 创建了 Nvidia CUDA 编译器,该编译器允许语言为 CUDA 添加原生支持,它是作为你生成的原生代码的一部分编译的,而不是通过附带的库进行调用的。



在各种不同的语言中使用 LLVM

使用 LLVM 的典型方法就是使用一种你拿手的语言(当然该语言需要有 LLVM 的库)来编写代码。


两种常见的语言选择就是 C 和 C++。许多 LLVM 开发者会因为如下几个原因而默认选择这两者之中的一个:



LLVM 本身是使用 C++ 编写的。


LLVM 的 API 在 C 和 C++ 的变种版本中是可以使用的。


以 C/C++ 为基础进行大量的语言开发,势头正盛。



不过,这两种语言并非唯一选择。许多语言都可以原生地调用到 C 库里面去,因此理论上使用任何这类语言进行 LLVM 开发都是可能实现的。不过要是实际中语言的支持库对 LLVM 的 API 进行了不错的封装的话,还是挺有帮助的。幸运的是,许多语言和语言运行时都拥有这样的库,包括 C#/.Net/Mono , Rust , Haskell , OCAML , Node.js , Go , 还有 Python 。



需要警惕的是,有些绑定到 LLVM 的语言可能比其它的一些在完整性上有所欠缺。比如 Python 就有许多的选择,但每一种在完整度和实用性方面都各不相同。



LLVM 项目本身就 维护了一组它自己到 LLVM 的 C 语言 API 的绑定 ,不过它们目前没有得到维护了。


llvmpy 在 2015 年就停止维护了 — 这样的情况对任何软件项目来说都是不利的,而在使用 LLVM 时则更加如此,因为每个版本的 LLVM 都有一定数量的变化。


llvmlite , 它是由创造了 Numba 的团队所开发的,作为当前在 Python 中使用 LLVM 的一位竞争者,应运而生。它只实现了 LLVM 全部功能的一个子集,正是 Numba 项目所需要的那些。而这个子集提供了 LLVM 用户所需要的绝大部分功能。


llvmcpy 旨在为保持 C 语言库的更新而引入 Python 的绑定,并且是以自动的方式保持其更新,还有就是让它们可以使用 Python 的原生习惯用法来访问得到。llvmcpy 仍然处在早期阶段,不过已经可以使用其 LLVM API 来做一些基本的事情了。




如果你对使用 LLVM 库开发语言感兴趣,不妨阅读由 LLVM 创始人撰写的 入门教程 ,该教程使用 C++ 和 OCAML 语言,一步步引导读者去创建一门简单的名为 Kaleidoscope 的语言。它还被移植到其他的语言实现:



Haskell : 参考官方教程移植而来


Python:两种方式都是使用 llvmlite 作为到 LLVM 的绑定, 一个是严格遵守官方教程的 ,另一个是做了大量的重写,并 使用交互式命令行 。


Rust 和 Swift : 似乎不可避免地地,我们使用本身由 LLVM 底层实现的这两种语言来移植教程。



最后,这个教程也提供了一些其他国家语言的不同翻译版本,这里有中文版,分别是 使用 C++ 的官方教程 与 使用 Pytho n 的教程。



最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台