【问题标题】:Is there a way to perform arithmetic right shift using only xorq, andq, addq, iaddq, & subq?有没有办法只使用 xorq、andq、addq、iaddq 和 subq 来执行算术右移?
【发布时间】:2018-11-19 20:35:46
【问题描述】:

我在一个假设的架构中,只有这些操作 (Y86)。不存在算术右移。我实际上是在尝试捕获最高位以确定该数字是否为负数,如果是,则将其添加到结果寄存器 rax。

编辑:

对不起,我忘了指定,我正在尝试避免条件分支,看看它是否提高了效率。我所在的版本中不存在 cmov。

我得到的最远的是:

andq $0x10000000, elem
subq $0x01111111, elem
addq elem, %rax

但是,对于 0 的结果,这不起作用。

【问题讨论】:

  • y86 确实有条件跳转。还有一些版本有 cmov。
  • 可以使用条件分支吗?你可以使用循环吗?
  • 没有mov?或者您可以使用add 作为负载,具有内存源和归零目标(来自异或归零)?如果是这样,您可以一次为 1 个字节创建一个查找表。也许是一个有用的构建块? (使用未对齐的存储到缓冲区+存储零,您应该能够隔离 qword 的 1 个字节)。但是,很难使用,并且无助于结果字节之间的进位。 LC3 Assembly Bitwise Right Shift 是关于另一个缺少右移的 ISA。
  • 您如何定义“效率”?没有物理 y86 CPU。如果您指的是在解释器中运行时的性能,那么请记住,y86 代码中的控制依赖关系将成为解释器中的数据依赖关系,因此分支错误预测不是直接的事情。 (如果使用间接分支为每个操作码分派到处理程序,解释器中的分支未命中通常来自指令组合的变化。)或者您是否在想象具有预取 + 分支预测但仍然没有右移的假设物理 y86?
  • @phuclv i 是即时的。 y86 在助记符中对其进行编码,类似于 mips,mips 也有 addaddi(顺便还有无符号版本 adduaddiu,尽管它们仅在溢出信号方面有所不同)

标签: assembly y86


【解决方案1】:

如果 Y86 允许 MOVQ 访问不是 QWORD 对齐的内存,则可以这样做。 但我怀疑它是否会比条件分支更好。

诀窍是将数字写入内存, 然后从稍微“关闭”的地址再次读取它。这有效地将位移动到 8 的倍数。将其与 addq 结合使用可将位向左移动 1 位。

请注意,这高度依赖于处理器架构的字节顺序。 以下示例基于 little endian(Intel 风格)。 在 big endian 上,必须调整偏移量。

(如果您更喜欢 AT&T 语法,请反转操作数并删除括号。)

movq rbx,number         ; sign bit is bit 63 of rbx
movq [address],rbx      ; sign bit is most significant bit of the byte at [address+7]
movq rbx,[address+4]    ; sign bit is bit 31 of rbx
addq rbx,rbx            ; sign bit is bit 32 of rbx
movq [address],bx       ; sign bit is least significant bit of the byte at [address+4]
movq rbx,[address+4]    ; sign bit is bit 0 of rbx
andq rbx,1              ; rbx = 0 for positive number, rbx = 1 for negative number
addq ax,bx

【讨论】:

  • 您的意思是“您更喜欢 AT&T 语法”?因为您的代码看起来像 Intel 语法。但是英特尔语法没有这样的后缀,addq ax, bx 不正确,因为后缀应该是 w
  • @phuclv 感谢您指出这一点,我调整了注释。我的组装经验已经过时了。请将我的代码示例视为伪代码。我相信读者会理解其意图。
【解决方案2】:

假设您可以使用循环和条件分支:

    mov result, 0
    mov lead, 2
    mov follow, 1
1:
    mov tmp, n
    and tmp, lead
    jz 2f
    add result, follow
2:
    add follow, follow
    add lead, lead
    jnz 1b

tmp、lead 和 follow 变量必须在寄存器中。结果可以在寄存器或内存中。

【讨论】:

  • 这个符号位的副本是如何移动的?在add lead,lead 离开lead=0 之后,您不会将最高位移入零吗?嗯,我猜由于移位计数固定为 1,我们可以只 and n, 1<<63 并添加它,将原始符号位复制到逻辑右移结果中。除了将其正常移动到第 62 位之外,我们不需要将其复制到任何较低的位置。
  • 糟糕,我完全忽略了您想要 算术 右移(可能是因为我认为我从未使用过 :-))。 @彼得
猜你喜欢
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 2021-02-24
  • 2018-09-23
  • 2019-06-18
  • 1970-01-01
相关资源
最近更新 更多