gcc mips在字节上签名算术

问题描述 投票:2回答:2

我把这个简单的代码提供给了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)。

c gcc mips
2个回答
1
投票

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

  • 0x31int类型的常数
  • 赋值x = 0x31包含右手int操作数与左手操作数类型的隐式转换(在本例中)(signed char
  • 3也是int类型的常数
  • 评估x + 3涉及对参数执行整数提升,特别是将signed charx值转换为(signed)int,然后执行加法
  • 将结果分配给y涉及从intsigned char的另一个隐式转换

原则上,C代码中隐含的所有转换和促销都需要由未经优化的汇编程序明确执行,而这看起来大致就是您所看到的。

总的来说,问及为什么非优化编译的汇编输出不如你想象的那样高效,这并不是很有用。如果您想要更高效的代码,请启用优化。


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

© www.soinside.com 2019 - 2024. All rights reserved.