前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SGADC2019丨拥抱方舟编译器:Maple IR 分析及 Toy Runtime 介绍

SGADC2019丨拥抱方舟编译器:Maple IR 分析及 Toy Runtime 介绍

作者头像
软件绿色联盟
发布2022-03-31 13:34:20
发布2022-03-31 13:34:20
1.2K0
举报

11月19日,在软件绿色联盟开发者大会开源与跨平台开发分论坛上,史宁宁发表了主题为《拥抱方舟开源编译器:Maple IR 分析及 Toy Runtime 介绍》的演讲,基于方舟编译器已经开源的代码和文档,对方舟编译器的IR的设计以及具体实现做介绍和分析,并将其设计与LLVM、Open64做简要的横向对比。同时,对基于方舟编译器IR的Phase体系做分析,展示其针对IR的转换和优化。除此以外,还对Toy runtime的基本情况进行介绍。本文内容主要有五个部分:

  • 方舟编译器概况
  • MAPLE IR的设计与实现
  • MIR与其他IR的横向对比
  • Phase体系的设计与实现
  • Toy Runtime简介

1

方舟编译器概况

方舟编译器是华为推出的首个完全自主研发的编译器平台,于2019年8月31日正式上线。方舟编译器已成为码云最快达成5000 Star的开源项目。华为方舟编译器是华为公司专门为软件厂商研发的统一编程平台,包含编译器、工具链、运行时等关键部件。该编译器支持多种编程语言、多种芯片平台的联合编译与运行,能够有效解决安卓程序“边解释边执行”的低效率问题。

方舟编译器是为支持多种编程语言、多种芯片平台的联合编译、运行而设计的统一编程平台,包含编译器、工具链、运行时等关键部件。方舟编译器还在持续演进中, 陆续将上述能力实现和开源。

单纯讲定义或许有些抽象,结合方舟编译器的应用场景更好理解一些,下图是传统的安卓的APP开发及手机运行过程。JNI,全称JavaNative Interface(Java原生接口),用来和C/C++等代码进行交互。目前大部分应用是使用Java和C/C++等多种语言混合开发而成。Java和C/C++属于两种不同架构的语言,各有自己的使用规范。为了APP正常运行,它俩之间需要互通有无,这个互通有无的接口就是JNI。在数据访问、函数调用、生命周期维护、异常处理等方面都需要这两种代码互相调用。这就意味着手机硬件资源要分配一部分给JNI去做调度。不仅占用了硬件资源,而且这种机制本身就效率较低。这便是额外的JNI开销。方舟编译器就是要解决这个痛点。

方舟编译器运行过程是什么样的?统一程序表示,统一程序做优化,变成APK可执行文件,在手机上是二进制码形式运行。既避免了JNI问题,性能有所提升,并不是编译器的优化算法。因为机制不同,快是必然的,因为它把一部分的工作等于在开发环境下做了,到运行环境的时候就直接是二进制码。

方舟编译器的架构:当前方舟编译器支持Java/Kotlin程序字节码的前端输入,其它编程语言的支持(如 C/C++/JS 等)还在规划中,方舟编译器的中间表示(IR)转换器将前端输入转换成方舟IR,并输送给后端的优化器,最终生成二进制文件,二进制文件与编译器运行时库文件链接生成可执行文件,在方舟的运行环境中就可执行该文件。下图是方舟编译器架构示意图:

方舟编译器现在开源部分主要有两块,一块是IR,一块是Phase体系,所以IR和Phase体系是本文介绍的两个重点。下图绿色部分表示现在都是开源的。

2

Maple IR的设计与实现

接下来讲解第二部分,Maple IR的设计与实现。Maple IR的设计起源是一篇论文,下图是论文里面中的一张图,大家经常开玩笑,说是大一统思想,左边有多种语言,有多种前端,中间是IR和IR的优化,后面是多个目标平台和多个后端。当然现在我们主流的编译器基本上都在走这样的套路,已经证明这个模式是比较优秀的,比较容易扩展。

这一部分要介绍IR,IR在整个方舟编译器中的位置是在这个部位。如下图:

方舟编译器IR采用了多层IR的设计,具有以下特点:

1. 高层IR更接近于源程序,包含了更多的程序信息;

2. 底层IR更接近于目标平台的机器指令,甚至有的时候和机器指令是一对一的关系;

3. 高层IR保留了程序语言的层次结构,和目标机器平台无关;

4. 底层IR更加扁平化,依赖具体的目标平台。

为什么方舟编译器要采用多层IR设计,是因为多层IR设计有很多优点,总结了四点:

1.可以提供更多的源程序信息;

2.IR表达上更加地灵活,更加方便优化;

3.使得优化算法更加地高效;

4.可以将优化算法的负面影响降到最低。

当然多层IR的设计也不全部是优点,任何事物都有双刃剑,也有一个缺点,底层IR的优化器将面临更多的可能,增加了特定语义的识别难度。

多层IR设计通常有一个明确的IR分层结构,下图左边是Open64多层IR分层结构图,右边的方舟编译器的IR多层结构图还是一个问号,暂未公开。这个多层IR分层是IR设计里面重要的一部分,具体分为哪几层,每一层需要做什么事,后续持续关注。

我们前面讲了那么多方舟IR多层设计,包括理论,我们看一下具体IR的结构。最外层是一个编辑单元,紧接着是全局范围的一些声明,接着是程序函数。函数里面是局部范围的声明和最后函数的执行节点,函数的执行节点分为三种,一种是叶节点,一种表达式节点,还有一种语句节点。

叶节点通常情况下就是一个常数的值,或者一个存储单元的具体值。表达式节点有一个最大区别,表达式节点操作数可以是另外一个新的表达式,或者是叶节点。语句节点操作数可以是语句节点也可以是表达式节点。将它们关系用下图表示,这种表达并不严谨,可以看为一种包含的状态,表达式节点可以是它自身也可以是叶节点,语句节点可以是表达式节点也可以是它自身。

MapleIR里面基本类型设计和控制流语句设计,这两项是IR里面基本的重要要素,下图是文档中描述的基本类型。有一点需要专门讲下,方舟编译器的MapleIR在设计的时候,专门给Javascript预留了一些基本类型,后续给Javascript做支持用。这点为什么需要重点关注,因为现在编译器多数针对多种语言设计的,但是在基本层面上直接为某一种语言去专门预留一批基本类型,这种相对来说比较少见,一般都是为整个体系考虑,后续看Javascript支持了以后,一起期待下这些基本类型能否发挥应有的作用吧。

方舟编译器源码和文档中基本类型还有两个方向,下图左边是文档中有的三个基本类型,源码中没有,源码中有七个基本类型,但是在文档中没有出现。

除了刚才讲基本类型,控制流语句是另外一个比较重要的要素,按照在文档中的分类,分为层次型的控制流语句、平坦型控制流语句。

我们在源码中看的时候,这块跟刚才一样,源码中和文档中控制流语句也有出入,分类方法不太一致,如下图:

3

MIR与其它IR的横向对比

方舟编译器开源之后,很多人一直在讨论,方舟编译器更像以前哪一种编译器,我们今天就把它和其他的IR横向对比一下,看看到底更像哪一个。

首先把方舟编译器的IR和LLVM的IR进行对比。绿色色块代表相似的地方,如下图:

总结:MAPLE IR和LLVM IR的基本类型设计思想不同,所以二者的基本类型采用的是不同的风格,基本没有相同的类型表示。

下面是MIR与WHIRL IR的基本类型对比:

总结:除去Javascript的专用基本类型,二者有16/26 种基本类型设计一致。

MIR与WHIRL IR的控制流语句对比:

总结:除了个别控制流语句之外,MAPLE IR基本上是WHIRL IR 的一个子集。

4

Phase体系的设计与实现

Phase分为两类,一个是ModulePhase,另一个是MeFuncPhase。所有Phase在具体实现的时候,如果是ModulePhase这一类别的就会作为ModulePhase的直接子类去实现,如果是MefuncPhase就作为MefuncPhase子类去实现。每一个类别的Phase都有一个对应的Manager去做管理,整体上是由InterleavedManager去管理整个Phase体系。如下图:

借助下图来分析整个Phase体系是怎么运行的。这是方舟编译器里面目前注册的ModulePhase和MeFuncPhase,分为三块,第一块是上面这五个,第二块中间这六个,第三块下面这五个,上面这五个是ModulePhase,中间是MeFuncPhase,最下面也是ModulePhase,整体执行上按照这个顺序从上到下执行的。但并不是直接根据这个Phase列表执行,而是上面这连续的五个ModulePhase,有一个ModulePhaseManager去管理,中间几个MeFuncPhase有一个MeFuncPhase的Manager去管理。每个Manager去管理自己的Phase体系,就实现了整个Phase体系的运行。

最右边是名称,第二列是对应的事件类,中间是具体代码的位置。如下图:

下图是整个方舟编译器目前公开代码中已经实现的MeFuncPhase,目前主要有八个。

5

Toy Runtime简介

ToyRuntime是中科院软件所智能软件中心程序语言与编译技术实验室在开发的一个方舟编译器Runtime参考实现,这个项目是为了实现一个示例Runtime版本。Toy Runtime开源地址:https://github.com/isrc-cas/pacific

目前Toy Runtime已经发布了V0.1版本。在没有方舟运行时环境设计细节的前提下,我们进行了一定程度的hack和逆向。 采用 QEMU来提供AArch64的架构支持,把方舟的Java的那一套巧妙地(硬生生)用 GNU/Linux的方式「fake」 了一套可以跑「Hello World」的 Toy Runtime 。

方舟编译器的持续开源,可以让更多的科研机构、高校院所、第三方厂商和广大开发者参与进来,源码才会在不断地重构和优化中激活、升华,助开发者们更好的理解软件开发编译,为开发者们如何高效开发带来新思路。近期我们会发布更多关于软件绿色联盟开发者大会开源与跨平台开发分论坛议题文章。

End

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 软件绿色联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档