这个错误可能实际上并没有显示在所有机器上,但是在我的下面运行下面的代码并获得输出(注意值-1.#IND00
)?
values int:: 4 2
shifts:: 4 2
result: : 64 32
input 1 HADDPD:: 10.000000 -1.#IND00
input 2 HADDPD:: 13.000000 10.000000
result of HADDPD:: -1.#IND00 23.000000
如果我发表评论
__m64 PSLLDm64_IN = _mm_set_pi32(2,4);
__m64 PSLLDm64_C = _mm_set_pi32(2,4);//could this be the culprit?
__m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C);
print_2_32_bit_int("values int:" , PSLLDm64_IN);
print_2_32_bit_int("shifts:", PSLLDm64_C);
print_2_32_bit_int("result: ", PSLLDm64_r);
我明白了......
input 1 HADDPD:: 10.000000 100.000000
input 2 HADDPD:: 13.000000 10.000000
result of HADDPD:: 110.000000 23.000000
我想知道第32行__m64 PSLLDm64_C = _mm_set_pi32(2,4);
可能被搞砸了吗?
下面是完整的代码(使用g ++与-msse3 -mmmx
一起运行)但并非所有标题都是必需的。
#include <xmmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <iostream>
void print_2_64_bit_doubles(const char * label, __m128d m64_r)
{
double *val = (double *) &m64_r;
printf("%s: %f %f\n",
label, val[0], val[1]);
}
void print_2_32_bit_int(const char * label, __m64 m32_r)
{
int *val = (int *) &m32_r;
printf("%s: %d %d\n",
label, val[0], val[1]);
}
__m128d HADDPD(__m128d __X, __m128d __Y)
{
return _mm_hadd_pd ( __X, __Y);
}
__m64 PSLLD(__m64 __m, __m64 __count)
{
return _mm_sll_pi32 ( __m, __count);
}
int main()
{
//PSLLD-------------------------------------------------------------------
__m64 PSLLDm64_IN = _mm_set_pi32(2,4);
__m64 PSLLDm64_C = _mm_set_pi32(2,4);
__m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C);
print_2_32_bit_int("values int:" , PSLLDm64_IN);
print_2_32_bit_int("shifts:", PSLLDm64_C);
print_2_32_bit_int("result: ", PSLLDm64_r);
//HADDPD------------------------------------------------------------------
double C1 = 10;
double D = C1*C1;
double x = 10;
double y = 13;
__m128d HADDPDm64_1 = _mm_set_pd(D,C1);
__m128d HADDPDm64_2 = _mm_set_pd(x,y);
__m128d HADDPDm64_r = HADDPD( HADDPDm64_1, HADDPDm64_2);
print_2_64_bit_doubles("input 1 HADDPD:", HADDPDm64_1);
print_2_64_bit_doubles("input 2 HADDPD:", HADDPDm64_2);
print_2_64_bit_doubles("result of HADDPD:", HADDPDm64_r);
return 0;
}
编辑:这是使用g ++ 4.4.1编译的新移位指令的更新代码-msse -msse2 -msse3 -msse4
#include <xmmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include <mmintrin.h>
#include <stdio.h>
#include <stdint.h>
void print_2_64_bit_doubles(const char * label, __m128d m64_r)
{
double *val = (double *) &m64_r;
printf("%s: %f %f\n",
label, val[0], val[1]);
}
void print_2_32_bit_int(const char * label, __m64 m32_r)
{
int *val = (int *) &m32_r;
printf("%s: %d %d\n",
label, val[0], val[1]);
}
void print_1_32_bit_int(const char * label, __m64 m32_r)
{
int *val = (int *) &m32_r;
printf("%s: %d \n",
label, val[0]);
}
__m128d HADDPD(__m128d __X, __m128d __Y)
{
return _mm_hadd_pd ( __X, __Y);
}
__m64 PSLLD(__m64 __m, __m64 __count)
{
return _mm_sll_pi32 ( __m, __count);
}
int main()
{
//PSLLD-------------------------------------------------------------------
__m64 PSLLDm64_IN = _mm_set_pi32(2,4);
long long __i = 2;
__m64 PSLLDm64_C = (__m64)(__i);
__m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C);
_mm_empty();
print_2_32_bit_int("values int:" , PSLLDm64_IN);
print_1_32_bit_int("shifts:", PSLLDm64_C);
print_2_32_bit_int("result: ", PSLLDm64_r);
//HADDPD------------------------------------------------------------------
double C1 = 10;
double D = C1*C1;
double x = 10;
double y = 13;
__m128d HADDPDm64_1 = _mm_set_pd(D,C1);
__m128d HADDPDm64_2 = _mm_set_pd(x,y);
__m128d HADDPDm64_r = HADDPD( HADDPDm64_1, HADDPDm64_2);
print_2_64_bit_doubles("input 1 HADDPD:", HADDPDm64_1);
print_2_64_bit_doubles("input 2 HADDPD:", HADDPDm64_2);
print_2_64_bit_doubles("result of HADDPD:", HADDPDm64_r);
return 0;
}
输出
values int:: 4 2
shifts:: 2
result: : 16 8
input 1 HADDPD:: 10.000000 -1.#IND00
input 2 HADDPD:: 13.000000 10.000000
result of HADDPD:: -1.#IND00 23.000000
答案 0 :(得分:1)
使用来自http://www.drangon.org/mingw/的gcc和g ++ 4.8.1的Windows x64端口进行测试都可以得到预期的结果。只需解压缩存档并设置mingw64 \ bin的路径即可。使用编译器选项(如-msse4)告诉编译器您的硬件支持这些指令。
07/05/2013:对于不完整的初始评论感到抱歉。此外,上述答案仅供评论而非答案。
Microsoft VS2010从cygwin报告的结果不正确,使用Microsoft调试器很容易找到原因。事实上,编译警告也指出了问题:
warning C4730: 'main' : mixing _m64 and floating point expressions may result in incorrect code
当编译器生成混合的MMX和x87 FPU指令时,会报告您报告的问题。编译器使用MMX寄存器用于_m64数据,编译器使用x87 FPU寄存器或较新的XMM或YMM寄存器用于浮点数据类型double。当英特尔设计MMX时,决定将x87寄存器重用于MMX寄存器数据。这样做是为了支持MMX使用,操作系统不需要任何更新。这个决定的缺点是MMX和x87 FPU指令不能混合使用。为防止意外混合FPU和MMX指令,英特尔制造的MMX寄存器加载将相应FPU寄存器的标记字位标记为SNAN(信令NAN)。这就是导致您看到的意外输出的原因。某些编译器和构建选项组合可能允许此代码正常运行。在某些情况下此代码可能起作用的可能原因: 1)编译器使用XMM或YMM寄存器来获得双精度数据。 2)编译器将所有x87 FPU值保存在内存中,并且不依赖于MMX指令中的FPU寄存器状态。 最重要的是,由编码器决定是否允许编译器生成混合MMX和x87 FPU指令的代码。采取警告,如“功能'print_2_32_bit_int'没有EMMS指令”或“混合_m64和浮点表达式可能导致错误的代码”严重。一种可行的方法是完全避免使用_m64数据类型。
Paul R关于使用_mm_empty()的建议解决了Microsoft VS2010的问题。我在“双C1 = 10”之前加了它,问题就消失了。 _mm_empty在这里解释http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/intref_cls/common/intref_mmx_emms_usage.htm。
对于你的其他问题,我只使用命令行为gcc,没有IDE。如果添加_mm_empty()或避免混合使用MMX和x87 FPU代码,则旧版本的gcc应该可以正常工作。