6

我正在使用 2 个无符号短裤的紧凑结构来指示开始和结束位置。
我需要能够快速确定是否有任何Range长度(从开始到结束的差异)超过阈值的对象。

我将拥有大量对象,每个对象都有自己的数组,因此在列表或其他内容中跟踪哪些对象高于阈值Range是不可行的。Range这段代码也会经常运行(每个数组每秒运行很多次),所以它需要高效。

struct Range
{
 unsigned short start;
 unsigned short end;
}

Range我将始终拥有一个大小为 2^n的数组。虽然我想在发现超过阈值的东西后立即中止,但我很确定将它们简单地或全部放在一起并在最后检查会更快......假设我可以对循环进行矢量化。虽然如果我可以对每个向量的结果块做一个 if 语句,那就太好了。

size_t rangecount = 1 << resolution;
Range* ranges = new Range[rangecount];

...

bool result = false;
for (size_t i = 0; i < ranges; ++i)
{
 result |= (range[i].end - range[i].start) > 4;
}

毫不奇怪,自动矢量化器会给出 1202 错误,因为我的数据类型不是 32 位或 64 位宽。我真的不想将我的数据大小加倍并使每个字段都成为无符号整数。所以我猜想自动矢量化方法不适合这个。

是否有可以处理 16 位变量的向量指令?如果有,我如何在 C++ 中使用它们来矢量化我的循环?

4

1 回答 1

1

您想知道是否有任何值大于 4?

是的,有这方面的 SIMD 指令。不幸的是,自动矢量化无法处理这种情况。这是一个矢量化算法:

diff_v = end_v - start_v; // _mm_hsub_epi16 
floor_v = max(4_v, diff_v); // _mm_max_epi16 
if (floor_v != 4_v) return true; // wide scalar comparison

_mm_sub_epi16与数组结构或结构数组一起使用_mm_hsub_epi16

实际上,由于start首先存储在内存中,因此您将处理start_v - end_v,因此使用_mm_min_epi16和 的向量-4

每条 SSE3 指令一次将执行 8 次比较。提前返回而不是循环仍然是最快的。然而,更多地展开循环可能会给你带来额外的速度(将第一组结果传递到打包的 min/max 函数中以组合它们)。

所以你最终(大约):

most_negative = threshold = _mm_set_epi64(0xFCFCFCFCFCFCFCFC); // vectorized -4

loop:
    a = load from range;
    b = load from range;
    diff = _mm_hsub_epi16(a, b);
    most_negative = _mm_min_epi16(most_negative, diff);

    // unroll by repeating the above four instructions 4 times or so
    if (most_negative != threshold) return true;
repeat loop
于 2012-12-21T16:23:15.437 回答