一文看懂RISC-V代码密度

简介: 对于内存受限的嵌入式芯片(包括MCU和成本要求的AP类芯片)来说,代码密度非常重要。同样功能的程序,如果代码密度过大,就可能导致因ROM空间装载不下而无法使用。所在,在嵌入式领域中,代码密度是最重要的指标之一。那么,代码密度由什么决定?如何提高代码密度呢?RISC-V的代码密度现状又如何?

代码密度的决定因素

如上面的倒金字塔所示,代码密度主要由指令集、ABI、编译器、Runtime库、程序代码五个部分决定。处在金字塔的越底端,说明该因素的越底层,更新的频率越小,但辐射和影响的范围却越广。

指令集

指令集是代码密度最根本的决定性因素,它决定了一个操作在最优的情况下需要编译成多少位宽的编码。

很多体系结构比如ARM、RISC-V、C-SKY都是16位指令、32位指令混编的,同样的一条指令,如果能够被编译成16位指令,那么它显然比编译成32位指令占用更小的空间;再比如,一个乘累加的操作,如果指令集中存在乘累加指令,那么它只需要一条指令来实现乘累加操作,如果没有则需要至少两条指令来完成相同的操作,假设指令都是32位的,显然一条指令将占用更少的空间。

由于指令集的编码空间是有限的,所以指令集设计的核心是将哪些指令(包括指令操作数的范围)放到编码空间当中,就像一个商场的店面是有限的,当我们把需求最广的商家引进来时,商场的销量就会达到最高。

ABI

ABI的全称是Application Binary Interface,是二进制级别的协议,它指导着编译器如何生成代码和二进制程序,同样也指导着用户如何写汇编代码。它主要包含函数调用约定(calling convention)、数据的对齐方式等内容。

其中对代码密度影响最大的就是函数调用约定,它规定了堆栈寄存器、链接寄存器、哪些寄存器寄存器需要在函数头尾保存和恢复、哪些寄存器可以作为参数寄存器等,还有一些特殊用途的寄存器。大部分特殊寄存器都是会被高频使用的,配合指令集设计可以降低代码密度;需要保存和恢复的寄存器个数同样也会影响代码密度。

编译器

编译器是开发者最直接接触的工具,也是给开发者体感最强的代码密度影响因素。它对代码密度的影响主要体现在两方面:

  1. 编译器本身的优化能力,优化能力的强弱是影响编译器产品竞争力的最主要的因素。
  2. 编译器的使用方法,比如GCC,除了添加-Os之外,还可以添加-ffunction-sections -fdata-sections -Wl,--gc-sections来删除没有用到的函数。

Runtime库

Runtime库是指程序运行所需的一些基本的函数库,它们一般都是预先编译好,和编译器一起打包发布,是工具链的一部分。由于这些函数的使用频率较高,一般程序都会用到一部分Runtime库的函数,对这些函数做针对性地优化会有比较好的收益。

程序代码

开发者书写的代码质量也会影响程序的代码密度,虽然编译器能够优化一部分冗余代码,但是并不能保证百分之百的优化,所以开发者也要注意代码的质量。

RISC-V架构的代码密度现状

RISC-V的代码密度表现一直被人诟病,那么,它的现状真的这么不值一提吗?

首先,RISC-V对代码密度做过一些专门的优化。在指令集方面,它通过量化分析的方法测试了spec等benchmark,找到高频指令并将它们放到16位指令的编码当中,这就是目前的compress指令集;在ABI方面,rv32e通过限制16个寄存器,使代码可以生产更多的16位指令;在编译器和Runtime中,它支持-msave-restore功能通过库函数调用的方式弥补了由于没有push/pop指令造成的一部分代码密度损失。这里需要特别指出的是,RISC-V的链接器做了较多的relax优化,即某些指令的目标符号距离比较接近的时候,可以优化使用更少的指令。比如函数跳转,比如具体在4k之内,可以使用一条jalr指令实现,而如果超过4k的话,则需要auipc+jalr或者lui+jalr两条指令实现。一般在未链接的object文件中,预留的都是指令条数最多的形式,链接之后很大一部分将被优化。如果测试的benchmark如果统计的是object文件,比如CSiBE,那么结果会比实际的要差一些。

那么,在做了这些优化之后,为什么RISC-V的代码密度还是被这么多人诟病呢?主要是由于compress指令集设计时,基于的benchmark是spec2006,它在应用PC端非常具有代表性,但在嵌入式领域却不具有典型性。所以在RISC-V 64位核中,它的代码密度表现还不错,但是在真正关心代码密度的嵌入式领域表现却不尽如人意。其次,ABI也需要重新针对嵌入式领域做量化评估和设计。

平头哥对RISC-V的代码密度优化

针对代码密度,RISC-V社区目前也在不断地优化中,比如code-size TG和EABI TG的成立。平头哥也参与其中,在优化代码密度的道路上不断前行。目前,平头哥所做的优化有如下两个方面:

Runtime库

平头哥设计开发了一套针对嵌入式领域的、最大化优化代码密度的Lower-Level Runtime Library。目前玄铁E902、玄铁E906和玄铁E907均已支持该Runtime库,它相对于libgcc提升40%;相对于Arm的macrolib,玄铁E902与M0-plus相当,玄铁E906、玄铁E907与M4相当。

ABI

目前,社区正在设计、制定针对嵌入式领域的新的ABI——EABI(Embedded ABI),它不仅会调整Calling Convention以减少中断延迟,也会考虑代码密度,使用量化分析地方法设计出一套对嵌入式领域优化的ABI。平头哥作为EABI Task Group的Co-Chair,也参与其中推动EABI的前进。

作为平头哥玄铁系列科普文章之一,以上是本文关于RISC-V代码密度的介绍及平头哥在其中的优化成果的简介,更多关于RISC-V指令集优劣势分析等内容可参见后续文章。

相关文章
|
10月前
|
缓存 测试技术 数据中心
【计算机架构】计算 CPU 动态功耗 | 集成电路成本 | SPEC 基准测试 | Amdahl 定律 | MIPS 性能指标
【计算机架构】计算 CPU 动态功耗 | 集成电路成本 | SPEC 基准测试 | Amdahl 定律 | MIPS 性能指标
382 0
如何用晶体管构建异或门
。XOR ,异或的缩写,它是一种逻辑运算,当高电平输入的数量为奇数时,产生高电平输出;当低电平输入的数量为偶数时,产生低电平输出。这种独特的特性使异或门成为各种应用中的重要组成部分,从简单的二进制算术到复杂的数据加密算法。 在本文中,我们将探讨异或门的内部工作原理,包括其真值表、逻辑符号表示、电路图以及使用晶体管的实际构造。
783 0
|
10月前
|
存储 并行计算 编译器
【计算机架构】程序指令计数 | 功耗计算 | 电力功耗 | 安德尔定律(Amdahl‘s Law)
【计算机架构】程序指令计数 | 功耗计算 | 电力功耗 | 安德尔定律(Amdahl‘s Law)
94 1
|
机器学习/深度学习 人工智能 缓存
英伟达用AI设计GPU算术电路,面积比最先进EDA减少25%,速度更快、更加高效
英伟达用AI设计GPU算术电路,面积比最先进EDA减少25%,速度更快、更加高效
239 0
|
存储 数据格式
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-3
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-3
1126 0
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-3
|
开发者
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-4
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-4
429 0
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-4
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-1
实验目的 1. 了解和熟悉指令级模拟器。 2. 熟练掌握MIPSsim模拟器的操作和使用方法。 3. 熟悉MIPS指令系统及其特点,加深对MIPS指令操作语义的理解。 4. 熟悉MIPS体系结构。
759 0
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-2
同济大学系统结构 实验一:MIPS指令系统和MIPS体系结构-2
500 0
|
存储 算法 IDE
数字信号处理-04- FPGA常用运算模块-除法器(一)
数字信号处理-04- FPGA常用运算模块-除法器
1241 0
数字信号处理-04- FPGA常用运算模块-除法器(一)
|
算法 异构计算
数字信号处理-03- FPGA常用运算模块-乘加器
数字信号处理-03- FPGA常用运算模块-乘加器
262 0
数字信号处理-03- FPGA常用运算模块-乘加器