aarch64内联汇编堆栈指针约束的内存地址,带有Clang 6+的偏移量

时间:2019-04-28 02:11:42

标签: stack clang inline-assembly memory-address arm64

我注意到在不同的优化级别上,Clang 6有时对相邻的内存地址vld1 neon load instrinsics使用ldp(负载氖寄存器对)。

我正在尝试使用内联汇编手动强制执行更多负载对指令。源数组保存在堆栈中,当Clang本身生成ldp指令时,它使用具有偏移量的堆栈指针,但是当我使用内联汇编的索引输入该数组时,它会扩展为该地址的x寄存器。但是,这有效导致性能下降。我相信这是因为从堆栈中读取速度更快,但将ax寄存器作为源地址可能指向了堆,尽管我不确定,这可能又回头引用了堆栈,或者可能是从堆中的重复数据读取。 这是我现在正在使用的示例。

asm (
    "ldp %q[DST1], %q[DST2], [%[SRC]]" "\n"
    : [DST1] "=w" (TMP1), [DST2] "=w" (TMP2)
    : [SRC] "X" (&K2[8])
);

这就是Clang将其扩展为

ldp q19, q4, [x11]

但是我想使用带有偏移地址的堆栈指针,该地址从索引的K2数组变量自动解析。例如

ldp q19, q4, [sp,#32]

反汇编代码中堆栈指针地址的偏移量不相邻,因此我不能仅对sp寄存器进行硬编码并输入一个偏移量以加载顺序数据。这是因为Clang 6正在将其他函数使用的其他数组中的相同值合并到堆栈中。

GCC具有aarch64机器约束,例如 k ,用于堆栈指针(sp)寄存器,而 Ump 则用于stp和ldp存储/加载对指令地址我从来没有在GCC或Clang上工作过,后者在稀疏的文档中没有等效的约束。

我更喜欢使用Clang 6,因为它生成的代码比GCC 8快6%以上,因为它会将大多数指令安排在性能关键循环中以正确地双重发布。

反正有没有将带有索引的数组输入到内联汇编中并使其自动解析为Clang 6中具有偏移地址的堆栈指针?

1 个答案:

答案 0 :(得分:1)

您是否尝试过使用像[SRC] "m" (K2[8])这样的内存源操作数?否则,您甚至没有告诉编译器内存内容也是内联asm的输入,因此它可能会重新排序asm wrt。存储,或执行死角消除。

让编译器选择寻址模式是"m"操作数的全部要点。