我试图弄清楚如何最好地预测一些罪恶和余弦值,将它们存储在对齐的块中,然后以后使用它们进行SSE计算:

在程序的开头,我创建一个具有成员的对象:

static __m128 *m_sincos;

然后,我在构造函数中初始化该成员:

m_sincos = (__m128*) _aligned_malloc(Bins*sizeof(__m128), 16);
for (int t=0; t<Bins; t++)
  m_sincos[t] = _mm_set_ps(cos(t), sin(t), sin(t), cos(t));



当我使用m_sincos时,我遇到了三个问题:
- 数据似乎并未对齐

movaps xmm0, m_sincos[t] //crashes
movups xmm0, m_sincos[t] //does not crash

- 变量似乎不正确

movaps result, xmm0 // returns values that are not what is in m_sincos[t]
//Although, putting a watch on m_sincos[t] displays the correct values

- 真正令我感到困惑的是,这使一切都起作用(但太慢):

__m128 _sincos = m_sincos[t];
movaps xmm0, _sincos
movaps result, xmm0
有帮助吗?

解决方案

m_sincos[t] 是C表达。但是,在大会指令中((__asm?),它被解释为X86寻址模式,结果完全不同。例如,VS2008 SP1编译:

movaps xmm0, m_sincos[t]

进入:(当应用程序以调试模式崩溃时,请参见拆卸窗口)

movaps xmm0, xmmword ptr [t]

该解释试图复制存储在变量地址的128位值 t 进入XMM0。 t, 但是,在可能不一致的地址处是32位值。执行指令可能会导致对齐失败,并在奇数情况下使您的结果不正确 t的地址是对齐的。

您可以使用适当的X86寻址模式来解决此问题。这是缓慢而清晰的版本:

__asm mov eax, m_sincos                  ; eax <- m_sincos
__asm mov ebx, dword ptr t
__asm shl ebx, 4                         ; ebx <- t * 16 ; each array element is 16-bytes (128 bit) long
__asm movaps xmm0, xmmword ptr [eax+ebx] ; xmm0 <- m_sincos[t]

边注:

当我将其放入完整的程序中时,会发生一些奇怪的事情:

#include <math.h>
#include <tchar.h>
#include <xmmintrin.h>

int main()
{
    static __m128 *m_sincos;
    int Bins = 4;

    m_sincos = (__m128*) _aligned_malloc(Bins*sizeof(__m128), 16);
    for (int t=0; t<Bins; t++) {
        m_sincos[t] = _mm_set_ps(cos((float) t), sin((float) t), sin((float) t), cos((float) t));
        __asm movaps xmm0, m_sincos[t];
        __asm mov eax, m_sincos
        __asm mov ebx, t
        __asm shl ebx, 4
        __asm movaps xmm0, [eax+ebx];
    }

    return 0;
}

运行此操作时,如果您密切注意寄存器窗口,您可能会发现一些奇怪的东西。尽管结果是正确的,但是 xmm0 得到正确的值 movaps 执行指令。这是怎么发生的?

查看生成的装配代码显示 _mm_set_ps() 将罪恶/cos的结果加载到 xmm0, ,然后将其保存到 m_sincos[t]. 。但是价值仍然存在 xmm0 也。 _mm_set_ps 是“内在”,而不是函数调用;它不会尝试恢复其完成后使用的寄存器值。

如果从中有一堂课,则可能是在使用SSE内在函数时,请在整个过程中使用它们,因此编译器可以为您优化事物。否则,如果您使用的是内联装配,请在整个过程中使用它。

其他提示

您应该始终使用仪器学,甚至应该将其打开并离开它们,而不是明确编码。这是因为__ asm不适合64位代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top