字节上的gcc mips有符号算术

字节上的gcc mips有符号算术,c,gcc,mips,C,Gcc,Mips,我已经将这个简单的代码提供给了gcc volatile signed char x, y, z; void test() { x = 0x31; y = x + 3; } 添加Volatile只是为了避免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

我已经将这个简单的代码提供给了gcc

   volatile  signed char x, y, z;

void test()
{
    x = 0x31;
    y = x + 3;
}
添加Volatile只是为了避免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)也有同样的作用。

我并不特别擅长读取MIPS程序集,但请注意,您已经使用
-O0
进行了编译,它应该生成未优化的代码。这或多或少意味着代码实现了C抽象机器的精确语义。特别是,

  • 0x31
    是类型为
    int
  • 赋值
    x=0x31
    包括将右侧
    int
    操作数隐式转换为左侧操作数的类型(
    有符号字符
  • 3
    也是类型
    int
  • 计算
    x+3
    涉及对参数执行整数提升,特别是将
    x
    signed char
    值转换为(signed)
    int
    ,然后执行加法
  • 将结果赋给
    y
    涉及另一个从
    int
    有符号字符的隐式转换
原则上,C代码中隐含的所有转换和升级都需要由未优化的汇编程序显式执行,这似乎就是您所看到的


总的来说,询问为什么非优化编译的程序集输出没有您想象的那么有效是没有多大用处的。如果需要更高效的代码,请启用优化。

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代码