寻址非整数地址和 sse
Posted
技术标签:
【中文标题】寻址非整数地址和 sse【英文标题】:Addressing a non-integer address, and sse 【发布时间】:2013-10-15 08:01:16 【问题描述】:我正在尝试使用 SSE 加速我的代码,以下代码运行良好。
基本上,__m128
变量应该连续指向 4 个浮点数,以便一次执行 4 个操作。
这段代码相当于用i
从0
计算c[i]=a[i]+b[i]
到3
。
float *data1,*data2,*data3
// ... code ... allocating data1-2-3 which are very long.
__m128* a = (__m128*) (data1);
__m128* b = (__m128*) (data2);
__m128* c = (__m128*) (data3);
*c = _mm_add_ps(*a, *b);
但是,当我想稍微移动我使用的数据(见下文)时,为了计算 c[i]=a[i+1]+b[i]
和 i
从 0
到 3
,它在执行时崩溃。
__m128* a = (__m128*) (data1+1); // <-- +1
__m128* b = (__m128*) (data2);
__m128* c = (__m128*) (data3);
*c = _mm_add_ps(*a, *b);
我的猜测是这与 __m128
是 128 位和 float
数据是 32 位的事实有关。所以,一个 128 位的指针可能不可能指向一个不能被 128 整除的地址。
不管怎样,你知道问题出在哪里以及我该如何解决它吗?
【问题讨论】:
您有未定义的行为。指向float
的指针不与指向__m128
的指针相同。另外,当你做data1 + 1
时,它和&data1[1]
是一样的,你真的分配了多个float
并将指针存储在data1
中吗?
是的,data1,data2,data3中有很多数据。他们分配得很好。
@JoachimPileborg,什么是不合时宜的行为?我知道指向 float 和 __m128 的指针是不同的。这就是我投的原因。 __mm128 应该连续指向 4 个浮点数,以便在 cpu 上一次执行所有 4 个操作。
好的,我在指针转换和赋值方面错了。但是,__m128
类型真的可以像您在第二个示例中那样错位吗?
@JoachimPileborg,我添加了一些编辑以使其更清晰。
【参考方案1】:
而不是像这样使用隐式对齐的加载/存储:
__m128* a = (__m128*) (data1+1); // <-- +1
__m128* b = (__m128*) (data2);
__m128* c = (__m128*) (data3);
*c = _mm_add_ps(*a, *b);
酌情使用显式对齐/未对齐的加载/存储,例如:
__m128 va = _mm_loadu_ps(data1+1); // <-- +1 (NB: use unaligned load)
__m128 vb = _mm_load_ps(data2);
__m128 vc = _mm_add_ps(va, vb);
_mm_store_ps(data3, vc);
相同数量的代码(即相同数量的指令),但不会崩溃,并且您可以明确控制哪些加载/存储对齐以及哪些未对齐。
请注意,最近的 CPU 对未对齐负载的惩罚相对较小,但在较旧的 CPU 上可能会有 2 倍或更高的命中率。
【讨论】:
【参考方案2】:您的问题是a
最终指向不是__m128
的东西;它指向包含__m128
的最后 96 位和外部 32 位的东西,可以是任何东西。它可能是下一个 __m128
的前 32 位,但最终,当您到达同一内存块中的最后一个 __m128
时,它将是另一回事。可能是您无法访问的保留内存,因此导致崩溃。
【讨论】:
这可能在数组的 end 处是正确的,因此使用 1 个额外元素填充a[]
可以使 _mm_loadu_ps
安全而不是结束。但这并不能回答为什么在未对齐时取消引用错误的问题。以上是关于寻址非整数地址和 sse的主要内容,如果未能解决你的问题,请参考以下文章