使用指针添加两个带有sse的4向量

时间:2014-07-14 12:33:06

标签: c++ assembly sse

这段代码(加倍4矢量)起作用:

__declspec(align(16)) struct vec4 { float a[4]; };

int main()
{
    vec4 c;
    c.a[0]=2;
    c.a[1]=0;
    c.a[2]=0;
    c.a[3]=0;

    __asm {
        movaps xmm1, c

        addps xmm1, xmm1
        movaps c, xmm1
    }
}

但是这篇文章(做同样但现在用指向对齐数据的指针)并没有:

__declspec(align(16)) struct vec4 { float a[4]; };

int main()
{
    vec4* c = new vec4;
    c->a[0]=2;
    c->a[1]=0;
    c->a[2]=0;
    c->a[3]=0;

    __asm {
        movaps xmm1, c

        addps xmm1, xmm1
        movaps c, xmm1
    }
}

为什么?

我需要它来处理指针,因为我不能将对齐的数据本身用作函数参数。

2 个答案:

答案 0 :(得分:0)

ASM中的指针必须根据某些规则进行处理,您可以通过学习how "MOV" works来学习。

根据Assembler的规则,首先需要将指针复制到cpu寄存器。然后你可以用它来指向内存位置。

vec4 *d = ...;
__asm {
    mov eax, d
    movaps xmm1, [eax]

    addps xmm1, xmm1
    movaps [eax], xmm1
}

答案 1 :(得分:0)

问题是堆分配器(如new和malloc)创建的对象不遵循您指定的对齐方式。您只能使用堆栈分配对象(第一个示例)进行对齐。

C ++ 11支持使用alignas显式对齐通过堆分配的对象,但VC ++尚未实现。它适用于某些编译器,而不适用于其他编译器。

您有几个选择。

最简单的方法:像你一样创建堆分配对象,并在使用之前将其复制到堆栈分配对象:

vec4* c = new vec4;
c->a[0]=2;
c->a[1]=0;
c->a[2]=0;
c->a[3]=0;

vec4 d = *c;
// process with d

另一个选择是让你的vec4结构包含足够的额外内存,以确保在16字节对齐上有16个字节。我相信新的保证至少4字节对齐,所以28字节就可以做到。然后,您必须手动检查指针,以查看要与sse一起使用的数据存储位置。