В академических целях я хочу попытаться написать ARM NEON оптимизацию следующего алгоритма, даже для проверки того, можно ли добиться какого-либо улучшения производительности или нет. Я думаю, что это не очень хороший кандидат для оптимизации SIMD, потому что результаты объединены с потерей доходов от параллелизации.Рекомендация в оптимизации ARM NEON
Это алгоритм:
const uchar* center = ...;
int t0, t1, val;
t0 = center[0]; t1 = center[1];
val = t0 < t1;
t0 = center[2]; t1 = center[3];
val |= (t0 < t1) << 1;
t0 = center[4]; t1 = center[5];
val |= (t0 < t1) << 2;
t0 = center[6]; t1 = center[7];
val |= (t0 < t1) << 3;
t0 = center[8]; t1 = center[9];
val |= (t0 < t1) << 4;
t0 = center[10]; t1 = center[11];
val |= (t0 < t1) << 5;
t0 = center[12]; t1 = center[13];
val |= (t0 < t1) << 6;
t0 = center[14]; t1 = center[15];
val |= (t0 < t1) << 7;
d[i] = (uchar)val;
Это то, что я думал, что в ARM сборки:
VLD2.8 {d0, d1} ["center" addr]
предполагающей 8-битные символы, это первая операция должна загрузить все значения t0 и t1 альтернативно 2 регистра.
VCLT.U8 d2, d0, d1
отдельная операция «меньше» для всех сравнений. ПРИМЕЧАНИЯ: Я читал, что VCLT возможен только с константой # 0 как второй операнд, поэтому это нужно инвертировать в a> =. Чтение документации ARM. Думаю, результат каждого 8-битного значения будет «все 1» для true (11111111) или «all 0» для false (00000000).
VSHR.U8 d4, d2, #7
этот сдвиг вправо удалит 7 из 8 значений в регистре 8-битных «клеток» (в основном, чтобы удалить из них 7). Я использовал d4, потому что следующим шагом будет первый регистр d, отображаемый в q2.
Теперь проблемы начинаются: сдвигаются и ОР.
VSHLL.U8 q2[1], d4[1], 1
VSHLL.U8 q2[2], d4[2], 2
...
VSHLL.U8 q2[7], d4[7], 7
Я могу представить только этот способ (если можно использовать [смещения]) для левых сдвигов. Q2 следует указывать вместо d4 в соответствии с документацией.
VORR(.U8) d4[0], d4[1], d4[0]
VORR(.U8) d4[0], d4[2], d4[0]
...
VORR(.U8) d4[0], d4[7], d4[0]
Последний шаг должен дать результат.
VST1.8 d4[0], [d[i] addr]
Простой магазин результата.
Это мой первый подход к ARM NEON, поэтому, вероятно, многие допущения могут быть неверными. Помогите мне понять возможные ошибки и предложите лучшее решение, если это возможно.
EDIT: Это последний рабочий код после предложенных решений:
__asm__ __volatile ("VLD2.8 {d0, d1}, [%[ordered_center]] \n\t"
"VCGT.U8 d2, d1, d0 \n\t"
"MOV r1, 0x01 \n\t"
"MOV r2, 0x0200 \n\t"
"ORR r2, r2, r1 \n\t"
"MOV r1, 0x10 \n\t"
"MOV r3, 0x2000 \n\t"
"ORR r3, r3, r1 \n\t"
"MOVT r2, 0x0804 \n\t"
"MOVT r3, 0x8040 \n\t"
"VMOV.32 d3[0], r2 \n\t"
"VMOV.32 d3[1], r3 \n\t"
"VAND d0, d2, d3 \n\t"
"VPADDL.U8 d0, d0 \n\t"
"VPADDL.U16 d0, d0 \n\t"
"VPADDL.U32 d0, d0 \n\t"
"VST1.8 d0[0], [%[desc]] \n\t"
:
: [ordered_center] "r" (ordered_center), [desc] "r" (&desc[i])
: "d0", "d1", "d2", "d3", "r1", "r2", "r3");
http://stackoverflow.com/questions/11870910/sse-mm-movemask-epi8-equivalent-method-for-arm-neon не уверен, почему это не отображается как связанное, когда оно цитируется в ответе. .. –