【问题标题】:Getting min short value in a __m128i vector with SSE?使用 SSE 在 __m128i 向量中获取最小短值?
【发布时间】:2015-04-18 04:15:21
【问题描述】:

这个问题似乎与Getting max value in a __m128i vector with SSE? 相似,但使用短裤和最小值而不是整数 + 最大值。这是我想出的:

typedef short int weight;

weight horizontal_min_Vec4i(__m128i x) {
    __m128i max1 = _mm_shufflehi_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max1b = _mm_shufflelo_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max2 = _mm_min_epi16(max1, max1b);
    //max2 = _mm_min_epi16(max2, x);
    max1 = _mm_shufflehi_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    max1b = _mm_shufflelo_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    __m128i max3 = _mm_min_epi16(max1, max1b);
    max2 = _mm_min_epi16(max2, max3);
    return min(_mm_extract_epi16(max2, 0), _mm_extract_epi16(max2, 4));
}

对于x的上下部分,函数的作用与https://stackoverflow.com/a/18616825/1500111中的答案基本相同。所以,我知道最小值在 __m128i 变量 max2 的位置 0 或 4 中。虽然它比下图的无 SIMD 功能 horizontal_min_Vec4i_Plain(__m128i x) 快​​得多,但恐怕瓶颈是最后一行的 _mm_extract_epi16 operation。有没有更好的方法来实现这一点,以获得更好的速度?我正在使用 Haswell,因此我可以访问最新的 SSE 扩展。

weight horizontal_min_Vec4i_Plain(__m128i x) {
    weight result[8] __attribute__((aligned(16)));
    _mm_store_si128((__m128i *) result, x);
    weight myMin = result[0];
    for (int l = 1; l < 8; l++) {
        if (myMin > result[l]) {
            myMin = result[l];
        }
    }
    return myMin;
}

【问题讨论】:

  • 为什么取 16 条短裤的水平最小值至关重要?
  • @Zboson 为 __m128i x 取最小值将执行超过 100k 次。对于这 100K 次中的每一次,总共有 24-64 个 SIMD 添加 + MAX 以在 __m128i x 内创建短值。
  • 您只是在寻找_mm_minpos_epu16吗?
  • @harold 我认为 _mm_minpos_epu16 是特定于 MS 的。我会试试看。
  • XOR 与 _mm_set1_epi16(0x8000) 如果你想找到有符号的最小值

标签: c++ sse simd sse4


【解决方案1】:

有符号和无符号比较几乎相同,除了在无符号比较中设置了最高位的范围被视为大于最高位未设置的范围,而在有符号比较中视为更小。这意味着有符号和无符号比较可以通过以下规则相互转换:

x <s y = (x ^ signbit) <u (y ^ signbit)
x <u y = (x ^ signbit) <s (y ^ signbit)

这个属性直接转移到minmax,所以:

min_s(x, y) = min_u(x ^ signbit, y ^ signbit) ^ signbit

然后我们可以使用_mm_minpos_epu16 来处理水平最小值,总共得到类似的东西

__m128i xs = _mm_xor_si128(x, _mm_set1_epi16(0x8000));
return _mm_extract_epi16(_mm_minpos_epu16(xs), 0) - 0x8000;

- 0x8000^ 0x8000 和符号扩展(extract 零扩展)合二为一。

【讨论】:

  • stackoverflow.com/questions/48730542 中寻求帮助的任何机会。谢谢。
  • @Royi 你可以使用psradpminsdpandn 将值限制在 0 和 1 之间。所有整数都具有如此低的延迟,它们都可以转到例如 Nehalem 上的不同执行端口。当然,这可能会在较新的处理器上引入一些旁路延迟..
猜你喜欢
  • 2012-04-10
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 2020-02-28
  • 2014-04-10
  • 2021-06-26
  • 1970-01-01
相关资源
最近更新 更多