该代码的目的是将字符串 str 的每个字符减去键数组中的值。该程序的非矢量化版本对应于两个程序中的最后一个周期。 这段代码怎么样:
void decode(const char* key, int m, char* str) {
int i; int n = strlen(str);
__m128i k = _mm_loadu_si128((const __m128i*) key);
for (int i = 0; i + 16 < n; i+=m) {
__m128i s = _mm_loadu_si128((__m128i*) (str + i));
s = _mm_sub_epi8(s, k);
_mm_storeu_si128((__m128i*) (str + i), s);
}
for(; i<n; i++) str[i] -= key[i%m];
}
与此不同?
void decode(const char* key, int m, char* str) {
int i, n = strlen(str);
char keybuf[16] = { 0 };
memcpy(keybuf, key, m);
__m128i k = _mm_loadu_si128((__m128i*)keybuf);
for (i=0; i+16 < n; i += m) {
__m128i s = _mm_loadu_si128((__m128i*)(str+i));
s = _mm_sub_epi8(s,k);
_mm_storeu_si128((__m128i*)(str+i), s);
}
for (; i<n; i++) str[i] -= key[i % m]; }
如果没有内存复制,相同的代码就不会以相同的方式工作。 我正在使用 gcc -msse2 进行编译。 为什么需要内存复制?
最佳答案
不同之处在于,在第二种情况下,您仅将 m
个字符加载到 keybuf
中,其余元素保持初始化为 0。这些附加元素将不起作用在 str
上。
但是,在第一个版本中, vector 末尾很可能有非零元素,因为无论 key 的实际长度如何,您都会盲目地从 key
加载所有 16 个元素。
为了使第一个版本正常工作,您需要屏蔽 k
的最终 16 - m
元素,强制它们为零,例如
const int8_t mask[32] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
__m128i k = _mm_loadu_si128((const __m128i*) key); // load 16 elements
k = _mm_and_si128(k, _mm_loadu_si128((const __m128i*)&mask[16 - m]));
// mask out final 16 - m elements
(注意:可能有一种更有效的屏蔽方法,但这是我在短时间内能想到的最好方法。它仍然比 memcpy
版本更有效,我猜。请参阅 this question and its answers 了解其他一些方法。)
关于c - Intel 负载固有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41741839/