SSE中的SSE4内联汇编问题

时间:2011-01-07 00:08:27

标签: c++ gcc assembly inline-assembly

大家好 我想执行一个以下形式的内联汇编指令

BLENDPD xmm1,xmm2/m128, imm8

我是内联装配的新手,所以我遇到了一些困难。 我的代码是:

#include<iostream>
using namespace std;
int main()
{
  long long y;
  __asm("blendpd %0,$0xabcd000000001111abcd000000001111,$0x1":
    "=r" (y):
    );
  cout<<y;
  return 0;
}

我的第一个错误是得到一个128位操作数,所以我使用了长十六进制数,但我仍然需要输出为128位,因为我希望2能够在屏幕上打印y。而且最重要的是我知道我的__asm语法是错误的但是无法弄明白,加上我不确定使用英特尔或AT&amp; T语法进行编译会在使用__asm时产生影响。

欢迎任何帮助。干杯! =)

编辑:我现在有了这个版本,并且收到了未定义的函数错误。

  #include<iostream>
  #include<emmintrin.h>
  using namespace std;

int main()
{
const int mask=5;
__m128d v2 = _mm_set_pd(1.0, 2.0);
__m128d v1;
v1=_mm_blend_pd(v1, v2, mask);
return 0;
}

2 个答案:

答案 0 :(得分:5)

首先,对于这类事情,您很少需要使用内联汇编。 GCC通常提供“编译器内在”函数,允许您使用C函数语法而不是汇编语法调用给定的特殊指令。

在这种情况下,你想要的内在函数是_mm_blend_pd(),它有这个函数签名

#include <smmintrin.h>
__m128d _mm_blend_pd(__m128d v1, __m128d v2, const int mask);

编译器将用单blendpd指令替换它;这实际上不是函数调用。

__m128d数据类型是一个包含两个双精度浮点值的向量;你可以从像这样的双打数组中创建一个:

__m128d v = _mm_set_pd(1.0, 2.0);

要从矢量中检索值以打印它们,可以将矢量存储到双精度浮点数组中:

double a[2];
_mm_store_pd(a, v);

所有这些都基于http://www.info.univ-angers.fr/~richer/ens/l3info/ao/intel_intrinsics.pdf上的英特尔内在函数手册;虽然这是指英特尔C ++编译器,但GCC支持相同的语法。

修改:使用正确的emmintrin.h替换错误的smmintrin.h。另请注意,mask值必须为2位(向量中每个值一位); 0,1,2或3以外的值会产生错误。当然,您需要使用-msse4 GCC选项进行编译。

答案 1 :(得分:3)

作为我的另一个答案的替代答案,这里是如何使用内联汇编而不是内在汇编。 (正如Thomas Pornin在我的另一个答案中指出的那样,内在函数通常更好,因为它们更便携,但有时你也想要这样的东西。)

首先,我作弊 - 我使用了内部函数的版本,并使用-S编译它,并查看生成的汇编代码,即:

    movsd   -64(%rbp), %xmm0
    movhpd  -56(%rbp), %xmm0
    movsd   -48(%rbp), %xmm1
    movhpd  -40(%rbp), %xmm1
    blendpd $3, %xmm1, %xmm0
    movlpd  %xmm0, -64(%rbp)
    movhpd  %xmm0, -56(%rbp)

您可以在此处看到与原始代码不同的一些内容。首先,请注意两个128位参数即时 - 它们是xmm0和xmm1寄存器。此外,您的操作数错误 - 掩码首先出现,包含输出的寄存器最后。修复这些,代码编译。

这里的第二个问题是你将通用寄存器的结果存储到y,而blendpd指令不接触通用寄存器,所以这只是存储垃圾。您需要xmm0注册,=Yz(请参阅GCC's documentation here)。并且你不能将它存储到long long,这是64位;你需要一个128位向量变量。解决所有这些问题,纠正的代码是:

#include<iostream>
#include<smmintrin.h>
using namespace std;
int main()
{
  __m128d y;
  __asm("blendpd $0x3,%%xmm1,%%xmm0":
    "=Yz" (y):
    );
  // cout<<y;
  return 0;
}

你会注意到我必须注释cout行,因为它没有处理SSE向量的规定;您需要先使用_mm_store_pd内在函数从y中获取单个double值。 (或者您可以添加更多内联汇编来调用movhpdmovhld指令以直接从寄存器中获取double值,而不是使用约束将它们分配给y。)

而且你有它 - 编译并运行良好。当然,输入值是未定义的(无论这些寄存器中是否随机出现),因此输出仍然是垃圾 - 如果您想获得有意义的结果,则需要先添加一些内容以将值加载到寄存器中。