合作Oncomputer

在基于risc - v的应用中最小化代码占用的技术

2021年11月11日,
在本文中,我们将了解开发人员如何帮助编译器做出更好的决定,以便在基于RISC-V的应用程序中实现优化。

本文是本文的一部分TechXchange开发高质量的软件

成员可以以PDF格式下载此文章。

你将学习:

  • RISC-V支持的标准扩展。
  • 帮助编译器做出更好决策的提示。
  • 避免写作“聪明代码”的原因。


RV32I是可以获得列出的标准扩展的基本指令集图1, 如:

  • (整数乘法)
  • (原子指令)
  • F(单浮点)
  • D(双浮点)
  • C(压缩指令)
  • B(操作)
  • 等等…。


大多数扩展(图。1)批准或冻结,但目前正在制定新的协议。在各种核心中支持扩展的示例可以在图2


如果我们拍摄了通用设备RV32,我们可以认识到它支持M,F,D和C. C(压缩指令)通过添加短的16位指令进行操作来降低静态和动态代码大小,从而平均25% -减少30%的码大小,并导致较低的功耗和内存使用。另外,RV32E基本指令集(嵌入式)旨在为具有16个寄存器的嵌入微控制器提供甚至更小的基础核心。

设计师可以自由地为特定需求实现自己的扩展,例如,机器学习,低功耗应用,或计量和电机控制的优化SoC。标准扩展或自定义扩展的目的是实现在硬件中执行的计算和处理的更快响应时间,这些计算和处理通常需要一个或几个周期。

为什么使用专业的RISC-V工具?

随着RISC-V的发展,出现了对能够充分利用核心特性和扩展的专业工具的需求。一个精心设计和优化的SoC还应该运行最佳优化的代码,以便公司能够快速创新,拥有优秀的产品,并从中获得最佳的成本效益。

当涉及代码密度时,每个可以保存计数的字节。专业工具有助于优化应用程序,以最适合所需的需求。通过优化应用程序,通过向现有平台添加功能,客户将能够通过使用具有较小内存或聚合值的设备来节省资金(图3)


与其他工具相比,RISC-V的专业编译器可以平均生成7%-10%的较小代码。

为更好的优化编写编译器友好的代码

优化编译器尝试通过以最佳顺序选择正确的指令来生成小而快速的代码。它通过重复将多个转换应用于源程序来实现。大多数优化基于声音理论基础遵循数学或逻辑规则。其他转型基于启发式,经验表明,一些转换通常会导致良好的代码或开辟进一步优化的机会。

因此,您编写源代码的方式可以决定是否可以将优化应用于您的程序。有时,源代码中的微小更改可能会显著影响编译器生成的代码的效率。

尝试在尽可能少的行上编写代码,使用?:-表达式、后加和逗号表达式来将大量的副作用压缩在一个表达式中,不会使编译器生成更高效的代码。最好的提示是用一种易于阅读的风格编写代码。

开发人员可以通过注意源代码中的以下提示来帮助编译器做出更好的决策:

1.只调用一次函数。编译器通常很难查看公共子表达式,因为这些子表达式可能有副作用,编译器可能不知道它们是否必要。因此,编译器在接到指令时将多次调用同一个函数,这会浪费代码空间和执行开销。最好将函数赋值给一个变量(该变量很可能存储在寄存器中),并在一个容易访问的寄存器中执行操作(图4)


2.通过引用而不是复制传递。当你传递一个指向原语而不是原语本身的指针时,你为编译器节省了在RAM或寄存器中复制该原语的开销。对于大型数组,这可以节省相当多的执行时间。传递copy将强制编译器插入代码来复制原语的内容。

3.使用正确的数据大小。一些MCU,如8051或AVR是8位微观方式;一些像MSP430的人是16位;有些像ARM和RISC-V一样是32位。When using an “unnatural” size for your core, then the compiler must create extra overhead to interpret the data contained therein, e.g., a 32-bit MCU will need to do shift, mask, and sign-extend operations to get to the value needed to perform its operation. It’s therefore best to use the natural size of the MCU for your data types unless there’s a compelling reason not to, i.e.. doing I/O. You also need a precise number of bits, or bigger types (such as a character array) would take up too much memory.

4.适当地使用signedness。变量的符号可以影响编译器生成的代码。例如,根据C语言的规则,对负数的除法与对正数的除法是不同的。因此,如果您在应用程序中使用一个永远不会为负数的有符号数字,您可能会在代码中产生额外的测试-跳转条件,从而浪费代码空间和执行时间。此外,如果变量的目的是进行位操作,那么它应该是无符号的,否则在进行移位和屏蔽时可能会产生意想不到的结果。

5.避免成为漂流者。C语言通常会执行隐式类型转换(例如,在浮点数和整数之间,在整型数和长整型之间),而这些都是不自由的。从较小的类型强制转换为较大的类型将使用符号扩展操作,与浮点数进行强制转换和与浮点数进行强制转换将引入对浮点库的需求(这会极大地增加代码的大小)。当然,您应该尽可能避免进行显式强制转换,以避免这种额外的开销。当习惯于交替使用整型数和函数指针的桌面程序员跳转到嵌入式编程时,很容易看到这个问题(图5)


6.使用函数原型。如果原型不存在,那么C语言规则规定必须将所有参数提升为整数,并且如前所述,这可能会链接到运行时库的不必要开销。

7.将全局变量读入临时变量。如果您在函数中多次访问全局变量,则可能希望将其读入本地临时变量。否则,每次访问此变量时,都需要从内存中读取。通过将其放入本地临时变量,编译器可能会将寄存器分配给值,以便可以更有效地对其执行操作(图6)


8.避免内联装配。使用内联组件对优化器具有非常有害的影响。由于优化器无关代码块的内容,因此无法优化它。此外,它无法做手写块的指令调度,因为它不知道代码正在做什么(这可能对DSPS尤其损害)。在此之上,开发人员必须每次都检查手写代码,以确保它正确地散布在优化的C代码中,以便它不会产生意外的副作用。内联汇编程序的可移植性非常差,因此如果您决定将其转移到新的架构中,需要重写(并理解其后果)。如果必须在线汇编程序,则应将其拆分到自己的汇编程序文件中,并将其与源分开。

9.不要编写聪明的代码。一些开发人员错误地认为,编写更少的源代码行并巧妙地使用C结构将使代码更小或更快(也就是说,他们正在为它做编译器的工作)。其结果是代码难以阅读,除了最初编写它的人之外,任何人都无法理解,而且更难编译。以一种清晰和直接的方式编写它可以提高代码的可读性,并帮助编译器在如何最好地优化代码方面做出更明智的决定。

例如,假设我们想要设置一个变量b的最低位,如果另一个变量的最低21位已经设置。聪明的代码使用!操作符,如果实参不为零则返回0 (C中的“true”是除零以外的任何值),如果实参为零则返回1。简单的解决方案很容易编译成一个条件语句,后面跟着一个设置位指令,因为位设置操作很明显,屏蔽可能比移位更有效。理想情况下,这两个解决方案应该生成相同的代码。然而,聪明的代码可能会导致更多的代码,因为它执行两个!操作,每个操作都可以编译成一个条件(图7)


另一个例子涉及在计算中使用条件值。的“聪明”代码将导致更大的机器代码自生成的代码将包含相同的测试简单的代码,并添加了一个临时变量来保存一个或零添加str。简单的代码可以使用一个简单的增量,而不是一个完整加法和不需要中间结果的产生(图8)


10.存取结构按顺序排列。如果你秩序结构,从结构的一个元素到另一个而不是跳来跳去的结构,编译器可以利用增量操作访问下一个元素的结构,而不是试图从结构计算它的偏移指针。在静态分配结构中,这样做不会节省代码,因为地址是预先计算的。然而,在大多数应用程序中,这些都是动态完成的。

结论

嵌入式编译器在过去的30年中已经发达了很大发展,特别是因为它与他们的优化能力有关。现代编译器采用许多不同的技术来产生非常紧凑和有效的代码,以便您可以专注于以明确,逻辑和简洁的方式编写您的来源。每个开发人员都致力于在其软件中实现最佳效率。编译器是一种非常复杂的软件,能够优化的优化水平,但通过遵循这些简单的提示,您可以帮助它实现更大的效率。

阅读更多文章TechXchange开发高质量的软件

从我们的合作伙伴

物联网设备调试工具和技术的专业指南

2021年3月23日
嵌入式系统的开发,其中软件和硬件必须很好地结合在一起,已经变得极其复杂和具有挑战性,甚至……

探索集成电源的简单性和可扩展性

我们可扩展的双轨至完全集成的PMICs利用我们领先的电源技术,用更少的组件降低系统复杂性。建-…

欢迎来到边缘

照片/图像致谢(按显示顺序排列)。pinkeyes - stock.adobe.com, Monopoly919 - stock.adobe.com, proindustrial2 - stock.adobe.com。加入我们…

超高可靠性和低延迟

就在你读这篇文章的时候,5G正在美国推广。有些人有5G兼容的手机,可以连接到AT&T、T-Mobile等公司的网络。

用于自动化和工业4.0的M12连接器编码

赞助。用于自动化和工业4.0的连接器编码| 1。连接器在任何类型的电的持续运行中都是至关重要的。

理解和使用e - stop

问:什么是电子车站,它是如何使用的?答:为确保机器及人员的安全,使用e -stop或紧急停止开关。他们正在使用……

声音你的意见!

本网站要求您注册或登录后才能发表评论。
目前还没有任何评论。想开始谈话吗?

从我们的合作伙伴

物联网设备调试工具和技术的专业指南

嵌入式系统的开发,其中软件和硬件必须很好地结合在一起,已经变得极其复杂和具有挑战性,甚至……

探索集成电源的简单性和可扩展性

我们可扩展的双轨至完全集成的PMICs利用我们领先的电源技术,用更少的组件降低系统复杂性。建-…

欢迎来到边缘

照片/图像致谢(按显示顺序排列)。pinkeyes - stock.adobe.com, Monopoly919 - stock.adobe.com, proindustrial2 - stock.adobe.com。加入我们…

超高可靠性和低延迟

就在你读这篇文章的时候,5G正在美国推广。有些人有5G兼容的手机,可以连接到AT&T、T-Mobile等公司的网络。

用于自动化和工业4.0的M12连接器编码

赞助。用于自动化和工业4.0的连接器编码| 1。连接器在任何类型的电的持续运行中都是至关重要的。
穆罕默德·安瓦鲁·卡比尔·乔杜里,Dreamstime.com
起搏器穆罕默德ANWARUL KABIR Choudhury Dreamstime L 51106898
Baidu