MMX операция (добавить 16 бит не сделано) - PullRequest
2 голосов
/ 29 июня 2011

Я получил несколько векторов, содержащих символы без знака, которые представляют пиксели из кадра. Эта функция работает без улучшения MMX, но я разочарован тем, что MMX не работает ... Итак:

Мне нужно добавить два знака без знака (сумма должна быть сделана как 16-битная, а не 8-битная, потому что символ без знака идет от 0 до 255, как известно) и разделить их на две (сдвиг вправо на 1). Код, который я сделал до сих пор, приведен ниже, но значения неверны, add_pu16 не добавляет 16 бит просто 8:

  MM0 = _mm_setzero_si64();        //all zeros
  MM1 = TO_M64(lv1+k);             //first 8 unsigned chars
  MM2 = TO_M64(lv2+k);             //second 8 unsigned chars

  MM3 =_mm_unpacklo_pi8(MM0,MM1);  //get first 4chars from MM1 and add Zeros
  MM4 =_mm_unpackhi_pi8(MM0,MM1);  //get last 4chars from MM1 and add Zeros

  MM5 =_mm_unpacklo_pi8(MM0,MM2);  //same as above for line 2
  MM6 =_mm_unpackhi_pi8(MM0,MM2);

  MM1 = _mm_adds_pu16(MM3,MM5);    //add both chars as a 16bit sum (255+255 max range)
  MM2 = _mm_adds_pu16(MM4,MM6);

  MM3 = _mm_srai_pi16(MM1,1);      //right shift (division by 2)
  MM4 = _mm_srai_pi16(MM2,1);

  MM1 = _mm_packs_pi16(MM3,MM4);   //pack the 2 MMX registers into one

  v2 = TO_UCHAR(MM1);              //put results in the destination array

Новые разработки: Спасибо за этот кинг_нак !! Я написал простую версию того, что я пытаюсь сделать:


int main()
{
char A[8]={255,155,2,3,4,5,6,7};
char B[8]={255,155,2,3,4,5,6,7};
char C[8];
char D[8];
char R[8];

__m64* pA=(__m64*) A;

__m64* pB=(__m64*) B;

__m64* pC=(__m64*) C;

__m64* pD=(__m64*) D;

__m64* pR=(__m64*) R;

_mm_empty();

__m64 MM0 = _mm_setzero_si64();

__m64 MM1 = _mm_unpacklo_pi8(*pA,MM0);

__m64 MM2 = _mm_unpackhi_pi8(*pA,MM0);

__m64 MM3 = _mm_unpacklo_pi8(*pB,MM0);

__m64 MM4 = _mm_unpackhi_pi8(*pB,MM0);

__m64 MM5 = _mm_add_pi16(MM1,MM3);

__m64 MM6 = _mm_add_pi16(MM2,MM4);

printf("SUM:\n");

*pC= _mm_add_pi16(MM1,MM3);

*pD= _mm_add_pi16(MM2,MM4);

for(int i=0; i<8; i++) printf("\t%d ", (C[i])); printf("\n");

for(int i=0; i<8; i++) printf("\t%d ", D[i]); printf("\n");

printf("DIV:\n");

*pC= _mm_srai_pi16(MM5,1);

*pD= _mm_srai_pi16(MM6,1);

for(int i=0; i<8; i++) printf("\t%d ", (C[i])); printf("\n");

for(int i=0; i<8; i++) printf("\t%d ", D[i]); printf("\n");

MM1= _mm_srai_pi16(MM5,1);    
MM2= _mm_srai_pi16(MM6,1);

printf("Final Result:\n");
*pR= _mm_packs_pi16(MM1,MM2);
for(int i=0; i<8; i++) printf("\t%d ", (R[i])); printf("\n");

return(0);
}

И результаты:

SUM:

-2  1   54  1   4   0   6   0 

8   0   10  0   12  0   14  0 

ДИВ:

-1  0   -101    0   2   0   3   0 

4   0   5   0   6   0   7   0 

Окончательный результат:

127     127     2   3   4   5   6   7 

Ну, маленькие числа в порядке, в то время как большие числа, которые дают 127, неправильны. Это проблема, что я делаю не так: s

Ответы [ 3 ]

4 голосов
/ 29 июня 2011

Вы должны переключать операнды в вызовах _mm_unpacklo_pi8.При этом байты значения находятся в старших байтах слова (например, AB и 00 упакованы в AB00).После сложения и сдвига значения будут больше, чем 0x7F, и, таким образом, будут насыщены до этого значения инструкцией пакета.

С переключенными операндами вычисление выполняется для таких значений, как 00AB, и результатбудет помещаться в подписанный байт.

UPATE:
После вашей дополнительной информации я вижу, что проблема связана с _mm_packs_pi16.Это инструкция по сборке packsswb, которая будет насыщать со знаком байт.Например, для значений> 127 будет установлено значение 127. (255+255)>>1 равно 255, а (155+155)>>1 равно 155 ...
Используйте взамен _mm_packs_pu16.Это обрабатывает значения как неподписанные байты, и вы получите желаемые результаты (255/155).

1 голос
/ 30 июня 2011

Кроме того, вам не нужно 16-битное промежуточное звено для вычисления среднего двух 8-битных значений.Формулировка:

(a >> 1) + (b >> 1) + (a & b & 1)

дает правильный результат с необходимыми только 8-битовыми интермедиатами.Возможно, вы сможете использовать это для повышения пропускной способности, если у вас есть 8-битные векторные инструкции.

1 голос
/ 29 июня 2011

Я думаю, что нашел проблему: Аргументы инструкций распаковки находятся в неправильном порядке. Если вы посмотрите на регистры в целом, похоже, что отдельные символы расширяются от нуля до шортов, но на самом деле они заполнены нулями - . Просто поменяйте местами mm0 и другой регистр в каждом случае, и он должен работать.

Кроме того, вам не нужно насыщенное добавление, достаточно обычного PADDW. Максимальное значение, которое вы получите: 0xff + 0xff = 0x01fe, которое не должно быть насыщенным.

Редактировать: Более того, PACKSSWB не совсем делает то, что вы хотите. PACKUSWB - правильная инструкция, насыщение приведет к неверным результатам.

Вот решение (также заменил смены на логические и в некоторых местах использовали разные псевдорегистры):

mm0=pxor(mm0,mm0) =[00,00,00,00,00,00,00,00]
mm1 =[a0,10,ff,18,7f,f0,ff,cc]
mm2 =[c0,20,ff,00,70,26,ff,01]
mm3=punpcklbw(mm1,mm0) =[00a0,0010,00ff,0018]
mm4=punpckhbw(mm1,mm0) =[007f,00f0,00ff,00cc]
mm5=punpcklbw(mm2,mm0) =[00c0,0020,00ff,0000]
mm6=punpckhbw(mm2,mm0) =[0070,0026,00ff,0001]
mm5=paddw(mm3,mm5) =[0160,0030,01fe,0018]
mm6=paddw(mm4,mm6) =[00ef,0116,01fe,00cd]
mm3=psrlwi(mm5,1) =[00b0,0018,00ff,000c]
mm4=psrlwi(mm6,1) =[0077,008b,00ff,0066]
mm1=packuswb(mm3,mm4) =[b0,18,ff,0c,77,8b,ff,66]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...