Frage

Ich habe zwei 16-Bit-Werte in einem 32-Bit-Wort signiert, und ich brauche sie nach rechts verschieben (Dividieren) auf konstanten Wert (es von 1 bis 6 sein kann) und sättigen, um Byte (0..0xFF) .

Beispiel:

  • 0x FFE1 00AA mit Shift = 5 muss sich 0x 0000 0005 ,
  • 0x 2345 1234 werden müssen 0x 00FF 0091

Ich versuche, die Werte gleichzeitig, so etwas wie dieser Pseudo-Code zu sättigen:

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

aber Code, den ich bekommen, ist sehr hässlich und langsam. :) Die beste (schnellste), was ich jetzt haben, ist getrennte Sättigung jeder Hälfte, wie folgt aus:

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

Aber es ist 10 Zyklen. :( Kann es sein, schneller?

P. S .: Später fand ich USAT16 Anweisung für diese, aber es ist nur für ARMv6. Und ich brauche Code auf ARMv5TE und ARMv4 zu arbeiten.


Edit: ich jetzt meinen ersten Code neu schreiben:

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     

, aber es ist nicht schön.

War es hilfreich?

Lösung 2

Es war eine gute Idee, einen Scheck zu verwenden Flags für zwei Operationen einzustellen. Aber ich kann es nicht für zweiten Teil tun. Ich kann etwas anderes tun :) Hier Universal-Variante ist mit jeder Verschiebung von 1 bis 6 zu verwenden:

;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

So ist es nun 7 Zyklen ist. :)

Kann es besser sein?


Edit: sieht aus wie Überläufe sind selten genug, so ist es eine gute Idee, so etwas addieren:

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

Andere Tipps

Was Sie haben, ist so gut, wie Sie für das Problem tun werden, wie angegeben. Wenn Sie dies für eine Menge von Daten in einer engen Schleife tun, und können ein paar Register leisten Masken zu halten, können Sie in der Lage sein, einen Zyklus oder zwei zu retten, aber es ist nicht eine große Verbesserung sein werde. Es ist einfach nicht große Unterstützung für diese Art von „small-Vektor“ Sättigung Betrieb auf ARM vor der v6-Architektur.

Im Grunde genommen, es sei denn dies ist die einzige Engpass in Ihrem Programm ist, ist es Zeit, diese weg zu setzen und auf den nächsten Hotspot bewegen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top