2

32ビットワードに2つの符号付き16ビット値があり、定数値(1から6まで可能)で右にシフト(除算)し、バイト(0..0xFF)に飽和させる必要があります。

例えば、

  • shift=5の0xFFE100AAは、0x00000005になる必要があります。
  • 0x23451234は0x00FF0091になる必要があります

次のような擬似コードのように、値を同時に飽和させようとしています。

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

しかし、私が取得するコードは非常に醜くて遅いです。:)私が今持っている最高の(最速の)ものは、次のように、各半分の別々の飽和です:

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

しかし、それは10サイクルです。:(もっと速くできますか?

ps:後で、このためのUSAT16命令を見つけましたが、これはARMv6専用です。そして、ARMv5TEとARMv4で動作するコードが必要です。


編集:今、私は私の最初のコードを書き直します:

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     

しかし、それは美しくありません。

4

2 に答える 2

1

あなたが持っているものは、あなたが述べたように問題のためにやろうとしているのとほぼ同じくらい良いです。タイトなループで大量のデータに対してこれを実行し、マスクを保持するためのいくつかのレジスタを使用できる場合は、1〜2サイクル節約できる可能性がありますが、大きな改善にはなりません。v6アーキテクチャ以前のARMでは、このタイプの「小ベクトル」飽和操作はあまりサポートされていません。

基本的に、これがプログラムの唯一のボトルネックでない限り、これを片付けて次のホットスポットに移動するときが来ました。

于 2009-08-17T02:19:55.807 に答える
1

1つのチェックを使用して2つの操作のフラグを設定することをお勧めします。しかし、私は第二部のためにそれをすることはできません。私は何か他のことをすることができます:)これは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

つまり、今は7サイクルです。:)

それはもっと良くなることができますか?


編集:オーバーフローは十分にまれであるように見えるので、次のようなものを追加することをお勧めします:

TST R0, 0xE000E000
BEQ no_saturation_needed
... ; saturation ops here
于 2009-08-18T06:24:08.473 に答える