寻址非整数地址和 sse

Posted

技术标签:

【中文标题】寻址非整数地址和 sse【英文标题】:Addressing a non-integer address, and sse 【发布时间】:2013-10-15 08:01:16 【问题描述】:

我正在尝试使用 SSE 加速我的代码,以下代码运行良好。 基本上,__m128 变量应该连续指向 4 个浮点数,以便一次执行 4 个操作。

这段代码相当于用i0计算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]i03,它在执行时崩溃。

__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时,它和&amp;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的主要内容,如果未能解决你的问题,请参考以下文章

2018-2019-1 20165306 《信息安全系统设计基础》第十一周学习总结

深入理解Linux内核 - 第二章 内存寻址 01

Linux 内存寻址

:内存寻址.md

:内存寻址.md

shmget 如何分配内存?无法使用线性寻址访问(地址边界错误)