如何在_mm256_shuffle_epi8意义在这个游戏中生命的实施?

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

让我实现Conway's Game of Life使用内部函数功课找到工作的代码,但无法理解它的主要部分。

此实现首先计算活着的邻居每卖出的量,结果存储在数组中counts,所以销售的产品(世界)的阵列states。我真的不能得到如何newstate在这里产生。我的理解是如何转变工作向左,如何按位或工作,但我不明白他们为什么这样使用,为什么shufmask是这样,如何洗牌的作品。也无法理解为什么_mm256_slli_epi16使用,如果数组元素的类型是uint8_t。所以我的问题是关于这个字符串

__m256i newstate = _mm256_shuffle_epi8(shufmask, _mm256_or_si256(c, _mm256_slli_epi16(oldstate, 3)));

能否请您给我解释一下,假的孩子,如果有可能的最大详细介绍,它是如何工作的。

void gameoflife8vec(uint8_t *counts, uint8_t *states, size_t width, size_t height) {
assert(width % (sizeof(__m256i)) == 0);
size_t awidth = width + 2;
computecounts8vec(counts, states, width, height);
__m256i shufmask =
    _mm256_set_epi8(
        0, 0, 0, 0, 0, 1, 1, 0,
        0, 0, 0, 0, 0, 1, 0, 0,
        0, 0, 0, 0, 0, 1, 1, 0,
        0, 0, 0, 0, 0, 1, 0, 0
    );
for (size_t i = 0; i < height; i++) {
    for (size_t j = 0; j < width; j += sizeof(__m256i)) {
        __m256i c = _mm256_lddqu_si256(
            (const __m256i *)(counts + (i + 1) * awidth + j + 1));
        c = _mm256_subs_epu8(
            c, _mm256_set1_epi8(
                1)); // max was 8 = 0b1000, make it 7, 1 becomes 0, 0 remains 0

        __m256i oldstate = _mm256_lddqu_si256(
            (const __m256i *)(states + (i + 1) * awidth + j + 1));
        __m256i newstate = _mm256_shuffle_epi8(
            shufmask, _mm256_or_si256(c, _mm256_slli_epi16(oldstate, 3)));
        _mm256_storeu_si256((__m256i *)(states + (i + 1) * awidth + (j + 1)),
            newstate);
    }
}
}

数组的内存以这种方式分配

uint8_t *states = (uint8_t *)malloc((N + 2) * (N + 2) * sizeof(uint8_t));
uint8_t *counts = (uint8_t *)malloc((N + 2) * (N + 2) * sizeof(uint8_t));

另外,源代码可以在这里找到https://github.com/lemire/SIMDgameoflife

c++ intrinsics avx conways-game-of-life
1个回答
6
投票

shuffle_epi8正在这里用作并行表查找,具有恒定的第一操作数和变量第二操作数。

丹尼尔的代码做一些计算方法,产生在载体的每一个字节一个4位整数,然后使用_mm256_shuffle_epi8这些整数映射到0/1活着,或者死新的状态。

请注意,shufmask的低和高通道是相同的:它是两车道相同的查找表。 (这不是一个车道交叉洗牌,它的32个并行查找从2×16个字节的表中,在每个元件中使用低4位,而且高比特为零出来。)


shufmask是变量名的一个糟糕的选择。这不是洗牌,对照载体。 alivetable可能是一个更好的选择。


使用[v]pshufb实现16入口LUT是一个(相当)的公知技术。这是实现大型阵列,这比标快POPCNT的一种方式,分裂到字节低/高半仰起脸4位POPCNT结果。见Counting 1 bits (population count) on large data using AVX-512 or AVX-2,具体https://github.com/WojciechMula/sse-popcount/blob/master/popcnt-avx2-lookup.cpp

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