首先叙述下我的问题,编译器是 64bit 编译器,主要代码如下:
#define _BIT(n) (((unsigned )(1)) << (n))
void __write_icr(int idx, unsigned short value, int irq)
{
printk("icr_dump %d %d %d %p %p %p\n", irq, idx, value, &idx, &value, &irq);
}
int main()
{
for(int i = 1; i < 63; i++){
__write_icr(i>>4, _BIT( (i & 0x1F) ), i);
}
return 0;
}
我省略了其他无关代码, 主要就是 main 函数里调用 __write_icr 函数。 注意 __write_icr 的第二个参数是 unsigned short 类型.
我提取了编译的中间文件,main 函数里的循环对应汇编如下:
.L31:
add x19, x19, 1
cmp x19, 2
bne .L33
mov w19, 1
.loc 1 371 0
mov w20, w19
.L34:
mov w2, w19
lsl w1, w20, w19
asr w0, w19, 4
bl __write_icr
.LVL89:
add w19, w19, 1
cmp w19, 63
bne .L34
mov w0, 64
不知道为什么,(i & 0x1F) 这个操作被编译器忽略掉了, 导致后续传到 __write_icr 的数据不对。
但如果我吧 __write_icr 第二个类型修改为 unsigned int value, 编译出来就感觉是正确的。
.L31:
add x19, x19, 1
cmp x19, 2
bne .L33
mov w19, 1
.loc 1 371 0
mov w20, w19
.L34:
and w1, w19, 15
mov w2, w19
lsl w1, w20, w1
asr w0, w19, 4
bl __write_icr
.LVL89:
add w19, w19, 1
cmp w19, 63
bne .L34
mov w0, 64
其中会有这句 (and w1, w19, 15), 对应着 (i & 0x1F)。 试了很多次,原因就是使用 short 类型时这句话时这个与操作被编译器优化掉了,这个是正常的吗,还是我自己理解太浅了。。。
请各位大神帮忙指点下
1
billlee 2018-07-19 22:56:03 +08:00 1
不知道你这是什么架构。但我知道 x86 上的 shl, 本来就只会用 cl 中的低 5 位。所以 x86 的编译器开优化的时候一定会把那个 & 0x1f 优化掉。
|
2
billlee 2018-07-19 23:20:07 +08:00 1
不对,肯定还有哪里遇到 undefined behaviour 了
https://gist.github.com/BillLeecn/846d96ec6a5f360d9b962e53a2acf56a 这代码在 gcc -O0 下输出 0 1, -O1 下输出 0 0 |
3
Panic OP @billlee 谢了, 现在搞明白了, 确实是 编译器的 bug, 找了好几天最终定位了, 之前这里贴的应该没到定位点。
这个问题是 arm64 平台专用且遗留的问题, 在普通 gcc 和 arm 平台上都是没问题的。15 年就被修复了, 我这边厂家提供的编译器正好是有问题的。 对应的说明和 patch 在这里: https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=64304 |