有条件地 load/store 的 aarch64 方法是什么?
What's aarch64's way to conditionally load/store?
我知道 armv7 可以使用 load/store 的条件代码,例如 ldrne/streq。但是A64不允许有条件地执行指令。那么我如何将其存档在 arm64 中:
ands tmp1, dstend, 7 # set nzcv flag with ands
# if not zero, ldr w6, [srcend, -4]!, str w6, [dstend, -4]!
# else, do nothing and goes on
...
对每条指令进行预测是一项使高性能 ARM CPU 更难实现的功能,尤其是在乱序执行的情况下。它是为 AArch64 故意删除的。 (Why are conditionally executed instructions not present in later ARM instruction sets? 引用供应商自己的理由)
如果你需要一些有副作用/可能有错误的东西,比如存储和加载是有条件的,你通常需要分支。
我能想到的唯一值得考虑的无分支选项是 csel
带有指向虚拟位置(例如在堆栈上)与真实位置的指针。然后你仍然实际加载和存储,但不是你关心的位置。这可能更糟,除非分支预测错误惩罚很高 并且 分支很难预测。
void fun0 ( unsigned int x, unsigned int *y )
{
if(x) *y=0;
else *y=1;
}
void fun1 ( unsigned int x, unsigned int *y )
{
if(x) *y=10;
else *y=11;
}
void fun2 ( unsigned int x, unsigned int *y, unsigned int a, unsigned int b )
{
if(x) *y=a;
else *y=b;
}
void fun5 ( unsigned int x, unsigned int *y, unsigned int *z )
{
if(x) *y=123;
else *z=123;
}
0000000000000000 <fun0>:
0: 7100001f cmp w0, #0x0
4: 1a9f17e0 cset w0, eq // eq = none
8: b9000020 str w0, [x1]
c: d65f03c0 ret
0000000000000010 <fun1>:
10: 7100001f cmp w0, #0x0
14: 1a9f17e0 cset w0, eq // eq = none
18: 11002800 add w0, w0, #0xa
1c: b9000020 str w0, [x1]
20: d65f03c0 ret
0000000000000024 <fun2>:
24: 7100001f cmp w0, #0x0
28: 1a831042 csel w2, w2, w3, ne // ne = any
2c: b9000022 str w2, [x1]
30: d65f03c0 ret
0000000000000034 <fun5>:
34: 34000080 cbz w0, 44 <fun5+0x10>
38: 52800f60 mov w0, #0x7b // #123
3c: b9000020 str w0, [x1]
40: d65f03c0 ret
44: 52800f60 mov w0, #0x7b // #123
48: b9000040 str w0, [x2]
4c: d65f03c0 ret
我知道 armv7 可以使用 load/store 的条件代码,例如 ldrne/streq。但是A64不允许有条件地执行指令。那么我如何将其存档在 arm64 中:
ands tmp1, dstend, 7 # set nzcv flag with ands
# if not zero, ldr w6, [srcend, -4]!, str w6, [dstend, -4]!
# else, do nothing and goes on
...
对每条指令进行预测是一项使高性能 ARM CPU 更难实现的功能,尤其是在乱序执行的情况下。它是为 AArch64 故意删除的。 (Why are conditionally executed instructions not present in later ARM instruction sets? 引用供应商自己的理由)
如果你需要一些有副作用/可能有错误的东西,比如存储和加载是有条件的,你通常需要分支。
我能想到的唯一值得考虑的无分支选项是 csel
带有指向虚拟位置(例如在堆栈上)与真实位置的指针。然后你仍然实际加载和存储,但不是你关心的位置。这可能更糟,除非分支预测错误惩罚很高 并且 分支很难预测。
void fun0 ( unsigned int x, unsigned int *y )
{
if(x) *y=0;
else *y=1;
}
void fun1 ( unsigned int x, unsigned int *y )
{
if(x) *y=10;
else *y=11;
}
void fun2 ( unsigned int x, unsigned int *y, unsigned int a, unsigned int b )
{
if(x) *y=a;
else *y=b;
}
void fun5 ( unsigned int x, unsigned int *y, unsigned int *z )
{
if(x) *y=123;
else *z=123;
}
0000000000000000 <fun0>:
0: 7100001f cmp w0, #0x0
4: 1a9f17e0 cset w0, eq // eq = none
8: b9000020 str w0, [x1]
c: d65f03c0 ret
0000000000000010 <fun1>:
10: 7100001f cmp w0, #0x0
14: 1a9f17e0 cset w0, eq // eq = none
18: 11002800 add w0, w0, #0xa
1c: b9000020 str w0, [x1]
20: d65f03c0 ret
0000000000000024 <fun2>:
24: 7100001f cmp w0, #0x0
28: 1a831042 csel w2, w2, w3, ne // ne = any
2c: b9000022 str w2, [x1]
30: d65f03c0 ret
0000000000000034 <fun5>:
34: 34000080 cbz w0, 44 <fun5+0x10>
38: 52800f60 mov w0, #0x7b // #123
3c: b9000020 str w0, [x1]
40: d65f03c0 ret
44: 52800f60 mov w0, #0x7b // #123
48: b9000040 str w0, [x2]
4c: d65f03c0 ret