16

我正在阅读 ARM 的SVE 白皮书,遇到了一些让我感到奇怪的事情(在非 SVE 示例中):

mov x8, xzr

我不知道这个xzr寄存器是什么,所以我查了一下,发现ARM 的一些内容表明它在许多情况下是零的同义词。

所以它看起来x8被初始化为零,这是有道理的,因为它是在x8用作循环计数器的循环之前执行的。

我不明白的是,为什么不使用文字0代替xzr?例如:

mov x8, 0

总而言之,我的问题是:为什么在这里使用xzr寄存器而不是文字0

4

5 回答 5

16

I think the mov x8, xzr vs mov x8, #0 comparison is something of a red herring.

As @old_timer's answer shows, there is no encoding gain to be made, and quite likely (although admittedly I haven't checked) little or no pipeline performance gain.

What xzr gives us, however - in addition to a dummy register as per @InfinitelyManic's answer - is access to a zero-valued operand without having to load and occupy a real register. This has the dual benefit of one less instruction, and one more register available to hold 'real' data.

I think this is an important characteristic that the original 'some content from ARM' referred to in the OP neglects to point out.

That's what I mean by mov x8, xzr vs mov x8, #0 being a red herring. If we're zeroing x8 with the intention of then modifying it, then using xzr or #0 is pretty arbitrary (although I'd tend to favour #0 as the more obvious). But if we're zeroing x8 purely in order to supply a zero operand to a subsequent instruction, then we'd be better off using - where permitted - xzr instead of x8 as the operand in that instruction, and not zeroing x8 at all.

于 2017-03-14T19:18:38.720 回答
4
mov x8,xzr
mov x8,#0
mov x8,0

生产

0000000000000000 <.text>:
   0:   aa1f03e8    mov x8, xzr
   4:   d2800008    mov x8, #0x0                    // #0
   8:   d2800008    mov x8, #0x0                    // #0

除了它允许没有英镑符号的立即数之外,没有什么真正令人惊讶的。这不是指令大小问题(同样不足为奇,例如 xor rax,rax 比 mov rax,0 便宜),也许有管道性能提升(尽管普遍认为指令需要多个时钟开始完成) .

很可能这是个人喜好,我们有这个很酷的 mips,就像总是零寄存器一样,让我们​​只是为了好玩而使用它。

于 2017-03-14T14:41:02.680 回答
1

这两条指令在效果和预期性能方面应该是相同的。

它们实际上都是更通用指令的别名。

mov x8, 0被编码为orr x8, xzr, 0

mov x8, xzr被编码为orr x8, xzr, xzr

别名很有用,因为它们使 ASM 更具可读性。

第二种编码说明了为什么使用零寄存器xzr会很有用。因为我们知道 xzr 总是为零,所以我们可以将orr指令重用于mov. 没有它,mov将需要不同的编码,因此会浪费编码空间。

于 2017-03-14T14:50:45.570 回答
0

这个答案对 OP 来说并不是“全力以赴”。

XZR 可用于丢弃结果;例如,“ldr xzr, [sp], 16”。请参阅下面的 GDB

0x7fffffef40:   0x00000000      0x00000000      0x00400498      0x00000000
0x7fffffef50:   0x00000000      0x00000000      0x00000000      0x00000000
              ldr x0,=0xdead
(gdb)
              ldr x1,=0xc0de
(gdb)
              stp x0, x1, [sp, #-16]!
(gdb) x/8x $sp
0x7fffffef30:   0x0000dead      0x00000000      0x0000c0de      0x00000000
0x7fffffef40:   0x00000000      0x00000000      0x00400498      0x00000000

              ldr xzr, [sp], #16
(gdb) x/8x $sp
0x7fffffef40:   0x00000000      0x00000000      0x00400498      0x00000000
0x7fffffef50:   0x00000000      0x00000000      0x00000000      0x00000000

还请记住,在 ARMv8 中,堆栈应该是四字对齐或 SP mod 16 = 0。因此您可以使用 XZR 之一的“推送”或“弹出”对寄存器。

stp x1, xzr, [sp, #-16]!

ldp x10, xzr, [sp], #16
于 2017-03-14T16:17:21.233 回答
-1

TL;博士

将 64 位文字加载到寄存器中需要多条指令,但使用 zxr 只需一条指令将其设置为 0。因此代码更短更快。


要将文字移动到寄存器,您将使用 MOVL 指令,请参阅 arm 参考:

MOVL 伪指令

使用以下任一方式加载寄存器:

A 32-bit or 64-bit immediate value.

Any address.

MOVL 生成两个或四个指令……一个 MOV,MOVK 对。

因此,将文字加载到寄存器中是一个多步骤的过程。如果您只想清除寄存器,那么他们有一个快捷方式。zxr 是一个伪寄存器,始终读取零,这是您需要的常用值,并且可以在一条指令中完成将寄存器移动到寄存器。

在 Microchip 组装中,它们具有类似的概念。要将寄存器设置为文字,您可以执行以下操作:

MOVLW   10       (Move 10 to the working register) 
MOVWF   0x1234   (Move the working register to address 0x1234)

但是要设置为零,他们有以下指令:

CLRF    0x1234   (Set 0x1234 to zero)
于 2017-03-14T14:39:40.947 回答