【发布时间】:2018-12-30 18:53:36
【问题描述】:
找到以下内联汇编器code来计算向量叉积:
float32x4_t cross_test( const float32x4_t& lhs, const float32x4_t& rhs )
{
float32x4_t result;
asm volatile(
"vext.8 d6, %e2, %f2, #4 \n\t"
"vext.8 d7, %e1, %f1, #4 \n\t"
"vmul.f32 %e0, %f1, %e2 \n\t"
"vmul.f32 %f0, %e1, d6 \n\t"
"vmls.f32 %e0, %f2, %e1 \n\t"
"vmls.f32 %f0, %e2, d7 \n\t"
"vext.8 %e0, %f0, %e0, #4 "
: "+w" ( result )
: "w" ( lhs ), "w" ( rhs )
: "d6", "d7" );
return result;
}
'%' 之后的修饰符 e 和 f 是什么意思(例如 %e2)?我找不到任何参考。
这是gcc生成的汇编代码:
vext.8 d6, d20, d21, #4
vext.8 d7, d18, d19, #4
vmul.f32 d16, d19, d20
vmul.f32 d17, d18, d6
vmls.f32 d16, d21, d18
vmls.f32 d17, d20, d7
vext.8 d16, d17, d16, #4
我现在明白了使用修饰符的含义。现在我尝试遵循叉积算法。为此,我在汇编代码中添加了一些额外的 cmets,但结果并不等于我的预期:
// History:
// - '%e' = lower register part
// - '%f' = higher register part
// - '%?0' = res = [ x2 y2 | z2 v2 ]
// - '%?1' = lhs = [ x0 y0 | z0 v0 ]
// - '%?2' = rhs = [ x1 y1 | z1 v1 ]
// - '%e0' = [ x2 y2 ]
// - '%f0' = [ z2 v2 ]
// - '%e1' = [ x0 y0 ]
// - '%f1' = [ z0 v0 ]
// - '%e2' = [ x1 y1 ]
// - '%f2' = [ z1 v1 ]
// Implemented algorithm:
// |x2| |y0 * z1 - z0 * y1|
// |y2| = |z0 * x1 - x0 * z1|
// |z2| |x0 * y1 - y0 * x1|
asm (
"vext.8 d6, %e2, %f2, #4 \n\t" // e2=[ x1 y1 ], f2=[ z1 v1 ] -> d6=[ v1 x1 ]
"vext.8 d7, %e1, %f1, #4 \n\t" // e1=[ x0 y0 ], f1=[ z0 v0 ] -> d7=[ v0 x0 ]
"vmul.f32 %e0, %f1, %e2 \n\t" // f1=[ z0 v0 ], e2=[ x1 y1 ] -> e0=[ z0 * x1, v0 * y1 ]
"vmul.f32 %f0, %e1, d6 \n\t" // e1=[ x0 y0 ], d6=[ v1 x1 ] -> f0=[ x0 * v1, y0 * x1 ]
"vmls.f32 %e0, %f2, %e1 \n\t" // f2=[ z1 v1 ], e1=[ x0 y0 ] -> e0=[ z0 * x1 - z1 * x0, v0 * y1 - v1 * y0 ] = [ y2, - ]
"vmls.f32 %f0, %e2, d7 \n\t" // e2=[ x1 y1 ], d7=[ v0 x0 ] -> f0=[ x0 * v1 - x1 * v0, y0 * x1 - y1 * x0 ] = [ -, - ]
"vext.8 %e0, %f0, %e0, #4 " //
: "+w" ( result ) // Output section: 'w'='VFP floating point register', '+'='read/write'
: "w" ( lhs ), "w" ( rhs ) // Input section : 'w'='VFP floating point register'
: "d6", "d7" ); // Temporary 64[bit] register.
【问题讨论】:
-
这是内联汇编,不是真正的汇编,不会在 arm 文档中找到。你的 C 代码的其余部分是什么样的?
-
我添加了完整的 C 函数。它用 gcc 编译得很好。
-
传统 FPA 寄存器 f0-f7。
-
你可以先检查反汇编然后换一个检查反汇编,看看有什么变化。
-
VEXT(向量提取)从第二个操作数向量的底端和第一个操作数向量的顶端提取 8 位元素,将它们连接起来,并将结果放入目标向量中。示例请参见图 6。
标签: gcc arm inline-assembly neon