GCC为何不优化MIPS下立即数指针赋值,该特性如何关闭
优化原因
这个操作是GCC针对MIPS架构的指令特性做的默认性能优化,底层逻辑如下:
- MIPS架构的
lw/sw等访存指令仅支持16位有符号立即数作为偏移,可覆盖-32768~32767的地址范围。而加载32位完整立即数到寄存器,默认需要两条指令:lui加载高16位,再加一条算术指令拼接低16位。 - 你示例中的指针地址是
0x30000004,GCC会自动提取所有访问地址的公共高16位0x3000作为基址存到$v1,后续所有访存操作的偏移直接加上低16位的差值,相当于把拼接低16位的指令开销合并到了访存指令的偏移字段里,最终生成的代码比你期望的写法少一条指令,代码体积更小、执行效率更高。
关闭方法
可以通过编译选项或代码修改关闭该特性,得到你期望的汇编输出:
- 全局关闭(编译参数方案)
编译时添加-fno-section-anchors选项,关闭GCC的段锚点基址复用优化即可。如果开启了全局指针优化,可额外添加-mno-gpopt参数。
示例编译命令:
mips-linux-gnu-gcc-8 -O3 -nostdlib -fno-section-anchors test.c -c
- 针对单个指针关闭(代码修改方案)
给需要取消优化的指针加上volatile修饰,强制编译器不做地址合并:
int test(){ int * volatile tmp = (int*)0x30000004; tmp[0]++; return tmp[1]; }
注:你期望汇编中的
li v1,0x30000004是MIPS汇编伪指令,实际编译后会被展开为lui v1,0x3000+addiu v1,v1,4两条指令,比GCC默认生成的代码多一条指令,性能会略低。
内容的提问来源于stack exchange,提问作者krystalgamer
相关产品推荐
相关产品推荐

