gcc mips在字节上签名算术

时间:2017-12-19 16:49:47

标签: c gcc mips

我已将此简单代码提供给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)。

2 个答案:

答案 0 :(得分:1)

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

  • 0x31int
  • 类型的常量
  • 赋值x = 0x31包含右侧int操作数与左侧操作数类型(signed char)的隐式转换(在本例中)
  • 3也是int
  • 类型的常量
  • 评估x + 3涉及对参数执行整数提升,特别是将signed char的值x转换为(已签名)int,然后执行添加
  • 将结果分配给y涉及从intsigned 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代码。