_loaddqu_LE内部存储以相反的顺序

时间:2019-01-13 18:19:55

标签: c x86 byte bit

_loaddqu_LE内部存储按相反顺序存储。请建议一种解决方法,或先使用数组先重新排列字节,然后再使用_loaddqu_LE

#include <stdio.h>

int main() {
uint32_t src[16];
__m128i a; /* 128 bit */

src[0] = 0x00000000;
src[1] = 0x00000000;
src[2] = 0x00000000;
src[3] = 0x00000000;
src[4] = 0x63636362;
src[5] = 0x63636362;
src[6] = 0x63636362;
src[7] = 0x63636362;
src[8] = 0xc998989b;
src[9] = 0xaafbfbf9;
src[10] =0xc998989b; 
src[11] =0xaafbfbf9;
src[12] =0x50349790;
src[13] =0xfacf6c69;
src[14] =0x3357f4f2;
src[15] =0x99ac0f0b;

/* load 32 bits */
a = _loaddqu_LE((const char _ptr64 *) & (((__m128i *)src)[0]));
printf("0x%016llx%016llx\n", a.v0, a.v1);
a = _loaddqu_LE((const char _ptr64 *) & (((__m128i *)src)[1]));
printf("0x%016llx%016llx\n", a.v0, a.v1);

return 0;
}

实际输出:

0x00000000000000000000000000000000
0x62636363626363636263636362636363

预期输出:

0x00000000000000000000000000000000
0x63636362636363626363636263636362

1 个答案:

答案 0 :(得分:0)

假设您有一个128位无符号整数

28018020645823955151501786048551321856

以十六进制表示,是

0x15141312111009080706050403020100

在使用little-endian byte order的体系结构上,例如64位Intel / AMD(考虑使用的__m128i类型,它是最有可能的候选者),该数字以十六进制形式存储在内存中

0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 0x11 0x12 0x13 0x14 0x15

我们可以将这些字节重新解释为例如八个16位无符号整数,

0x0100 0x0302 0x0504 0x0706 0x0908 0x1110 0x1312 0x1514

或四个32位无符号整数

0x03020100 0x07060504 0x11100908 0x15141312

或两个64位无符号整数

0x0706050403020100 0x1514131211100908

OP希望将128位无符号整数输入分成两个64位无符号整数。英特尔/ AMD内部函数为此提供了_mm_shuffle_epi8()_mm_set_epi8()内部函数。 (如果OP使用的是TNS / X C / C ++,则等效的内在函数为_pshufb()_mm_set_epi8()。)

_mm_set_epi8()内在函数采用16个参数(最高有效字节在前)并将它们打包为128位整数。 _mm_shuffle_epi8() / _pshufb()内在函数使用两个128位整数作为参数,并返回一个128位整数,该整数由第一个参数中的字节构成,并由第二个参数中的字节指示。


以下是一些有用的字节顺序常量:

/* SWAP128_128 = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); */
#define  SWAP128_128  { 579005069656919567LL, 283686952306183LL }

/* SWAP128_64 = _mm_set_epi8(8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7); */
#define  SWAP128_64  { 283686952306183LL, 579005069656919567LL };

/* SWAP128_32 = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); */
#define  SWAP128_32  { 289644378169868803LL, 868365760874482187LL }; 

/* SWAP128_16 = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1); */
#define  SWAP128_16  { 434320308619640833LL, 1013041691324254217LL };

const __m128i  swap128_128 = SWAP128_128;
const __m128i  swap128_64  = SWAP128_64;
const __m128i  swap128_32  = SWAP128_32;
const __m128i  swap128_16  = SWAP128_16;

请注意,常量声明假定C编译器实现了__m128i类型,就好像它是两个long long(据我所知,所有支持SSE3的类型都可以)。无论如何,您都可以使用_mm_set_epi8()内在函数构造常量。

将它们放入宏的原因是,如果遇到compiler or architecture,而该https://mongodb.github.io/mongo-java-driver/3.4/javadoc/com/mongodb/MongoClientURI.html需要不同类型的声明才能获得相同的有效值(与各自的_mm_set_epi8()内在收益率一样),则只需要少量的预处理器按摩。

使用以上命令,a = _mm_shuffle_epi8(a, swap128_128);(对于TNS / X C / C ++,则为a = _pshufb(a, swap128_128))将反转整个字节顺序; swap128_64仅是两个64位分量的字节顺序,swap128_32是所有四个32位分量的字节顺序,swap128_16是所有八个16位分量的字节顺序。还有11种其他变体(加上“ no shuffle”,对于128位值而言,总共16个字节顺序),再加上您可以将源字节复制到目标字节,因此请使用_mm_set_epi8()查找所需的一个

鉴于上述数据,

const uint8_t  data[16] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
};
__m128i vector = _mm_lddqu_si128((const __m128i *)data);
__m128i v128 = _mm_shuffle_epi8(vector, swap128_128);
__m128i v64 = _mm_shuffle_epi8(vector, swap128_64);
__m128i v32 = _mm_shuffle_epi8(vector, swap128_32);
__m128i v16 = _mm_shuffle_epi8(vector, swap128_16);

将产生:

vector = 0x0706050403020100 0x1514131211100908
       = 0x03020100 0x07060504 0x11100908 0x15141312
       = 0x0100 0x0302 0x0504 0x0706 0x0908 0x1110 0x1312 0x1514
       = 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 0x11 0x12 0x13 0x14 0x15

v128 = 0x0809101112131415 0x0001020304050607
     = 0x12131415 0x08091011 0x04050607 0x00010203
     = 0x1415 0x1213 0x1011 0x0809 0x0607 0x0405 0x0203 0x0001
     = 0x15 0x14 0x13 0x12 0x11 0x10 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00

v64 = 0x0001020304050607 0x0809101112131415
    = 0x04050607 0x00010203 0x12131415 0x08091011
    = 0x0607 0x0405 0x0203 0x0001 0x1415 0x1213 0x1011 0x0809
    = 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00 0x15 0x14 0x13 0x12 0x11 0x10 0x09 0x08

v32 = 0x0405060700010203 0x1213141508091011
    = 0x00010203 0x04050607 0x08091011 0x12131415
    = 0x0203 0x0001 0x0607 0x0405 0x1011 0x0809 0x1415 0x1213
    = 0x03 0x02 0x01 0x00 0x07 0x06 0x05 0x04 0x11 0x10 0x09 0x08 0x15 0x14 0x13 0x12

v16 = 0x0607040502030001 0x1415121310110809
    = 0x02030001 0x06070405 0x10110809 0x14151213
    = 0x0001 0x0203 0x0405 0x0607 0x0809 0x1011 0x1213 0x1415
    = 0x01 0x00 0x03 0x02 0x05 0x04 0x07 0x06 0x09 0x08 0x11 0x10 0x13 0x12 0x15 0x14

取决于您希望如何解释每个__m128i。 (第一个是两个64位整数,第二个是四个32位整数,第三个是八个16位整数,第四个是16个字节。)

还有许多其他可能的变化(对于128位值,可能有16个唯一的字节顺序),但是在不确切知道潜在问题是什么以及OP试图实现什么的情况下,我不会费心探索它们全部。