gcc优化问题:unsigned mod vs if branch
Gcc optimization question: unsigned mod vs if branch
我有一个在实时微控制器程序 (ARM Cortex-M) 中经常调用的函数(每秒至少 40,000 次),它基本上在缓冲区的长度内保留一个计数器,它是不是二的幂。
所以我可以选择以下两个选项之一:
extern uint32_t x;
void increment_MOD(void)
{
x = (x + 1) % 100;
}
或
void increment_IF(void)
{
uint32_t tmp = x + 1;
if (tmp >= 100)
tmp = 0;
x = tmp;
}
除非我错了,否则这两个在功能上似乎是等价的,所以:
GCC 将其中之一优化为更快的形式(无论哪个)是否不正确?
看起来 "if" 版本仍然会更快,除非 pipeline/branch 预测错误是一个问题(但 ARM Cortex-M cpus 没有大型管道 AFAIK)。
// it's nice to see that % is implemented
// using multiplication and shifts
increment_MOD:
ldr r1, .L2
ldr r3, .L2+4
ldr r2, [r1]
add r2, r2, #1
umull r0, r3, r2, r3
lsr r3, r3, #5
add r3, r3, r3, lsl #2
add r3, r3, r3, lsl #2
sub r3, r2, r3, lsl #2
str r3, [r1]
bx lr
.L2:
.word x
.word 1374389535
// this is the IF variant
increment_IF:
ldr r2, .L6
ldr r3, [r2]
add r3, r3, #1
cmp r3, #99
movhi r3, #0
str r3, [r2]
bx lr
.L6:
.word x
优化无效,因为编译器无法从代码中得知输入函数时 x
永远不会 >99。如果使用 x=100
进入函数,那么在函数 increment_IF
的出口处使用 if 分支 x=0
,而对于 mod 变体 increment_MOD
你得到x=1
.
我有一个在实时微控制器程序 (ARM Cortex-M) 中经常调用的函数(每秒至少 40,000 次),它基本上在缓冲区的长度内保留一个计数器,它是不是二的幂。
所以我可以选择以下两个选项之一:
extern uint32_t x;
void increment_MOD(void)
{
x = (x + 1) % 100;
}
或
void increment_IF(void)
{
uint32_t tmp = x + 1;
if (tmp >= 100)
tmp = 0;
x = tmp;
}
除非我错了,否则这两个在功能上似乎是等价的,所以:
GCC 将其中之一优化为更快的形式(无论哪个)是否不正确?
看起来 "if" 版本仍然会更快,除非 pipeline/branch 预测错误是一个问题(但 ARM Cortex-M cpus 没有大型管道 AFAIK)。
// it's nice to see that % is implemented
// using multiplication and shifts
increment_MOD:
ldr r1, .L2
ldr r3, .L2+4
ldr r2, [r1]
add r2, r2, #1
umull r0, r3, r2, r3
lsr r3, r3, #5
add r3, r3, r3, lsl #2
add r3, r3, r3, lsl #2
sub r3, r2, r3, lsl #2
str r3, [r1]
bx lr
.L2:
.word x
.word 1374389535
// this is the IF variant
increment_IF:
ldr r2, .L6
ldr r3, [r2]
add r3, r3, #1
cmp r3, #99
movhi r3, #0
str r3, [r2]
bx lr
.L6:
.word x
优化无效,因为编译器无法从代码中得知输入函数时 x
永远不会 >99。如果使用 x=100
进入函数,那么在函数 increment_IF
的出口处使用 if 分支 x=0
,而对于 mod 变体 increment_MOD
你得到x=1
.