Legv8 中是否有使用另一个寄存器而不是立即偏移量的 LOAD 或 STORE?
Is there a LOAD or STORE in Legv8 that uses another register instead of a immediate offset?
Legv8中是否有不使用立即数偏移量的加载或存储指令?我在底部问题中没有 i 的值,当我使用 LDUR 或 STUR 时,我无法抵消数据 [i]。我使用了 ARMv8 的 STR 和 LDR。还有其他方法可以回答这个问题吗?
Convert the following C program into LEGv8 assembly program. Assume variables k, x, y and i are associated with registers X19, X20, X21, and X22 respectively. The base address of array data[] is in register X25. Each element of array data[] occupies 8 bytes.
if ( x > y )
k = x – y;
else
k = y – x;
while (data[i] < k) {
data[i] = data[i] + k;
i = i + 1;
这是我写的。
IF:
SUBS X23, X20, X21 // CHECK IF X> Y
B.LT ELSE // IF LESS THAN, BRANCH TO ELSE
SUB X19, X20, X21 // STORE K = X-Y
B.LOOP
ELSE:
SUB X19, X21, X20 // STORE K= Y-X;
LOOP:
LDR X24, [X25, X22] // load into X24, base address from X24 with offset from X22
SUBS X18, X24, X19 // CHECK IF data[i] < k
B.GT EXIT
ADD X24, X24, X19 // data[i] += k
STR X24, [X25, X22] // store into X25 with offset from X22, the value from X24
ADDI X22, X22, #1 // I += 1
B.LOOP
EXIT:
str
/ldr
是可以使用多种寻址方式的普通指令
ldur
/stur
仅在立即数不是 4 或 8 的倍数时对寄存器 + 常量偏移有用。
具有该寻址模式的 ldr
的正常形式将其编码为缩放值,因此它可以使用更广泛的偏移量。 U 表示 "unscaled"。 (但这是一个 encoding 细节:asm 源代码仍然总是有一个字节偏移量,如 ldr w0, [x0, 4]
以加载下一个 int
在 x0
.Godbolt).但正如我所说,ldr
/str
可以使用任何寻址模式。
你说得对 ldur
对于 data[i]
没有用 运行 时间变量 i
.
Is there another way i could have answered this question?
是的,当然有很多方法可以安排你的循环。例如使用指针增量而不是 2 寄存器寻址模式,在循环外计算 data+i
。
或者将您的计数器增加 8 作为字节偏移量,而不是每次使用时都需要缩放的数组索引。 (我想你忘了这一点,除非 LEGv8 不同于 AArch64)。
或者优化掉 i
并只计算一个终点指针来进行比较。
甚至可以使用 AdvSIMD(NEON 的 AArch64 版本)SIMD 指令进行矢量化以一次执行 2 次加法。
你也可以用底部的条件分支来构造循环,这总是好的(循环内的指令更少)。即使这意味着你需要一个 compare/branch 来跳过循环,如果它应该 运行 零次。
但所有这些方式都只使用ldr
/str
,而不是ldur
/stur
。作为寻址模式的一部分,您不需要偏移量,只需 2 个寄存器。
Legv8中是否有不使用立即数偏移量的加载或存储指令?我在底部问题中没有 i 的值,当我使用 LDUR 或 STUR 时,我无法抵消数据 [i]。我使用了 ARMv8 的 STR 和 LDR。还有其他方法可以回答这个问题吗?
Convert the following C program into LEGv8 assembly program. Assume variables k, x, y and i are associated with registers X19, X20, X21, and X22 respectively. The base address of array data[] is in register X25. Each element of array data[] occupies 8 bytes.
if ( x > y )
k = x – y;
else
k = y – x;
while (data[i] < k) {
data[i] = data[i] + k;
i = i + 1;
这是我写的。
IF:
SUBS X23, X20, X21 // CHECK IF X> Y
B.LT ELSE // IF LESS THAN, BRANCH TO ELSE
SUB X19, X20, X21 // STORE K = X-Y
B.LOOP
ELSE:
SUB X19, X21, X20 // STORE K= Y-X;
LOOP:
LDR X24, [X25, X22] // load into X24, base address from X24 with offset from X22
SUBS X18, X24, X19 // CHECK IF data[i] < k
B.GT EXIT
ADD X24, X24, X19 // data[i] += k
STR X24, [X25, X22] // store into X25 with offset from X22, the value from X24
ADDI X22, X22, #1 // I += 1
B.LOOP
EXIT:
str
/ldr
是可以使用多种寻址方式的普通指令
ldur
/stur
仅在立即数不是 4 或 8 的倍数时对寄存器 + 常量偏移有用。
具有该寻址模式的 ldr
的正常形式将其编码为缩放值,因此它可以使用更广泛的偏移量。 U 表示 "unscaled"。 (但这是一个 encoding 细节:asm 源代码仍然总是有一个字节偏移量,如 ldr w0, [x0, 4]
以加载下一个 int
在 x0
.Godbolt).但正如我所说,ldr
/str
可以使用任何寻址模式。
你说得对 ldur
对于 data[i]
没有用 运行 时间变量 i
.
Is there another way i could have answered this question?
是的,当然有很多方法可以安排你的循环。例如使用指针增量而不是 2 寄存器寻址模式,在循环外计算 data+i
。
或者将您的计数器增加 8 作为字节偏移量,而不是每次使用时都需要缩放的数组索引。 (我想你忘了这一点,除非 LEGv8 不同于 AArch64)。
或者优化掉 i
并只计算一个终点指针来进行比较。
甚至可以使用 AdvSIMD(NEON 的 AArch64 版本)SIMD 指令进行矢量化以一次执行 2 次加法。
你也可以用底部的条件分支来构造循环,这总是好的(循环内的指令更少)。即使这意味着你需要一个 compare/branch 来跳过循环,如果它应该 运行 零次。
但所有这些方式都只使用ldr
/str
,而不是ldur
/stur
。作为寻址模式的一部分,您不需要偏移量,只需 2 个寄存器。