![](/img/trans.png)
[英]What to and a random number with to constrain range between 0 to 9 in ARMv8 Assembly?
[英]What is the fastest way to index into ARMv8 registers
ARMv8 指令集允許訪問指令中內置的任何 integer 寄存器,如下所示:
add x0, x1, x2 @ x0 = x1 + x2, 64 bit arithmetic
但是,有沒有辦法將寄存器從 0 加載到 15,例如,使用寄存器中的值?
例如,假設寄存器 x16 包含數字 5。在這種情況下,我想要 x5。
這當然可以在 memory (一個數組)中完成,但這要慢得多。
ldr x19, [x17, x16, lsl #3]
其中 x17 是某個基地址,x16 是索引,但這需要轉到 memory。 如果緩存,這會更慢。 如果寫回該值,則寫入可能需要更多時間。
我能想到的唯一其他方法是某種計算的 goto:
add x18, x18, x16, lsl #6
bx x18
1:
mov x19, x0
...
2:
mov x19, x1
...
3:
mov x19, x2
...
這甚至比數組訪問還要慢。
理想情況下會有一個索引模式,如:
mov x19, x[x16]
如評論中所述,使用 memory 中的數組為較小的數據集執行此操作通常更快。 在 ARM 上,還可以使用表查找指令更有效地處理大量數據:
最多可以將四個 16 字節 SIMD 寄存器傳送到tbl
指令。 對於條目的 16 個字節中的每一個,該值取自具有相應編號的部分寄存器,否則為零(但是,類似的指令tbx
使該值保持不變)。 一個例子:
input: v0 = [0x00, 0x01, 0x08, 0x10, 0x12, 0x20, 0x21, 0x30, 0x3F, 0x40, ...]
tables: v4 = [0x40, 0x41, 0x42, ..., 0x4F]
v5 = [0x50, 0x51, 0x52, ..., 0x5F]
v6 = [0x60, 0x61, 0x62, ..., 0x6F]
v7 = [0x70, 0x71, 0x72, ..., 0x7F]
執行tbl v1.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v0.16b
給出以下結果:
output: v1 = [0x40, 0x41, 0x48, 0x50, 0x52, 0x60, 0x61, 0x70, 0x7F, 0x00, ...]
使用tbx
所有大於0x3F
的值都將被輸入而不是歸零:
output: v1 = [0x40, 0x41, 0x48, 0x50, 0x52, 0x60, 0x61, 0x70, 0x7F, 0x40, ...]
由於只能進行逐字節查找,因此需要進行一些初步工作:通用寄存器中的索引被傳輸到 SIMD 寄存器,另外還傳輸到第二個寄存器,以便它可以適應兩個寄存器。
input: x0 = [index, 0, 0, ..., 0]
first SIMD register: v0 = [index*8, index*8+1, ..., index*8+7, 0, 0, ..., 0]
second SIMD register: v1 = [index*8-64, index*8-63, ..., index*8-57, 0, 0, ..., 0]
這是為了滿足查找值必須始終介於 0 和 15(或 31、47 或 63)之間的事實,並且應該在此處對八個連續字節進行查找。
因此,索引在每個查找表中轉換為 position(每個tbl
指令都有一個)。 如果超出范圍,則tbl
將提供零,並且如果結果在最后被orr
-ed 一起使用,則將無效。
需要定義以下數據:
modifier: .byte 0, 1, 2, 3, 4, 5, 6, 7, -64, -63, -62, -61, -60, -59, -58, -57
輸入值在x0
中。 查找的值取自lookup_table
memory 位置。 結果存儲在x0
中:
// Load lookup table from memory
adr x1, lookup_table
ldp q8, q9, [x1]
ldp q10, q11, [x1, 32]
ldp q12, q13, [x1, 64]
ldp q14, q15, [x1, 96]
// Take value to be looked up from general-purpose register
dup v0.8b, w0
// Prepare index before lookup
adr x1, modifier
ldp d2, d3, [x1]
shl v0.8b, v0.8b, 3
add v2.8b, v0.8b, v2.8b
add v3.8b, v0.8b, v3.8b
// Do Lookup
tbl v2.8b, {v8.16b, v9.16b, v10.16b, v11.16b}, v0.8b
tbl v3.8b, {v12.16b, v13.16b, v14.16b, v15.16b}, v1.8b
orr v0.8b, v2.8b, v3.8b
// Load the result back into a general-purpose register
umov x0, v0.2d[0]
如果實在沒有其他辦法,也可以從通用寄存器x8
到x23
中取值:
ins v8.2d[0], x8
ins v9.2d[0], x10
ins v10.2d[0], x12
// ...
ins v15.2d[0], x22
ins v8.2d[1], x9
ins v9.2d[1], x11
ins v10.2d[1], x13
// ...
ins v15.2d[1], x23
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.