Векторизация условных шорт

Я использую компактную структуру из 2 беззнаковых шорт, указывающих начальную и конечную позицию.
Я должен быть в состоянии быстро определить, есть ли Range объекты с длиной (от начала до конца) после порогового значения.

Я собираюсь иметь огромное количество объектов, каждый со своим Range массив, поэтому невозможно отследить, какой Range объекты находятся выше порога в списке или что-то. Этот код также будет запускаться очень часто (много раз в секунду для каждого массива), поэтому он должен быть эффективным.

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

Я всегда буду иметь массив Range размером 2 ^ н. Хотя я хотел бы прервать работу, как только что-то превысит порог, я почти уверен, что будет проще просто ИЛИ все это вместе и проверить в конце … при условии, что я могу векторизовать цикл. Хотя, если бы я мог сделать оператор 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 ++ для векторизации моего цикла?

6

Решение

Вам интересно, если какое-либо значение больше 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
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]