使用Intel Intrinsics进行无符号短整数运算

问题描述 投票:1回答:1

我想使用Intel内在函数(16位无符号整数向量)进行一些操作,操作如下:

从unsigned short int数组加载或设置。

使用unsigned short int的Div和Mod操作。

使用unsigned short int的乘法运算。

将unsigned short int的操作存储到数组中。

我查看了Intrinsics指南,但看起来只有短整数的内在函数而不是未签名的整数。有人可以帮我解决这个问题吗?

实际上,我正在尝试将特定栅格格式的图像存储在具有特定排序的数组中。所以我必须计算每个像素值将被存储的索引:

unsigned int Index(unsigned int interleaving_depth, unsigned int x_size, unsigned int y_size, unsigned int z_size, unsigned int Pixel_number)
{
   unsigned int x = 0, y = 0, z = 0, reminder = 0, i = 0;

   y = Pixel_number/(x_size*z_size);
   reminder = Pixel_number % (x_size*z_size);

   i = reminder/(x_size*interleaving_depth);
   reminder = reminder % (x_size*interleaving_depth);

   if(i == z_size/interleaving_depth){
       x = reminder/(z_size - i*interleaving_depth);
       reminder = reminder % (z_size - i*interleaving_depth);
    }
    else
    {
       x = reminder/interleaving_depth;
       reminder = reminder % interleaving_depth;        
    }

    z = interleaving_depth*i + reminder;
    if(z >= z_size)
       z = z_size - 1;

    return x + y*x_size + *x_size*y_size;
}
c sse pixels intrinsics avx
1个回答
3
投票

如果您只想要结果的低半部分,则乘法与有符号或无符号的二进制运算相同。所以你可以使用pmullw。尽管如此,有单独的高半乘法指令用于有符号和无符号短路:_mm_mulhi_epu16pmulhuw)与_mm_mulhi_epi16pmuluw

类似地,你不需要一个_mm_set_epu16,因为它是相同的操作:在x86上转换为signed不会改变位模式,所以英特尔只打算提供_mm_set_epi16,但是你可以使用像0xFFFFu而不是-1这样的args没问题。 (自动使用Intel内在函数意味着您的代码只能移植到x86 32和64位。)

加载/存储内在函数根本不会更改数据。


SSE / AVX没有整数除法或mod指令。如果你有编译时常数除数,可以用乘法/移位自己做。您可以查看编译器输出以获得魔法常量和移位计数(Why does GCC use multiplication by a strange number in implementing integer division?),甚至让gcc为您自动矢量化。或者甚至使用GNU C本机向量语法来划分:

#include <immintrin.h>

__m128i div13_epu16(__m128i a) 
{
    typedef unsigned short __attribute__((vector_size(16))) v8uw;
    v8uw tmp = (v8uw)a;
    v8uw divisor = (v8uw)_mm_set1_epi16(13);
    v8uw result = tmp/divisor;
    return (__m128i)result;

    // clang allows "lax" vector type conversions without casts
    // gcc allows vector / scalar, e.g. tmp / 13.  Clang requires set1

    // to work with both, we need to jump through all the syntax hoops
}

用gcc和clang(Godbolt compiler explorer)编译到这个asm:

div13_epu16:
    pmulhuw xmm0, XMMWORD PTR .LC0[rip]       # tmp93,
    psrlw   xmm0, 2       # tmp95,
    ret

.section .rodata
.LC0:
    .value  20165
    # repeats 8 times

如果你有运行时变量除数,它会变慢,但你可以使用http://libdivide.com/。如果重复使用相同的除数也不算太糟糕,所以你只需要为它计算一次定点逆,但使用任意逆的代码需要一个变量移位计数,这对于SSE效率较低(同样也适用于整数) ),以及可能更多的指令,因为一些除数需要比其他除数更复杂的序列。

© www.soinside.com 2019 - 2024. All rights reserved.