如何将参数传递给英特尔 SSE 内在函数中的 const 值?

Posted

技术标签:

【中文标题】如何将参数传递给英特尔 SSE 内在函数中的 const 值?【英文标题】:how to pass parameters to const value in intel SSE intrinsics? 【发布时间】:2014-02-01 20:55:12 【问题描述】:

我知道在参数中使用 const value ;当您不希望函数修改参数时。

所以这个测试代码运行良好:

#include "stdafx.h"
#include <io.h>
#include <iostream>
using namespace std;

void foo (const int y ) 

    printf ( "x = %d \n" , y*2 ) ;  


int _tmain(int argc, _TCHAR* argv[])

    int y = 3;
    foo ( y );
    system("pause");
    return 0;

但是当我在英特尔 SSE 内在函数(例如 *_mm_blend_epi16* 函数)上执行相同操作时,我收到此错误:

error C2057: expected constant expression

这个错误的代码是:

#include "stdafx.h"
#include <io.h>
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])

    int y = 3 ;
    __m128i x1,x2;
    _mm_blend_epi16(x1,x2,y);
    system("pause");
    return 0;

_mm_blend_epi16的定义是:

__m128i _mm_blend_epi16( __m128i a, __m128i b, const int mask )

那么,问题是什么?难道我做错了什么 ?

编辑解决办法是什么?

【问题讨论】:

请注意,这确实适用于 gcc(使用 gcc 4.5.2 和 gcc 4.8.2 测试)。 Microsoft Visual Studio 2012 失败。 @ScottD 第一个代码在 Visual c++ 2012 中运行良好。问题出在给我上述错误的第二个代码中 我明白了。我只是指出这个问题是特定于 Microsoft 编译器的,而不是一般的 C 或 C++ 编译器。也就是说,第二个代码使用 gcc。 不可能做你想做的事 - mask 参数是一个立即操作数 - 这意味着它是指令的一部分并且必须在编译时知道。如果您需要一个单独的函数来调用带有掩码作为参数的 _mm_blend_epi16,则必须将其实现为宏并在任何地方编写类似 const int mask = 3 的代码。或者,您可以使用类似的指令_mm_blendv_epi8 对 8 位字进行洗牌,并且不需要掩码是编译时常量(请注意,它必须与 _mm_blend_epi16 的掩码略有不同。 【参考方案1】:

问题在于_mm_blend_epi16 不仅要求掩码为const int,而且还需要在编译时为已知值(如c++11 中的constexpr)。所以,即使_mm_blend_epi16(x1,x2,(const int)y) 也行不通。此行为与测试示例中的行为不同,因为它是编译器内在函数,而不是真正的函数。

【讨论】:

嗨!您在内容方面写得很好,但请阅读格式常见问题解答。谢谢。【参考方案2】:

这是一个可能有用的解决方法。限制:所需的高效代码生成仅存在于发布(优化)构建中。如果编译器无法确定掩码值,则不会记录错误消息。相反,您将获得低效的代码生成。因此,必须使用调试器或反汇编器检查代码生成以确认所需的结果。此解决方法需要调用包装函数来代替 _mm_blend_epi16 本身。优化器将在其位置内联单个 _mm_blend_epi16。这是一个使用纯 C 代码的示例。使用 Visual Studio 2010 和 Visual Studio 2013 测试。

#include "stdio.h"
#include "smmintrin.h"

#define XM(a,b,x) if (mask == x) result = _mm_blend_epi16 (a, b, x)
#define XM1(a,b,x) XM (a,b,x+0x00); XM (a,b,x+0x01); XM (a,b,x+0x02); XM (a,b,x+0x03);\
                   XM (a,b,x+0x04); XM (a,b,x+0x05); XM (a,b,x+0x06); XM (a,b,x+0x07);\
                   XM (a,b,x+0x08); XM (a,b,x+0x09); XM (a,b,x+0x0A); XM (a,b,x+0x0B);\
                   XM (a,b,x+0x0C); XM (a,b,x+0x0D); XM (a,b,x+0x0E); XM (a,b,x+0x0F);

static __m128i my_mm_blend_epi16(__m128i a, __m128i b, int mask)
    
    __m128i result;
    XM1 (a, b, 0x00); XM1 (a, b, 0x10); XM1 (a, b, 0x20); XM1 (a, b, 0x30);
    XM1 (a, b, 0x40); XM1 (a, b, 0x50); XM1 (a, b, 0x60); XM1 (a, b, 0x70);
    XM1 (a, b, 0x80); XM1 (a, b, 0x90); XM1 (a, b, 0xa0); XM1 (a, b, 0xb0);
    XM1 (a, b, 0xc0); XM1 (a, b, 0xd0); XM1 (a, b, 0xe0); XM1 (a, b, 0xf0);
    return result;
    

int main(void)
    
    int y = 0x99;
    __m128i x1,x2;

    x1 =_mm_set_epi32 (1, 2, 3, 4);
    x2 =_mm_set_epi32 (5, 6, 7, 8);
    x2 = my_mm_blend_epi16 (x1, x2, y);

    printf ("%x\n", _mm_cvtsi128_si32 (x2));
    return 0;
    

这是显示代码生成的发布构建调试器视图:

int main(void)
    
00161000 55                   push        ebp  
00161001 8B EC                mov         ebp,esp  
00161003 83 E4 F8             and         esp,0FFFFFFF8h  
    int y = 0x99;
    __m128i x1,x2;

    x1 =_mm_set_epi32 (1, 2, 3, 4);
00161006 66 0F 6F 05 00 21 16 00 movdqa      xmm0,xmmword ptr ds:[162100h]  
    x2 =_mm_set_epi32 (5, 6, 7, 8);
0016100E 66 0F 6F 0D 10 21 16 00 movdqa      xmm1,xmmword ptr ds:[162110h]  
    x2 = my_mm_blend_epi16 (x1, x2, y);
00161016 66 0F 3A 0E C1 99    pblendw     xmm0,xmm1,99h  

    printf ("%x\n", _mm_cvtsi128_si32 (x2));
0016101C 66 0F 7E C0          movd        eax,xmm0  
00161020 50                   push        eax  
00161021 68 F4 20 16 00       push        offset string "%x\n" (1620F4h)  
00161026 FF 15 A0 20 16 00    call        dword ptr [__imp__printf (1620A0h)]  
0016102C 83 C4 08             add         esp,8  
    return 0;
0016102F 33 C0                xor         eax,eax  
    

【讨论】:

【参考方案3】:

内在

__m128i _mm_blend_epi16( __m128i a, __m128i b, const int mask

期望第三个参数是一个 const int;所以一个在编译时已知的 const 值。

如果你修改如下代码:

    const int y = 3 ;
    _mm_blend_epi16(x1,x2,y);

如果应该可以。

或者,使用#define 作为掩码

【讨论】:

以上是关于如何将参数传递给英特尔 SSE 内在函数中的 const 值?的主要内容,如果未能解决你的问题,请参考以下文章

c++ SSE内在函数atan2

如何将输入参数传递给 AWS Glue Map.apply 函数

SSE 将整数加载到 __m128

如何通过单击 PyQt 中的按钮将参数传递给函数?

如何将参数传递给 React js 中的函数?

英特尔 SSE 的斜坡功能