【问题标题】:SSE strangeness with Functions函数的 SSE 陌生性
【发布时间】: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 vectorcall ABI 和所有其他 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


【解决方案1】:

您的代码很奇怪,您使用的是什么版本的 dmd?这按预期工作:

import std.stdio;
import core.simd;

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;
}

void main()
{
    float4 lhs = [1, 2, 3, 4];
    float4 rhs = [4, 3, 2, 1];

    auto r = add(lhs, rhs);
    writeln(r.array); //float4(5, 5, 5, 5)

    //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
    writeln(res.array); //float4(5, 5, 5, 5)
}

【讨论】:

  • 感谢您的帮助,但我刚刚意识到我的问题中没有包含一些内容,它们已被添加到问题中。
  • @Straivers,Kozzi11 真的回答了你的问题吗?
  • 没有。或者更确切地说,他回答了最初的问题,这让我意识到我的问题措辞不正确。一个已被纠正的错误。
  • @Straivers 你能把你的完整代码放在某个地方吗?这真的很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-19
  • 2016-06-16
  • 2011-06-01
  • 2017-08-04
  • 1970-01-01
相关资源
最近更新 更多