2009-08-16 6 views
2

J'ai deux valeurs de 16 bits signées dans un mot de 32 bits, et j'ai besoin de les déplacer à droite (diviser) sur une valeur constante (cela peut être de 1 à 6) et saturer en octet (0..0xFF).Rapide Saturer et décaler deux demi-mots dans ARM asm

Par exemple,

  • 0x FFE1 00AA avec changement = 5 doit devenir 0x 0000 0005;
  • 0x 2345 1234 doit devenir 0x 00FF 0091

Je suis en train de saturer les valeurs en même temps, quelque chose comme ce pseudo-code:

AND RT, R0, 0x80008000; - mask high bits to get negatives 
ORR RT, RT, LSR #1 
ORR RT, RT, LSR #2 
ORR RT, RT, LSR #4 
ORR RT, RT, LSR #8; - now its expanded signs in each halfword 
MVN RT, RT 
AND R0, RT; now negative values are zero 
; here something to saturate high overflow and shift after 

mais le code que je reçois est très moche et lent. :) Le meilleur (le plus rapide) que j'ai maintenant la saturation séparée chaque moitié, comme ceci:

MOV RT, R0, LSL #16 
MOVS RT, RT, ASR #16+5 
MOVMI RT, #0 
CMP RT, RT, #256 
MOVCS RT, #255 
MOVS R0, R0, ASR #16+5 
MOVMI R0, #0 
CMP R0, R0, #256 
MOVCS R0, #255 
ORR R0, RT, R0, LSL #16 

Mais il est 10 cycles. :(Peut-il être plus rapide

ps: plus tard je l'ai trouvé USAT16 instructions pour, mais il est seulement pour ARMv6 Et je besoin du code pour travailler sur ARMv5TE et ARMv4


Edit..: maintenant je récrire mon premier code.

ANDS RT, 0x10000, R0 << 1;  // 0x10000 is in register. Sign (HI) moves to C flag, Sign (LO) is masked 
SUBNE RT, RT, 1;   // Mask LO with 0xFFFF if it's negative 
SUBCS RT, RT, 0x10000;  // Mask HI with 0xFFFF if it's negative 
BIC R0, R0, RT;   // Negatives are 0 now. The mask can be used as XOR too 
TST R0, 0xE0000000;   // check HI overflow    
ORRNE R0, R0, 0x1FE00000  // set HI to 0xFF (shifted) if so 
TST R0, 0x0000E000   // check LO overflow    
ORRNE R0, R0, 0x00001FE0  // set LO to 0xFF if so   
AND R0, 0x00FF00FF, R0 >> 5; // 0x00FF00FF is in register  

mais il est pas beau

+0

Avez-vous il essayé d'écrire en C, puis voir ce que le compilateur produit? –

+0

Steve, je ne sais pas comment l'écrire en C sans traitement séparé des moitiés. Mais mon cerveau crée quelques idées :) L'un d'entre eux est "masque XOR". Il doit contenir 0 (dans chaque moitié individuellement), si le nombre est OK. Si le nombre est négatif, il se contiendra. Un débordement positif, il contiendra le numéro^0xFFFF. Donc le résultat sera source^mask. Mais n'a pas d'idées, comment le faire simultanément – zxcat

Répondre

1

C'était une bonne idée d'utiliser une vérification pour définir des indicateurs pour deux opérations. Mais je ne peux pas le faire pour la deuxième partie. Je peux faire quelque chose d'autre :) Voici variante universelle à utiliser avec tout changement de 1 à 6:

;prepare: 
MOV RMask, ((0xFF00 << shift) & 0xFF00) << 16; Mask overflow bits 
MOV R_0xFF00FF, 0xFF; 
ORR R_0xFF00FF, 0xFF000000; 
;... 
; innerloop: 
;.... 
TST R0, RMask, R0 << 16;   Set flags for LO half 
ORRNE R0, R0, 0xFF << shift;  It is overflow. First try positive 
BICMI R0, R0, 0xFF << shift;  Fix it if negative. LO half is ready 
TST R0, RMask, R0;    Set flags for HI half. Can TST R0, R0, #Mask also 
ORRNE R0, R0, 0xFF << (shift+16) 
BICNE R0, R0, 0xFF << (shift+16) 
AND R0, R_0xFF00FF, R0 >> shift;  Shift and mask 

Il est donc 7 cycles maintenant. :)

Peut-il être mieux?


Edit: ressemble trop-pleins sont assez rares, il est donc une bonne idée d'ajouter quelque chose comme ceci:

TST R0, 0xE000E000 
BEQ no_saturation_needed 
... ; saturation ops here 
1

Qu'est-ce que vous h Ave est à peu près aussi bon que vous allez faire pour le problème comme indiqué. Si vous le faites pour beaucoup de données dans une boucle serrée, et pouvez vous permettre quelques registres pour tenir des masques, vous pouvez enregistrer un cycle ou deux, mais cela ne va pas être une grande amélioration. Il n'y a tout simplement pas de grand support pour ce type d'opération de saturation "small-vector" sur ARM avant l'architecture v6. Fondamentalement, à moins que ce soit le seul goulot d'étranglement dans votre programme, il est temps de mettre cela et de passer à la prochaine hotspot.

+0

Oui, vous avez raison. Mon code est en boucle interne. J'ai optimisé certains traitements de données pour travailler non avec des octets, mais avec des paires d'octets. Tout allait bien, mais la saturation mange maintenant ~ 35% du temps en boucle interne :) Cette tâche est intéressante pour moi, donc je veux essayer de l'optimiser davantage. J'aime les extraits de code difficiles comme ici: http://stackoverflow.com/questions/121240/saturating-addition-in-c/121323#121323 ou http://stackoverflow.com/questions/347889/how-to-mask- bytes-in-arm-assembly/1100352 # 1100352, et peut-être que nous pouvons créer du beau code à partir de cette tâche :) – zxcat

Questions connexes