c - 有没有一个技巧可以让 GCC 优化掉多余的指令?
问题描述
编译gcc -mcpu=cortex-m0 -mthumb -Os
会发出冗余指令,如本说明性示例中所示:
void memzero(void* p, int n)
{
n -= 4;
do
{
*(int*)((char*)p + n) = 0;
n -= 4;
}
while(n > 0);
}
结果是:
memzero:
movs r3, #0
subs r1, r1, #4
.L2:
str r3, [r0, r1]
subs r1, r1, #4
cmp r1, #0
bgt .L2
bx lr
显然,显式比较本质上是一个 nop。有没有办法打开更多优化来解决这个问题?
解决方案
删除比较会改变函数的行为。
如果.BGT
则指令跳转Z == 0 and N == V
。这在n
溢出时很重要。
考虑使用n = -2147483644
(如果int
是 32 位)调用该函数:
memzero:
movs r3, #0
subs r1, r1, #4 ; n = -2147483648
.L2:
str r3, [r0, r1]
subs r1, r1, #4 ; n = 2147483644, Z = 0, N = 0, V = 1
;cmp r1, #0 ; (would set Z = 0, N = 0, V = 0)
bgt .L2 ; doesn't jump, even though n is positive
bx lr
如果我们测试,优化就会起作用,n >= 0
因为如果有一条指令会跳转N == 0
:
memzero:
movs r3, #0
subs r1, r1, #4
.L2:
str r3, [r0, r1]
subs r1, r1, #4
bpl .L2
bx lr
测试程序
#include <stdio.h>
#include <limits.h>
__attribute__((noinline)) int with_cmp(int n) {
asm("L1:\n\t"
"subs %[n], #4\n\t"
"cmp %[n], #0\n\t"
"bgt L1"
: [n] "+r" (n));
return n;
}
__attribute__((noinline)) int without_cmp(int n) {
asm("L2:\n\t"
"subs %[n], #4\n\t"
"bgt L2"
: [n] "+r" (n));
return n;
}
int main() {
printf("with cmp: %d\nwithout cmp: %d\n", with_cmp(INT_MIN), without_cmp(INT_MIN));
}
输出:
with cmp: 0 // loops as long as n > 0
without cmp: 2147483644 // immediately returns with positive n
推荐阅读
- apache - 重定向后 Apache RewtireRule 不保存 URL
- javascript - 尝试发送请求时出现“405 方法不允许”错误。通过 JS 获取 API 到 PHP 文件
- laravel-5.8 - 创建迁移时错误地形成了外键约束
- android - 申请报告需要很长时间才能更新
- python - Python 集成测试:使用 paramiko 伪造一个 ssh 服务器,并记录给它的命令
- angular - 如何在另一个 Angular 应用程序中导入 Angular Web 组件
- node.js - 如何将多个查询值添加到 url
- java - 如何链接 reactor 订阅者
- linux - 为什么 Centos 7 的 Docker 文件不支持 yum 命令
- java - 声纳,在 setter POJO 上使用 private 以避免重复