首页 > 解决方案 > 零/符号扩展是无操作的,为什么每种尺寸类型的说明?

问题描述

对于 x86 和 x64 编译器生成类似的零/符号扩展 MOVSX 和 MOVZX。扩展本身不是免费的,但允许处理器执行无序的魔法加速。

但在 RISC-V 上:

因此,无符号和有符号 32 位整数之间的转换是无操作的,从有符号 32 位整数到有符号 64 位整数的转换也是如此。

加法和移位需要一些新指令 (ADD[I]W/SUBW/SxxW) 以确保 32 位值的合理性能。

(C) RISC-V 规范

但同时,新的现代 RISC-V 64 位处理器包含 32 位有符号整数的指令。为什么?提高性能?那么 8 位和 16 位在哪里呢?我已经什么都不懂了。

标签: assemblyriscvsign-extensionzero-extension

解决方案


完整的报价对我来说似乎很清楚:

编译器和调用约定保持不变,即所有 32 位值都以符号扩展格式保存在 64 位寄存器中。甚至 32 位无符号整数也将第 31 位扩展到第 63 到 32 位。

因此,无符号和有符号 32 位整数之间的转换是无操作的,从有符号 32 位整数到有符号 64 位整数的转换也是如此。
现有的 64 位宽 SLTU 和无符号分支比较仍然在此不变量下对无符号 32 位整数正确运行。
同样,对 32 位符号扩展整数的现有 64 位宽逻辑运算保留符号扩展属性。

加法和移位需要一些新指令 (ADD[I]W/SUBW/SxxW) 以确保 32 位值的合理性能。

它表示 32 位值存储在 64 位寄存器中,其 MSb(最高有效位)通过位 32-63 重复。
这对符号和无符号整数都是如此。

这允许进行一些优化,如报价中所述:

  • 无符号 <-> 有符号转换是免费的。
    将此与通常的算法进行比较,您必须将低 32 位值归零或符号扩展以将其提升为不同“符号”的 64 位值(忽略溢出)。
  • 带符号的 32 位 <-> 带符号的 64 位是免费的。
    这省去了一个符号扩展。
  • 分支和设置指令仍然有效。
    这是因为重复 MSb 不会改变比较结果。
  • 逻辑 64 位操作保留了这个属性
    通过几个例子很容易看出这一点。

然而,加法(仅举一个例子)并没有保留这个不变量: 0x000000007fffffff + 0x0000000000000001 = 0x0000000080000000 这违反了假设。

由于 a) 使用 32 位值经常发生并且 b) 修复结果需要额外的工作(我可以考虑使用slli/srai对),因此引入了一种新的指令格式。
这些指令对 64 位寄存器进行操作,但只使用它们的低 32 位值,并对 32 位结果进行符号扩展。
这很容易在硬件中完成,因此值得拥有这种新的指令。

正如评论中所指出的,8 位和 16 位算术很少见,因此没有花费任何工程精力为其寻找新空间(无论是在所需的门方面还是在使用的操作码空间方面)。


推荐阅读