我已将此简单代码提供给gcc
volatile signed char x, y, z;
void test()
{
x = 0x31;
y = x + 3;
}
添加易失性只是为了避免gcc优化(无论如何都设置为-O0)。 结果mips代码是:
x:
y:
z:
test():
addiu $sp,$sp,-8
sw $fp,4($sp)
move $fp,$sp
lui $2,%hi(x)
li $3,49 # 0x31
sb $3,%lo(x)($2)
lui $2,%hi(x)
lbu $2,%lo(x)($2)
seb $2,$2
andi $2,$2,0x00ff
addiu $2,$2,3
andi $2,$2,0x00ff
seb $3,$2
lui $2,%hi(y)
sb $3,%lo(y)($2)
nop
move $sp,$fp
lw $fp,4($sp)
addiu $sp,$sp,8
j $31
nop
对于(y = x + 3),gcc将字节加载为无符号,然后用符号扩展它,然后用0xff加载它? 为什么不简单地使用lb加载它(它应该签署扩展它)? GCC对签名的半个单词也是如此(当然使用0xffff)。
答案 0 :(得分:1)
我并不是特别擅长阅读MIPS程序集,但请注意您已使用-O0
进行编译,这应该会生成未经优化的代码。这或多或少意味着实现C抽象机器的确切语义的代码。特别是,
0x31
是int
x = 0x31
包含右侧int
操作数与左侧操作数类型(signed char
)的隐式转换(在本例中)3
也是int
x + 3
涉及对参数执行整数提升,特别是将signed char
的值x
转换为(已签名)int
,然后执行添加y
涉及从int
到signed char
的另一种隐式转换原则上,C代码中隐含的所有转换和促销都需要由未经优化的汇编程序明确执行,而这看起来大致就是您所看到的。
总的来说,问及为什么非优化编译的汇编输出不如您想象的那样高效,这并不是很有用。如果您想要更高效的代码,启用优化。
答案 1 :(得分:0)
gcc -march = native -O3在Intel计算机上提供以下代码:
test:
.seh_endprologue
movb $49, x(%rip)
movzbl x(%rip), %eax
addl $3, %eax
movb %al, y(%rip)
ret
.seh_endproc
.comm z, 1, 0
.comm y, 1, 0
.comm x, 1, 0
.ident "GCC: (GNU) 6.4.0"
您的代码没有任何问题。 gcc / MIPS在代码生成方面并不擅长,这并不太令人惊讶,因为它比gcc / Intel得到的关注和关注要少得多。根据我的经验,clang通常会生成比gcc更好的MIPS代码。