【发布时间】:2016-08-12 12:03:06
【问题描述】:
我一直在玩 D 的内联汇编器和 SSE,但发现了一些我不明白的东西。当我尝试在声明后立即添加两个 float4 向量时,计算是正确的。如果我将计算放在一个单独的函数中,我会得到一系列nans。
//function contents identical to code section in unittest
float4 add(float4 lhs, float4 rhs)
{
float4 res;
auto lhs_addr = &lhs;
auto rhs_addr = &rhs;
asm
{
mov RAX, lhs_addr;
mov RBX, rhs_addr;
movups XMM0, [RAX];
movups XMM1, [RBX];
addps XMM0, XMM1;
movups res, XMM0;
}
return res;
}
unittest
{
float4 lhs = {1, 2, 3, 4};
float4 rhs = {4, 3, 2, 1};
println(add(lhs, rhs)); //float4(nan, nan, nan, nan)
//identical code starts here
float4 res;
auto lhs_addr = &lhs;
auto rhs_addr = &rhs;
asm
{
mov RAX, lhs_addr;
mov RBX, rhs_addr;
movups XMM0, [RAX];
movups XMM1, [RBX];
addps XMM0, XMM1;
movups res, XMM0;
} //end identical code
println(res); //float4(5, 5, 5, 5)
}
该程序集在功能上与this link 相同(据我所知)。
编辑:我正在使用自定义 float4 结构(目前,它只是一个数组),因为我希望能够拥有像 float4 add(float4 lhs, float rhs) 这样的添加函数。目前,这会导致如下编译器错误:
错误:需要浮点常量表达式而不是 rhs
注意:我使用的是 DMD 2.071.0
【问题讨论】:
-
我希望您不打算实际使用这样的代码来提高性能。您正在强制编译器将向量存储到内存中,然后将这些地址存储到内存中。然后,您正在编写从内存中加载地址并重新加载向量的代码。 (在 Windows
vectorcallABI 和所有其他 AMD64 系统使用的 SysV ABI 中,向量参数在向量寄存器中传递)。在 D 中,IDK 如果lhs_addr实际上可以是一个寄存器,但它充其量仍然是一个无用的 reg-reg 移动。理想情况下,有一种语法可以在特定 regs 中请求向量,例如 GNU C 内联 asm。 -
我正在尝试编写自己的 float4 类型,因为问题中的错误不允许
float4 rhs_vec = [rhs, rhs, rhs, rhs];。目前,我基本上已经从链接中复制粘贴了代码,并做了一些小的调整以(希望)使其在 D 中工作。目前,它只需要工作。但是,您会为该部分做什么?这只是我第三次尝试组装,所以任何更正将不胜感激。 -
我不知道 D,因为 SSE 和 inline-asm 标签,我才看到这个问题。 D 有类似 Intel C 内在函数的东西吗?
__m128 my_vec = _mm_add_ps(vec1, vec2);?如果是这样,你可能会做得更好。如果 D 的内联 asm 语法仅限于通过内存而不是寄存器传递数据,那么 it's only useful if you want to write a whole loop inside it, not as a wrapper for a few instructions。如果它支持 GNU-C 风格的 asm 语句,那么就使用它。 -
好吧,刚刚试过
__simd(XMM.ADDPS, lhs, rhs)。我认为它将指针添加在一起......
标签: d sse inline-assembly