我正在使用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 ++中使用它们来矢量化我的循环?
答案 0 :(得分: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