如果它们是16字节对齐,是否可以直接将浮点数转换为__m128?

时间:2012-08-01 12:57:14

标签: c++ c alignment sse intrinsics

如果16个字节对齐,将浮动直接转换为__m128是否安全/可行/可取?

我注意到使用_mm_load_ps_mm_store_ps来“包装”原始数组会增加显着的开销。

我应该注意哪些潜在的陷阱?

编辑:

使用加载和存储指令实际上没有开销,我得到了一些数字混合,这就是我获得更好性能的原因。即使你能够在__m128实例中使用原始内存地址进行一些HORRENDOUS修改,当我运行测试时,如果没有_mm_load_ps指令需要TWICE AS LONG完成,可能会回落到某些失败状态安全的代码路径。

5 个答案:

答案 0 :(得分:11)

是什么让您认为_mm_load_ps_mm_store_ps“会增加显着的开销”?这是向/从SSE寄存器加载/存储浮点数据的正常方法,假设源/目标是内存(并且任何其他方法最终归结为此)。

答案 1 :(得分:8)

有几种方法可以将float值放入SSE寄存器中;可以使用以下内在函数:

__m128 sseval;
float a, b, c, d;

sseval = _mm_set_ps(a, b, c, d);  // make vector from [ a, b, c, d ]
sseval = _mm_setr_ps(a, b, c, d); // make vector from [ d, c, b, a ]
sseval = _mm_load_ps(&a);         // ill-specified here - "a" not float[] ...
                                  // same as _mm_set_ps(a[0], a[1], a[2], a[3])
                                  // if you have an actual array

sseval = _mm_set1_ps(a);          // make vector from [ a, a, a, a ]
sseval = _mm_load1_ps(&a);        // load from &a, replicate - same as previous

sseval = _mm_set_ss(a);           // make vector from [ a, 0, 0, 0 ]
sseval = _mm_load_ss(&a);         // load from &a, zero others - same as prev

无论您是说出_mm_set_ss(val)还是_mm_load_ss(&val),编译器都会经常创建相同的指令 - 尝试并反汇编您的代码。

在某些情况下,写_mm_set_ss(*valptr)而不是_mm_load_ss(valptr)有利于取决于代码的(结构)。

答案 2 :(得分:5)

http://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx,可能但不安全或不推荐。

  

您不应直接访问 __ m128 字段。


这就是为什么:

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/766c8ddc-2e83-46f0-b5a1-31acbb6ac2c5/

  
      
  1. 将float *转换为__m128将无效。 C ++编译器将赋值转换为__m128类型转换为SSE指令,将4个浮点数加载到SSE寄存器。假设编译了这个转换,它不会创建工作代码,因为不会生成SEE加载指令。
  2.         

    __ m128变量实际上不是变量或数组。这是SSE寄存器的占位符,由C ++编译器替换为SSE汇编指令。要更好地理解这一点,请阅读英特尔汇编编程参考。

答案 3 :(得分:2)

问题问题已经过去了几年。要回答我的经验所显示的问题:

reinterpret_cast - 将float*转换为__m128*,反之亦然,只要float*为16字节对齐 - 示例(在MSVC 2012中) :

__declspec( align( 16 ) ) float f[4];
return _mm_mul_ps( _mm_set_ps1( 1.f ), *reinterpret_cast<__m128*>( f ) );

答案 4 :(得分:1)

我可以看到的一个明显问题是你不是别名(通过多个指针类型引用内存位置),这可能会使优化器混淆。别名的典型问题是,由于优化器没有观察到您正在通过原始指针修改内存位置,因此它认为它没有改变。

由于你显然没有完全使用优化器(或者你愿意依赖它来发出正确的SSE指令),你可能会没事。

自己使用内在函数的问题在于它们被设计为在SSE寄存器上运行,并且不能使用从内存位置加载的指令变体并在单个指令中处理它。