ARM での software packed 演算による飽和加算(3)

昨日のやつ、ちゃんと動いてませんでしたorz


どうやら、

    EOR     r1, r2, r2, LSR #16 ; r1 = r2 ^ (r2 >> 16)
    AND     r1, r1, r7          ; r1 = r1 & 0x7beff7de
    ADD     r0, r0, r1, LSR #1  ; r0 = r0 + (r1 >> 1)

EOR をやると r1 にゴミが残っていて、r7 も上位にゴミがあるため、AND をしても まだゴミが残っていて、しかも ADD の部分で右シフトしているため、16bit目にあるゴミが r0 に入っているようです。
なので、

    ; r7 = 0x7beff7de
    ; r8 = 0x08010821
    ; r2 = c0 | (c1 << 16)
    AND     r0, r2, r2, LSR #16 ; r0 = r2 & (r2 >> 16)
    EOR     r1, r2, r2, LSL #16 ; r1 = r2 ^ (r2 << 16)
    AND     r1, r7, r1, LSR #16 ; r1 = 0x7beff7de & (r1 >> 16)
    ADD     r0, r0, r1, LSR #1  ; r0 = r0 + (r1 >> 1)
    AND     r0, r0, r8, LSR #1  ; r0 = r0 & (0x08010821 >> 1)

    ADD     r0, r0, r8, LSR #12 ; r0 = r0 + (0x08010821 >> 12)
    AND     r0, r8, r0, LSR #5  ; r0 = 0x08010821 & (r0 >> 5)
    ADD     r0, r7, r0, LSL #16 ; r0 = 0x7beff7de & (r0 << 16)
    EOR     r0, r0, r7          ; r0 = r0 ^ 0x7beff7de
    ADD     r1, r2, r2, LSR #16 ; r1 = r2 + (r2 >> 16)
    SUB     r1, r1, r0, LSR #16 ; r1 = r1 - (r0 >> 16)
    ORR     r0, r1, r0, LSR #16 ; r0 = r1 | (r0 >> 16)

2,3行目だけ変更しています。
このように、最初の EOR の時点では左16ビットで計算して、右シフトしながら AND をしています。
こうすると、ゴミが残らないので成功します。


Windows で全パターンの加算合成を試してみたので大丈夫かと。
……まあ、テストプログラムが間違ってなかったらの話ですが(;´Д`)



ところでこれって、C言語で書くと、

unsigned int r7 = 0x7beff7de;
unsigned int r8 = 0x08010821;
unsigned int r2 = c0 | (c1 << 16);
unsigned int r0;
r0 = (((((((((r2 >> 16) & r2) + (((((r2 << 16) ^ r2) >> 16) & r7 ) >> 1)) & (r8 >> 1)) + (r8 >> 12)) >> 5) & r8) << 16) + r7) ^ r7;
r0 = (((r2 >> 16) + r2) - (r0 >> 16)) | (r0 >> 16);

こうなるんですけど、可読性皆無っていうか、ほんとに効率の良いコードなのかと疑いたくなりますね。