我们可以将内容从较小的寄存器移动到较大的寄存器吗
can we move content from smaller register to larger register
例如,我们可以这样做吗:
movl %eax,%rdx // l means 32 bits while rdx is 64 biregister
所以如果我们将 %eax
的 32 位内容移动到 %rdx
,那么只有 %rdx
的低位 32 位得到更新?
没有直接写入 64 位 GPR 的低 32 位的方法,但可以通过清除低 32 位并将值按位或运算写入其中来模拟:
shr rdx, 32
shl rdx, 32
or rdx, rax ; assumes top 32 bits of rax are zero
或者使用双精度移位和旋转:
shrd rdx, rax, 32
ror rdx, 32
不幸的是,这比大多数处理器上的第一个版本有更高的延迟(可能 Core2 及其直接祖先除外),因为
(这种形式的)双精度移位通常需要 3 个周期。对于典型的英特尔处理器,它在某些情况下具有潜在优势,因为它总体上需要更少的微操作,但在 AMD Zen 和英特尔凌动上,shrd
需要少量微操作。所以一般来说应该首选第一个版本,但在特定情况下可能有理由使用第二个版本。
也有可能有两个重叠的存储和一个负载(这很慢,例如由于存储转发失败,Haswell 上有 16 个周期,即使没有遇到如此糟糕的微架构边缘情况,它也不会击败寄存器- 仅解决方案):
mov [rsp], rdx
mov [rsp], eax
mov rdx, [rsp]
movl %eax,%rdx
(等同于 mov %eax,%rdx
)不是有效指令。 MOV
的有效组合可以在 Instruction Set Architecture reference.
中找到
有几条指令可以从较小的寄存器移动到较大的寄存器。你可以使用 MOVZX
for zero extension (upper bits set to 0), or MOVSX
sign extension where the top most bit of the source register is copied into all the higher bits of the destination register. In 64-bit long mode if the destination of any instruction (including MOV
) 是一个 32 位寄存器然后相应的 64 位寄存器的高 32 位由处理器自动设置为 0。
这些示例表示从较小寄存器到较大寄存器的可用有效移动:
movzx %al, %dx # move 8-bit register to 16-bit register. Upper 8 bits of DX set to 0
movzx %al, %edx # move 8-bit register to 32-bit register. Upper 24 bits of EDX set to 0
# Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
movzx %al, %rdx # move 8-bit register to 64-bit register. Upper 56 bits of RDX set to 0
movzx %ax, %edx # move 16-bit register to 32-bit register.Upper 16 bits of EDX set to 0
# Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
#movzx %eax, %rdx # This instruction doesn't exist. Use mov %eax, %edx
movsx %al, %dx # Sign extend 8-bit register to 16-bit register
movsx %al, %edx # Sign extend 8-bit register to 32-bit register
# Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
movsx %al, %rdx # Sign extend 8-bit register to 64-bit register
movsx %ax, %edx # Sign extend 16-bit register to 32-bit register
# Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
movsx %ax, %rdx # Sign extend 16-bit register to 64-bit register
movsx %eax, %rdx # Sign extend 32-bit register to 64-bit register
例如,我们可以这样做吗:
movl %eax,%rdx // l means 32 bits while rdx is 64 biregister
所以如果我们将 %eax
的 32 位内容移动到 %rdx
,那么只有 %rdx
的低位 32 位得到更新?
没有直接写入 64 位 GPR 的低 32 位的方法,但可以通过清除低 32 位并将值按位或运算写入其中来模拟:
shr rdx, 32
shl rdx, 32
or rdx, rax ; assumes top 32 bits of rax are zero
或者使用双精度移位和旋转:
shrd rdx, rax, 32
ror rdx, 32
不幸的是,这比大多数处理器上的第一个版本有更高的延迟(可能 Core2 及其直接祖先除外),因为
(这种形式的)双精度移位通常需要 3 个周期。对于典型的英特尔处理器,它在某些情况下具有潜在优势,因为它总体上需要更少的微操作,但在 AMD Zen 和英特尔凌动上,shrd
需要少量微操作。所以一般来说应该首选第一个版本,但在特定情况下可能有理由使用第二个版本。
也有可能有两个重叠的存储和一个负载(这很慢,例如由于存储转发失败,Haswell 上有 16 个周期,即使没有遇到如此糟糕的微架构边缘情况,它也不会击败寄存器- 仅解决方案):
mov [rsp], rdx
mov [rsp], eax
mov rdx, [rsp]
movl %eax,%rdx
(等同于 mov %eax,%rdx
)不是有效指令。 MOV
的有效组合可以在 Instruction Set Architecture reference.
有几条指令可以从较小的寄存器移动到较大的寄存器。你可以使用 MOVZX
for zero extension (upper bits set to 0), or MOVSX
sign extension where the top most bit of the source register is copied into all the higher bits of the destination register. In 64-bit long mode if the destination of any instruction (including MOV
) 是一个 32 位寄存器然后相应的 64 位寄存器的高 32 位由处理器自动设置为 0。
这些示例表示从较小寄存器到较大寄存器的可用有效移动:
movzx %al, %dx # move 8-bit register to 16-bit register. Upper 8 bits of DX set to 0
movzx %al, %edx # move 8-bit register to 32-bit register. Upper 24 bits of EDX set to 0
# Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
movzx %al, %rdx # move 8-bit register to 64-bit register. Upper 56 bits of RDX set to 0
movzx %ax, %edx # move 16-bit register to 32-bit register.Upper 16 bits of EDX set to 0
# Upper 32 bits of RDX also set to zero because EDX is 32-bit dest
#movzx %eax, %rdx # This instruction doesn't exist. Use mov %eax, %edx
movsx %al, %dx # Sign extend 8-bit register to 16-bit register
movsx %al, %edx # Sign extend 8-bit register to 32-bit register
# Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
movsx %al, %rdx # Sign extend 8-bit register to 64-bit register
movsx %ax, %edx # Sign extend 16-bit register to 32-bit register
# Upper 32 bits of RDX set to ZERO because EDX is 32-bit dest
movsx %ax, %rdx # Sign extend 16-bit register to 64-bit register
movsx %eax, %rdx # Sign extend 32-bit register to 64-bit register