shithub: libvpx

Download patch

ref: 022323bf856084e812354464a0302f5cb710ee78
parent: 14ba764219296ec74fab5647ca7bdc2e4ca693ce
author: Johann <johannkoenig@google.com>
date: Thu Sep 9 11:55:19 EDT 2010

reorder data to use wider instructions

the previous commit laid the groundwork by doing two sets of idcts
together. this moved that further by grouping the interesting data
(q[0], q+16[0]) together to allow using wider instructions. also
managed to drop a few instructions by recognizing that the constant
for sinpi8sqrt2 could be downshifted all the time which avoided a
dowshift as well as workarounds for a function which only accepted
signed data

looks like a modest gain for performance: at qcif, went from ~180
fps to ~183
Change-Id: I842673f3080b8239e026cc9b50346dbccbab4adf

--- a/vp8/decoder/arm/neon/idct_blk_neon.c
+++ b/vp8/decoder/arm/neon/idct_blk_neon.c
@@ -82,8 +82,6 @@
             (short *q, short *dq, unsigned char *pre,
              unsigned char *dstu, unsigned char *dstv, int stride, char *eobs)
 {
-    int i;
-
     if (((short *)eobs)[0] & 0xfefe)
         idct_dequant_full_2x_neon (q, dq, pre, dstu, 8, stride);
     else
--- a/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm
+++ b/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm
@@ -24,21 +24,22 @@
 ; sp    stride
 ; sp+4  *dc
 |idct_dequant_dc_full_2x_neon| PROC
-    vld1.16         {q3, q4}, [r0]          ; lo input
-    vld1.16         {q5, q6}, [r1]          ; use the same dq for both
+    vld1.16         {q0, q1}, [r1]          ; dq (same l/r)
+    vld1.16         {q2, q3}, [r0]          ; l q
     mov             r1, #16                 ; pitch
     add             r0, r0, #32
-    vld1.16         {q10, q11}, [r0]        ; hi input
+    vld1.16         {q4, q5}, [r0]          ; r q
     add             r12, r2, #4
-    vld1.32         {d14[0]}, [r2], r1      ; lo pred
-    vld1.32         {d14[1]}, [r2], r1
-    vld1.32         {d15[0]}, [r2], r1
-    vld1.32         {d15[1]}, [r2]
-    vld1.32         {d28[0]}, [r12], r1     ; hi pred
-    vld1.32         {d28[1]}, [r12], r1
-    vld1.32         {d29[0]}, [r12], r1
-    ldr             r1, [sp, #4]            ; dc
-    vld1.32         {d29[1]}, [r12]
+    ; interleave the predictors
+    vld1.32         {d28[0]}, [r2], r1      ; l pre
+    vld1.32         {d28[1]}, [r12], r1     ; r pre
+    vld1.32         {d29[0]}, [r2], r1
+    vld1.32         {d29[1]}, [r12], r1
+    vld1.32         {d30[0]}, [r2], r1
+    vld1.32         {d30[1]}, [r12], r1
+    vld1.32         {d31[0]}, [r2]
+    ldr             r1, [sp, #4]
+    vld1.32         {d31[1]}, [r12]
 
     ldr             r2, _CONSTANTS_
 
@@ -45,117 +46,129 @@
     ldrh            r12, [r1], #2           ; lo *dc
     ldrh            r1, [r1]                ; hi *dc
 
-    vmul.i16        q1, q3, q5              ; lo input * dq
-    vmul.i16        q2, q4, q6
-    vmul.i16        q8, q10, q5             ; hi input * dq
-    vmul.i16        q9, q11, q6
+    ; dequant: q[i] = q[i] * dq[i]
+    vmul.i16        q2, q2, q0
+    vmul.i16        q3, q3, q1
+    vmul.i16        q4, q4, q0
+    vmul.i16        q5, q5, q1
 
-    vmov.16         d2[0], r12              ; move lo dc up to neon, overwrite first element
-    vmov.16         d16[0], r1              ; move hi dc up to neon, overwrite first element
+    ; move dc up to neon and overwrite first element
+    vmov.16         d4[0], r12
+    vmov.16         d8[0], r1
 
-    ldr             r1, [sp]                ; stride
-
     vld1.16         {d0}, [r2]
-    vswp            d3, d4                  ; lo q2(vp[4] vp[12])
-    vswp            d17, d18                ; hi q2(vp[4] vp[12])
 
-    vqdmulh.s16     q3, q2, d0[2]           ; lo * constants
-    vqdmulh.s16     q4, q2, d0[0]
-    vqdmulh.s16     q10, q9, d0[2]          ; hi * constants
-    vqdmulh.s16     q11, q9, d0[0]
+    ; q2: l0r0  q3: l8r8
+    ; q4: l4r4  q5: l12r12
+    vswp            d5, d8
+    vswp            d7, d10
 
-    vqadd.s16       d12, d2, d3             ; lo a1
-    vqsub.s16       d13, d2, d3             ; lo b1
-    vqadd.s16       d26, d16, d17           ; hi a1
-    vqsub.s16       d27, d16, d17           ; hi b1
+    ; _CONSTANTS_ * 4,12 >> 16
+    ; q6:  4 * sinpi : c1/temp1
+    ; q7: 12 * sinpi : d1/temp2
+    ; q8:  4 * cospi
+    ; q9: 12 * cospi
+    vqdmulh.s16     q6, q4, d0[2]           ; sinpi8sqrt2
+    vqdmulh.s16     q7, q5, d0[2]
+    vqdmulh.s16     q8, q4, d0[0]           ; cospi8sqrt2minus1
+    vqdmulh.s16     q9, q5, d0[0]
 
-    vshr.s16        q3, q3, #1              ; lo
-    vshr.s16        q4, q4, #1
-    vshr.s16        q10, q10, #1            ; hi
-    vshr.s16        q11, q11, #1
+    vqadd.s16       q10, q2, q3             ; a1 = 0 + 8
+    vqsub.s16       q11, q2, q3             ; b1 = 0 - 8
 
-    vqadd.s16       q3, q3, q2              ; lo
-    vqadd.s16       q4, q4, q2
-    vqadd.s16       q10, q10, q9            ; hi
-    vqadd.s16       q11, q11, q9
+    ; vqdmulh only accepts signed values. this was a problem because
+    ; our constant had the high bit set, and was treated as a negative value.
+    ; vqdmulh also doubles the value before it shifts by 16. we need to
+    ; compensate for this. in the case of sinpi8sqrt2, the lowest bit is 0,
+    ; so we can shift the constant without losing precision. this avoids
+    ; shift again afterward, but also avoids the sign issue. win win!
+    ; for cospi8sqrt2minus1 the lowest bit is 1, so we lose precision if we
+    ; pre-shift it
+    vshr.s16        q8, q8, #1
+    vshr.s16        q9, q9, #1
 
-    vqsub.s16       d10, d6, d9             ; lo c1
-    vqadd.s16       d11, d7, d8             ; lo d1
-    vqsub.s16       d24, d20, d23           ; hi c1
-    vqadd.s16       d25, d21, d22           ; hi d1
+    ; q4:  4 +  4 * cospi : d1/temp1
+    ; q5: 12 + 12 * cospi : c1/temp2
+    vqadd.s16       q4, q4, q8
+    vqadd.s16       q5, q5, q9
 
-    vqadd.s16       d2, d12, d11            ; lo
-    vqadd.s16       d3, d13, d10
-    vqsub.s16       d4, d13, d10
-    vqsub.s16       d5, d12, d11
-    vqadd.s16       d16, d26, d25           ; hi
-    vqadd.s16       d17, d27, d24
-    vqsub.s16       d18, d27, d24
-    vqsub.s16       d19, d26, d25
+    ; c1 = temp1 - temp2
+    ; d1 = temp1 + temp2
+    vqsub.s16       q2, q6, q5
+    vqadd.s16       q3, q4, q7
 
-    vtrn.32         d2, d4                  ; lo
-    vtrn.32         d3, d5
-    vtrn.16         d2, d3
-    vtrn.16         d4, d5
-    vtrn.32         d16, d18                ; hi
-    vtrn.32         d17, d19
-    vtrn.16         d16, d17
-    vtrn.16         d18, d19
+    ; [0]: a1+d1
+    ; [1]: b1+c1
+    ; [2]: b1-c1
+    ; [3]: a1-d1
+    vqadd.s16       q4, q10, q3
+    vqadd.s16       q5, q11, q2
+    vqsub.s16       q6, q11, q2
+    vqsub.s16       q7, q10, q3
 
-    vswp            d3, d4                  ; lo
-    vqdmulh.s16     q3, q2, d0[2]
-    vqdmulh.s16     q4, q2, d0[0]
-    vswp            d17, d18                ; hi
-    vqdmulh.s16     q10, q9, d0[2]
-    vqdmulh.s16     q11, q9, d0[0]
+    ; rotate
+    vtrn.32         q4, q6
+    vtrn.32         q5, q7
+    vtrn.16         q4, q5
+    vtrn.16         q6, q7
+    ; idct loop 2
+    ; q4: l 0, 4, 8,12 r 0, 4, 8,12
+    ; q5: l 1, 5, 9,13 r 1, 5, 9,13
+    ; q6: l 2, 6,10,14 r 2, 6,10,14
+    ; q7: l 3, 7,11,15 r 3, 7,11,15
 
-    vqadd.s16       d12, d2, d3             ; lo a1
-    vqsub.s16       d13, d2, d3             ; lo b1
-    vqadd.s16       d26, d16, d17           ; hi a1
-    vqsub.s16       d27, d16, d17           ; hi b1
+    ; q8:  1 * sinpi : c1/temp1
+    ; q9:  3 * sinpi : d1/temp2
+    ; q10: 1 * cospi
+    ; q11: 3 * cospi
+    vqdmulh.s16     q8, q5, d0[2]           ; sinpi8sqrt2
+    vqdmulh.s16     q9, q7, d0[2]
+    vqdmulh.s16     q10, q5, d0[0]          ; cospi8sqrt2minus1
+    vqdmulh.s16     q11, q7, d0[0]
 
-    vshr.s16        q3, q3, #1              ; lo
-    vshr.s16        q4, q4, #1
-    vshr.s16        q10, q10, #1            ; hi
+    vqadd.s16       q2, q4, q6             ; a1 = 0 + 2
+    vqsub.s16       q3, q4, q6             ; b1 = 0 - 2
+
+    ; see note on shifting above
+    vshr.s16        q10, q10, #1
     vshr.s16        q11, q11, #1
 
-    vqadd.s16       q3, q3, q2              ; lo
-    vqadd.s16       q4, q4, q2
-    vqadd.s16       q10, q10, q9            ; hi
-    vqadd.s16       q11, q11, q9
+    ; q10: 1 + 1 * cospi : d1/temp1
+    ; q11: 3 + 3 * cospi : c1/temp2
+    vqadd.s16       q10, q5, q10
+    vqadd.s16       q11, q7, q11
 
-    vqsub.s16       d10, d6, d9             ; lo c1
-    vqadd.s16       d11, d7, d8             ; lo d1
-    vqsub.s16       d24, d20, d23           ; hi c1
-    vqadd.s16       d25, d21, d22           ; hi d1
+    ; q8: c1 = temp1 - temp2
+    ; q9: d1 = temp1 + temp2
+    vqsub.s16       q8, q8, q11
+    vqadd.s16       q9, q10, q9
 
-    vqadd.s16       d2, d12, d11            ; lo
-    vqadd.s16       d3, d13, d10
-    vqsub.s16       d4, d13, d10
-    vqsub.s16       d5, d12, d11
-    vqadd.s16       d16, d26, d25           ; hi
-    vqadd.s16       d17, d27, d24
-    vqsub.s16       d18, d27, d24
-    vqsub.s16       d19, d26, d25
+    ; a1+d1
+    ; b1+c1
+    ; b1-c1
+    ; a1-d1
+    vqadd.s16       q4, q2, q9
+    vqadd.s16       q5, q3, q8
+    vqsub.s16       q6, q3, q8
+    vqsub.s16       q7, q2, q9
 
-    vrshr.s16       q1, q1, #3              ; lo
-    vrshr.s16       q2, q2, #3
-    vrshr.s16       q8, q8, #3              ; hi
-    vrshr.s16       q9, q9, #3
+    ; +4 >> 3 (rounding)
+    vrshr.s16       q4, q4, #3              ; lo
+    vrshr.s16       q5, q5, #3
+    vrshr.s16       q6, q6, #3              ; hi
+    vrshr.s16       q7, q7, #3
 
-    vtrn.32         d2, d4                  ; lo
-    vtrn.32         d3, d5
-    vtrn.16         d2, d3
-    vtrn.16         d4, d5
-    vtrn.32         d16, d18                ; hi
-    vtrn.32         d17, d19
-    vtrn.16         d16, d17
-    vtrn.16         d18, d19
+    vtrn.32         q4, q6
+    vtrn.32         q5, q7
+    vtrn.16         q4, q5
+    vtrn.16         q6, q7
 
-    vaddw.u8        q1, q1, d14             ; lo
-    vaddw.u8        q2, q2, d15
-    vaddw.u8        q8, q8, d28             ; hi
-    vaddw.u8        q9, q9, d29
+    ; adding pre
+    ; input is still packed. pre was read interleaved
+    vaddw.u8        q4, q4, d28
+    vaddw.u8        q5, q5, d29
+    vaddw.u8        q6, q6, d30
+    vaddw.u8        q7, q7, d31
 
     vmov.i16        q14, #0
     vmov            q15, q14
@@ -163,19 +176,21 @@
     sub             r0, r0, #32
     vst1.16         {q14, q15}, [r0]        ; write over low input
 
-    vqmovun.s16     d0, q1                  ; lo
-    vqmovun.s16     d1, q2
-    vqmovun.s16     d2, q8                  ; hi
-    vqmovun.s16     d3, q9
+    ;saturate and narrow
+    vqmovun.s16     d0, q4                  ; lo
+    vqmovun.s16     d1, q5
+    vqmovun.s16     d2, q6                  ; hi
+    vqmovun.s16     d3, q7
 
+    ldr             r1, [sp]                ; stride
     add             r2, r3, #4              ; hi
     vst1.32         {d0[0]}, [r3], r1       ; lo
-    vst1.32         {d0[1]}, [r3], r1
+    vst1.32         {d0[1]}, [r2], r1       ; hi
     vst1.32         {d1[0]}, [r3], r1
-    vst1.32         {d1[1]}, [r3]
-    vst1.32         {d2[0]}, [r2], r1       ; hi
+    vst1.32         {d1[1]}, [r2], r1
+    vst1.32         {d2[0]}, [r3], r1
     vst1.32         {d2[1]}, [r2], r1
-    vst1.32         {d3[0]}, [r2], r1
+    vst1.32         {d3[0]}, [r3]
     vst1.32         {d3[1]}, [r2]
 
     bx             lr
@@ -184,7 +199,8 @@
 
 ; Constant Pool
 _CONSTANTS_       DCD cospi8sqrt2minus1
-cospi8sqrt2minus1 DCD 0x4e7b4e7b
-sinpi8sqrt2       DCD 0x8a8c8a8c
+cospi8sqrt2minus1 DCD 0x4e7b
+; because the lowest bit in 0x8a8c is 0, we can pre-shift this
+sinpi8sqrt2       DCD 0x4546
 
     END
--- a/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm
+++ b/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm
@@ -24,131 +24,143 @@
 ; sp    pitch
 ; sp+4  stride
 |idct_dequant_full_2x_neon| PROC
-    vld1.16         {q3, q4}, [r0]          ; lo input
-    vld1.16         {q5, q6}, [r1]          ; use the same dq for both
+    vld1.16         {q0, q1}, [r1]          ; dq (same l/r)
+    vld1.16         {q2, q3}, [r0]          ; l q
     ldr             r1, [sp]                ; pitch
     add             r0, r0, #32
-    vld1.16         {q10, q11}, [r0]        ; hi input
+    vld1.16         {q4, q5}, [r0]          ; r q
     add             r12, r2, #4
-    vld1.32         {d14[0]}, [r2], r1      ; lo pred
-    vld1.32         {d14[1]}, [r2], r1
-    vld1.32         {d15[0]}, [r2], r1
-    vld1.32         {d15[1]}, [r2]
-    vld1.32         {d28[0]}, [r12], r1     ; hi pred
-    vld1.32         {d28[1]}, [r12], r1
-    vld1.32         {d29[0]}, [r12], r1
-    vld1.32         {d29[1]}, [r12]
+    ; interleave the predictors
+    vld1.32         {d28[0]}, [r2], r1      ; l pre
+    vld1.32         {d28[1]}, [r12], r1     ; r pre
+    vld1.32         {d29[0]}, [r2], r1
+    vld1.32         {d29[1]}, [r12], r1
+    vld1.32         {d30[0]}, [r2], r1
+    vld1.32         {d30[1]}, [r12], r1
+    vld1.32         {d31[0]}, [r2]
+    vld1.32         {d31[1]}, [r12]
 
     ldr             r2, _CONSTANTS_
 
-    vmul.i16        q1, q3, q5              ; lo input * dq
-    vmul.i16        q2, q4, q6
-    vmul.i16        q8, q10, q5             ; hi input * dq
-    vmul.i16        q9, q11, q6
+    ; dequant: q[i] = q[i] * dq[i]
+    vmul.i16        q2, q2, q0
+    vmul.i16        q3, q3, q1
+    vmul.i16        q4, q4, q0
+    vmul.i16        q5, q5, q1
 
-    ldr             r1, [sp, #4]            ; stride
-
     vld1.16         {d0}, [r2]
-    vswp            d3, d4                  ; lo q2(vp[4] vp[12])
-    vswp            d17, d18                ; hi q2(vp[4] vp[12])
 
-    vqdmulh.s16     q3, q2, d0[2]           ; lo * constants
-    vqdmulh.s16     q4, q2, d0[0]
-    vqdmulh.s16     q10, q9, d0[2]          ; hi * constants
-    vqdmulh.s16     q11, q9, d0[0]
+    ; q2: l0r0  q3: l8r8
+    ; q4: l4r4  q5: l12r12
+    vswp            d5, d8
+    vswp            d7, d10
 
-    vqadd.s16       d12, d2, d3             ; lo a1
-    vqsub.s16       d13, d2, d3             ; lo b1
-    vqadd.s16       d26, d16, d17           ; hi a1
-    vqsub.s16       d27, d16, d17           ; hi b1
+    ; _CONSTANTS_ * 4,12 >> 16
+    ; q6:  4 * sinpi : c1/temp1
+    ; q7: 12 * sinpi : d1/temp2
+    ; q8:  4 * cospi
+    ; q9: 12 * cospi
+    vqdmulh.s16     q6, q4, d0[2]           ; sinpi8sqrt2
+    vqdmulh.s16     q7, q5, d0[2]
+    vqdmulh.s16     q8, q4, d0[0]           ; cospi8sqrt2minus1
+    vqdmulh.s16     q9, q5, d0[0]
 
-    vshr.s16        q3, q3, #1              ; lo
-    vshr.s16        q4, q4, #1
-    vshr.s16        q10, q10, #1            ; hi
-    vshr.s16        q11, q11, #1
+    vqadd.s16       q10, q2, q3             ; a1 = 0 + 8
+    vqsub.s16       q11, q2, q3             ; b1 = 0 - 8
 
-    vqadd.s16       q3, q3, q2              ; lo
-    vqadd.s16       q4, q4, q2
-    vqadd.s16       q10, q10, q9            ; hi
-    vqadd.s16       q11, q11, q9
+    ; vqdmulh only accepts signed values. this was a problem because
+    ; our constant had the high bit set, and was treated as a negative value.
+    ; vqdmulh also doubles the value before it shifts by 16. we need to
+    ; compensate for this. in the case of sinpi8sqrt2, the lowest bit is 0,
+    ; so we can shift the constant without losing precision. this avoids
+    ; shift again afterward, but also avoids the sign issue. win win!
+    ; for cospi8sqrt2minus1 the lowest bit is 1, so we lose precision if we
+    ; pre-shift it
+    vshr.s16        q8, q8, #1
+    vshr.s16        q9, q9, #1
 
-    vqsub.s16       d10, d6, d9             ; lo c1
-    vqadd.s16       d11, d7, d8             ; lo d1
-    vqsub.s16       d24, d20, d23           ; hi c1
-    vqadd.s16       d25, d21, d22           ; hi d1
+    ; q4:  4 +  4 * cospi : d1/temp1
+    ; q5: 12 + 12 * cospi : c1/temp2
+    vqadd.s16       q4, q4, q8
+    vqadd.s16       q5, q5, q9
 
-    vqadd.s16       d2, d12, d11            ; lo
-    vqadd.s16       d3, d13, d10
-    vqsub.s16       d4, d13, d10
-    vqsub.s16       d5, d12, d11
-    vqadd.s16       d16, d26, d25           ; hi
-    vqadd.s16       d17, d27, d24
-    vqsub.s16       d18, d27, d24
-    vqsub.s16       d19, d26, d25
+    ; c1 = temp1 - temp2
+    ; d1 = temp1 + temp2
+    vqsub.s16       q2, q6, q5
+    vqadd.s16       q3, q4, q7
 
-    vtrn.32         d2, d4                  ; lo
-    vtrn.32         d3, d5
-    vtrn.16         d2, d3
-    vtrn.16         d4, d5
-    vtrn.32         d16, d18                ; hi
-    vtrn.32         d17, d19
-    vtrn.16         d16, d17
-    vtrn.16         d18, d19
+    ; [0]: a1+d1
+    ; [1]: b1+c1
+    ; [2]: b1-c1
+    ; [3]: a1-d1
+    vqadd.s16       q4, q10, q3
+    vqadd.s16       q5, q11, q2
+    vqsub.s16       q6, q11, q2
+    vqsub.s16       q7, q10, q3
 
-    vswp            d3, d4                  ; lo
-    vqdmulh.s16     q3, q2, d0[2]
-    vqdmulh.s16     q4, q2, d0[0]
-    vswp            d17, d18                ; hi
-    vqdmulh.s16     q10, q9, d0[2]
-    vqdmulh.s16     q11, q9, d0[0]
+    ; rotate
+    vtrn.32         q4, q6
+    vtrn.32         q5, q7
+    vtrn.16         q4, q5
+    vtrn.16         q6, q7
+    ; idct loop 2
+    ; q4: l 0, 4, 8,12 r 0, 4, 8,12
+    ; q5: l 1, 5, 9,13 r 1, 5, 9,13
+    ; q6: l 2, 6,10,14 r 2, 6,10,14
+    ; q7: l 3, 7,11,15 r 3, 7,11,15
 
-    vqadd.s16       d12, d2, d3             ; lo a1
-    vqsub.s16       d13, d2, d3             ; lo b1
-    vqadd.s16       d26, d16, d17           ; hi a1
-    vqsub.s16       d27, d16, d17           ; hi b1
+    ; q8:  1 * sinpi : c1/temp1
+    ; q9:  3 * sinpi : d1/temp2
+    ; q10: 1 * cospi
+    ; q11: 3 * cospi
+    vqdmulh.s16     q8, q5, d0[2]           ; sinpi8sqrt2
+    vqdmulh.s16     q9, q7, d0[2]
+    vqdmulh.s16     q10, q5, d0[0]          ; cospi8sqrt2minus1
+    vqdmulh.s16     q11, q7, d0[0]
 
-    vshr.s16        q3, q3, #1              ; lo
-    vshr.s16        q4, q4, #1
-    vshr.s16        q10, q10, #1            ; hi
+    vqadd.s16       q2, q4, q6             ; a1 = 0 + 2
+    vqsub.s16       q3, q4, q6             ; b1 = 0 - 2
+
+    ; see note on shifting above
+    vshr.s16        q10, q10, #1
     vshr.s16        q11, q11, #1
 
-    vqadd.s16       q3, q3, q2              ; lo
-    vqadd.s16       q4, q4, q2
-    vqadd.s16       q10, q10, q9            ; hi
-    vqadd.s16       q11, q11, q9
+    ; q10: 1 + 1 * cospi : d1/temp1
+    ; q11: 3 + 3 * cospi : c1/temp2
+    vqadd.s16       q10, q5, q10
+    vqadd.s16       q11, q7, q11
 
-    vqsub.s16       d10, d6, d9             ; lo c1
-    vqadd.s16       d11, d7, d8             ; lo d1
-    vqsub.s16       d24, d20, d23           ; hi c1
-    vqadd.s16       d25, d21, d22           ; hi d1
+    ; q8: c1 = temp1 - temp2
+    ; q9: d1 = temp1 + temp2
+    vqsub.s16       q8, q8, q11
+    vqadd.s16       q9, q10, q9
 
-    vqadd.s16       d2, d12, d11            ; lo
-    vqadd.s16       d3, d13, d10
-    vqsub.s16       d4, d13, d10
-    vqsub.s16       d5, d12, d11
-    vqadd.s16       d16, d26, d25           ; hi
-    vqadd.s16       d17, d27, d24
-    vqsub.s16       d18, d27, d24
-    vqsub.s16       d19, d26, d25
+    ; a1+d1
+    ; b1+c1
+    ; b1-c1
+    ; a1-d1
+    vqadd.s16       q4, q2, q9
+    vqadd.s16       q5, q3, q8
+    vqsub.s16       q6, q3, q8
+    vqsub.s16       q7, q2, q9
 
-    vrshr.s16       q1, q1, #3              ; lo
-    vrshr.s16       q2, q2, #3
-    vrshr.s16       q8, q8, #3              ; hi
-    vrshr.s16       q9, q9, #3
+    ; +4 >> 3 (rounding)
+    vrshr.s16       q4, q4, #3              ; lo
+    vrshr.s16       q5, q5, #3
+    vrshr.s16       q6, q6, #3              ; hi
+    vrshr.s16       q7, q7, #3
 
-    vtrn.32         d2, d4                  ; lo
-    vtrn.32         d3, d5
-    vtrn.16         d2, d3
-    vtrn.16         d4, d5
-    vtrn.32         d16, d18                ; hi
-    vtrn.32         d17, d19
-    vtrn.16         d16, d17
-    vtrn.16         d18, d19
+    vtrn.32         q4, q6
+    vtrn.32         q5, q7
+    vtrn.16         q4, q5
+    vtrn.16         q6, q7
 
-    vaddw.u8        q1, q1, d14             ; lo
-    vaddw.u8        q2, q2, d15
-    vaddw.u8        q8, q8, d28             ; hi
-    vaddw.u8        q9, q9, d29
+    ; adding pre
+    ; input is still packed. pre was read interleaved
+    vaddw.u8        q4, q4, d28
+    vaddw.u8        q5, q5, d29
+    vaddw.u8        q6, q6, d30
+    vaddw.u8        q7, q7, d31
 
     vmov.i16        q14, #0
     vmov            q15, q14
@@ -156,19 +168,21 @@
     sub             r0, r0, #32
     vst1.16         {q14, q15}, [r0]        ; write over low input
 
-    vqmovun.s16     d0, q1                  ; lo
-    vqmovun.s16     d1, q2
-    vqmovun.s16     d2, q8                  ; hi
-    vqmovun.s16     d3, q9
+    ;saturate and narrow
+    vqmovun.s16     d0, q4                  ; lo
+    vqmovun.s16     d1, q5
+    vqmovun.s16     d2, q6                  ; hi
+    vqmovun.s16     d3, q7
 
+    ldr             r1, [sp, #4]            ; stride
     add             r2, r3, #4              ; hi
     vst1.32         {d0[0]}, [r3], r1       ; lo
-    vst1.32         {d0[1]}, [r3], r1
+    vst1.32         {d0[1]}, [r2], r1       ; hi
     vst1.32         {d1[0]}, [r3], r1
-    vst1.32         {d1[1]}, [r3]
-    vst1.32         {d2[0]}, [r2], r1       ; hi
+    vst1.32         {d1[1]}, [r2], r1
+    vst1.32         {d2[0]}, [r3], r1
     vst1.32         {d2[1]}, [r2], r1
-    vst1.32         {d3[0]}, [r2], r1
+    vst1.32         {d3[0]}, [r3]
     vst1.32         {d3[1]}, [r2]
 
     bx             lr
@@ -177,7 +191,8 @@
 
 ; Constant Pool
 _CONSTANTS_       DCD cospi8sqrt2minus1
-cospi8sqrt2minus1 DCD 0x4e7b4e7b
-sinpi8sqrt2       DCD 0x8a8c8a8c
+cospi8sqrt2minus1 DCD 0x4e7b
+; because the lowest bit in 0x8a8c is 0, we can pre-shift this
+sinpi8sqrt2       DCD 0x4546
 
     END