如何干预编译器的优化行为

适用于平头哥的CK801,CK802,E902,E906内核的芯片。

我们熟悉的优化等级O0,O1...其实都是一长串优化指令的集合。在大多数时候是默认可用的。一般量产版本中,速度优先,选择O2;代码大小优先,选择Os。

但对某些场景,可能需要我们加入人为干预,才可能让代码以我们预想的方式运行。

1. 编译优化有可能带来的问题

  • 对调试的影响:任何级别的优化都将带来代码结构的改变。例如:对分支的合并和消除,对公用子表达式的消除,对循环内load/store操作的替换和更改等,都将可能会使目标代码的执行顺序变得和我们预想的不一样,导致调试信息不足(如:断点错位或运行不到)。

  • 内存操作顺序改变:在O2优化后,编译器会对影响内存操作的执行顺序和执行效果。例如:

    • -fschedule-insns允许数据处理时先完成其他的指令。

    • 多处共享变量的时候,编译器并不知道该变量值会被别的程序修改,因此在它进行优化的时候,可能会把值先读入某个寄存器,然后等待那个寄存器的改变。

这里主要针对内存操作顺序的改变讲两种干预行为。

2. 阻止编译器对某些变量的优化

可以通过加volatile关键字,告诉编译器每次都从具体的地址去取值,而不是什么中间的buffer,如工作寄存器。我们驱动中所有寄存器前的属性定义都有volatile关键字。因为很多寄存器值是硬件可能会去改的。一个最简单的例子就是GPIO的PSDR。

具体可以参考C语言环境中的VOLATILE关键字说明

3. 阻止编译器乱序执行

为了充分利用流水线,CPU指令可以是乱序执行的,一种相对常见的处理是对读写指令重新排序。在大多数应用场景下,这些优化是透明的(无害的),而且效率很好。但在一些特殊情况下,代码必须以特性顺序执行的时候,这种优化就可能引入一些莫名奇妙的现象。

我们需要用设置内存屏障(memory barrier)的方式打破流水线,重新构建执行顺序。具体可以通过插入以下代码(二选一):

asm __volatile__("sync": : :"memory"); /*<sync是c-csky特有指令,全系列CPU可用>*/
asm __volatile__("fence");            /*<fence是riscv通用指令,e906和e902同时支持fence和sync>*/

这段话告诉编译器:不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,先将它前面的指令都执行完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值