在内联 GCC 汇编中使用 C 数组
我想使用 GCC 编译器(Mac 上的 Xcode)在汇编中使用传递到 C 函数的两个数组,如下所示。自从我编写汇编以来已经很多年了,所以我确信这是一个简单的修复。
这里的第一行很好。第二行失败。我正在尝试执行以下操作,A[0] += x[0]*x[0],并且我想对数组中具有不同索引的许多元素执行此操作。我这里只展示一个。如何在汇编块中使用读/写数组?
如果有更好的方法来做到这一点,我愿意倾听。
inline void ArrayOperation(float A[36], const float x[8])
{
float tmp;
__asm__ ( "fld %1; fld %2; fmul; fstp %0;" : "=r" (tmp) : "r" (x[0]), "r" (x[0]) );
__asm__ ( "fld %1; fld %2; fadd; fstp %0;" : "=r" (A[0]) : "r" (A[0]), "r" (tmp) );
// ...
}
I'd like to use two array passed into a C function as below in assembly using a GCC compiler (Xcode on Mac). It has been many years since I've written assembly, so I'm sure this is an easy fix.
The first line here is fine. The second line fails. I'm trying to do the following, A[0] += x[0]*x[0], and I want to do this for many elements in the array with different indices. I'm only showing one here. How do I use a read/write array in the assembly block?
And if there is a better approach to do this, I'm open ears.
inline void ArrayOperation(float A[36], const float x[8])
{
float tmp;
__asm__ ( "fld %1; fld %2; fmul; fstp %0;" : "=r" (tmp) : "r" (x[0]), "r" (x[0]) );
__asm__ ( "fld %1; fld %2; fadd; fstp %0;" : "=r" (A[0]) : "r" (A[0]), "r" (tmp) );
// ...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
代码失败的原因不是因为数组,而是因为 fld 和 fst 指令的工作方式。这是您想要的代码:
fld
和fst
指令需要内存操作数。此外,您还需要指定是否要加载 float (flds)、double (fldl) 或 long double (fldt)。至于输出操作数,我只使用一个约束=t
,它只是告诉编译器结果位于寄存器堆栈的顶部,即ST(0)。算术运算要么没有操作数 (fmulp),要么只有一个内存操作数(但随后您必须再次指定大小、fmuls、fadds 等)。
您可以阅读有关内联汇编器、GNU 汇编器一般信息,并参阅英特尔® 64 和 IA-32 架构软件开发人员手册。
当然,最好摆脱临时变量:
尽管如果您追求的是性能改进,则不需要使用汇编程序。 GCC 完全有能力生成此代码。但您可能会考虑使用向量 SSE 指令和其他简单的优化技术,例如打破计算中的依赖链,请参阅 Agner Fog的优化手册
The reason why the code fails is not because of arrays, but because of the way fld and fst instructions work. This is the code you want:
fld
andfst
instructions need a memory operand. Also, you need to specify if you want to load float (flds), double (fldl) or long double (fldt). As for the output operands, I just use a constraint=t
, which simply tells the compiler that the result is on the top of the register stack, i.e. ST(0).Arithmetic operations have either no operands (fmulp), or a single memory operand (but then you have to specify the size again, fmuls, fadds etc.).
You can read more about inline assembler, GNU Assembler in general, and see the Intel® 64 and IA-32 Architectures Software Developer’s Manual.
Of course, it is best to get rid of the temporary variable:
Though if a performance improvement is what you're after, you don't need to use assembler. GCC is completely capable of producing this code. But you might consider using vector SSE instructions and other simple optimization techniques, such as breaking the dependency chains in the calculations, see Agner Fog's optimization manuals