;
;  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
;
;  Use of this source code is governed by a BSD-style license and patent
;  grant that can be found in the LICENSE file in the root of the source
;  tree. All contributing project authors may be found in the AUTHORS
;  file in the root of the source tree.
;


include vpx_ports/x86_abi_support_win32.asm


;void vp8_loop_filter_horizontal_edge_sse2
;(
;    unsigned char *src_ptr,
;    int            src_pixel_step,
;    const char    *flimit,
;    const char    *limit,
;    const char    *thresh,
;    int            count
;)
public sym(vp8_loop_filter_horizontal_edge_sse2)
sym(vp8_loop_filter_horizontal_edge_sse2):
    push        rbp
    mov         rbp, rsp
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx
    push        rsi
    push        rdi
    ; end prolog

    ALIGN_STACK 16, rax
    sub         rsp, 32                         ; reserve 32 bytes
t0 textequ <[rsp + 0]>    ;__declspec(align(16)) char t0[16];
t1 textequ <[rsp + 16]>   ;__declspec(align(16)) char t1[16];

        mov         rsi, arg(0) ;src_ptr
        movsxd      rax, dword ptr arg(1) ;src_pixel_step     ; destination pitch?

        mov         rdx,    arg(3) ;limit
        movdqa      xmm7,   XMMWORD PTR [rdx]
        mov         rdi,    rsi           ; rdi points to row +1 for indirect addressing
        add         rdi,    rax

        ; calculate breakout conditions
        movdqu      xmm2,   [rdi+2*rax]      ; q3
        movdqu      xmm1,   [rsi+2*rax]      ; q2
        movdqa      xmm6,   xmm1              ; q2
        psubusb     xmm1,   xmm2              ; q2-=q3
        psubusb     xmm2,   xmm6              ; q3-=q2
        por         xmm1,   xmm2              ; abs(q3-q2)
        psubusb     xmm1,   xmm7              ;


        movdqu      xmm4,   [rsi+rax]         ; q1
        movdqa      xmm3,   xmm4              ; q1
        psubusb     xmm4,   xmm6              ; q1-=q2
        psubusb     xmm6,   xmm3              ; q2-=q1
        por         xmm4,   xmm6              ; abs(q2-q1)

        psubusb     xmm4,   xmm7
        por         xmm1,   xmm4

        movdqu      xmm4,   [rsi]             ; q0
        movdqa      xmm0,   xmm4              ; q0
        psubusb     xmm4,   xmm3              ; q0-=q1
        psubusb     xmm3,   xmm0              ; q1-=q0
        por         xmm4,   xmm3              ; abs(q0-q1)
        movdqa        t0,       xmm4                  ; save to t0
        psubusb     xmm4,   xmm7
        por         xmm1,   xmm4

        neg         rax                   ; negate pitch to deal with above border
        movdqu      xmm2,   [rsi+4*rax]      ; p3
        movdqu      xmm4,   [rdi+4*rax]      ; p2
        movdqa      xmm5,   xmm4              ; p2
        psubusb     xmm4,   xmm2              ; p2-=p3
        psubusb     xmm2,   xmm5              ; p3-=p2
        por         xmm4,   xmm2              ; abs(p3 - p2)
        psubusb     xmm4,   xmm7
        por         xmm1,   xmm4


        movdqu      xmm4,   [rsi+2*rax]      ; p1
        movdqa      xmm3,   xmm4              ; p1
        psubusb     xmm4,   xmm5              ; p1-=p2
        psubusb     xmm5,   xmm3              ; p2-=p1
        por         xmm4,   xmm5              ; abs(p2 - p1)
        psubusb     xmm4,   xmm7
        por         xmm1,   xmm4

        movdqa      xmm2,   xmm3              ; p1

        movdqu      xmm4,   [rsi+rax]         ; p0
        movdqa      xmm5,   xmm4              ; p0
        psubusb     xmm4,   xmm3              ; p0-=p1
        psubusb     xmm3,   xmm5              ; p1-=p0
        por         xmm4,   xmm3              ; abs(p1 - p0)
        movdqa      t1,     xmm4                  ; save to t1
        psubusb     xmm4,   xmm7
        por         xmm1,    xmm4

        movdqu      xmm3,   [rdi]             ; q1
        movdqa      xmm4,   xmm3              ; q1
        psubusb     xmm3,   xmm2              ; q1-=p1
        psubusb     xmm2,   xmm4              ; p1-=q1
        por         xmm2,   xmm3              ; abs(p1-q1)
        pand        xmm2,   [tfe GLOBAL]      ; set lsb of each byte to zero
        psrlw       xmm2,   1                 ; abs(p1-q1)/2

        movdqa      xmm6,   xmm5              ; p0
        movdqu      xmm3,   [rsi]             ; q0
        psubusb     xmm5,   xmm3              ; p0-=q0
        psubusb     xmm3,   xmm6              ; q0-=p0
        por         xmm5,   xmm3              ; abs(p0 - q0)
        paddusb     xmm5,   xmm5              ; abs(p0-q0)*2
        paddusb     xmm5,   xmm2              ; abs (p0 - q0) *2 + abs(p1-q1)/2

        mov         rdx,    arg(2) ;flimit            ; get flimit
        movdqa      xmm2,   [rdx]             ;

        paddb       xmm2,   xmm2              ; flimit*2 (less than 255)
        paddb       xmm7,   xmm2              ; flimit * 2 + limit (less than 255)

        psubusb     xmm5,    xmm7             ; abs (p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit
        por         xmm1,    xmm5
        pxor        xmm5,    xmm5
        pcmpeqb     xmm1,    xmm5             ; mask mm1


        ; calculate high edge variance
        mov         rdx,    arg(4) ;thresh            ; get thresh
        movdqa      xmm7,   [rdx]             ;
        movdqa      xmm4,   t0                ; get abs (q1 - q0)
        psubusb     xmm4,   xmm7
        movdqa      xmm3,   t1                ; get abs (p1 - p0)
        psubusb     xmm3,   xmm7
        paddb       xmm4,   xmm3              ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh
        pcmpeqb     xmm4,        xmm5
        pcmpeqb     xmm5,        xmm5
        pxor        xmm4,        xmm5


        ; start work on filters
        movdqu      xmm2, [rsi+2*rax]     ; p1
        movdqu      xmm7, [rdi]           ; q1
        pxor        xmm2, [t80 GLOBAL]    ; p1 offset to convert to signed values
        pxor        xmm7, [t80 GLOBAL]    ; q1 offset to convert to signed values
        psubsb      xmm2, xmm7            ; p1 - q1
        pand        xmm2, xmm4            ; high var mask (hvm)(p1 - q1)
        pxor        xmm6, [t80 GLOBAL]    ; offset to convert to signed values
        pxor        xmm0, [t80 GLOBAL]    ; offset to convert to signed values
        movdqa      xmm3, xmm0            ; q0
        psubsb      xmm0, xmm6            ; q0 - p0
        paddsb      xmm2, xmm0            ; 1 * (q0 - p0) + hvm(p1 - q1)
        paddsb      xmm2, xmm0            ; 2 * (q0 - p0) + hvm(p1 - q1)
        paddsb      xmm2, xmm0            ; 3 * (q0 - p0) + hvm(p1 - q1)
        pand        xmm1, xmm2            ; mask filter values we don't care about
        movdqa      xmm2, xmm1
        paddsb      xmm1, [t4 GLOBAL]         ; 3* (q0 - p0) + hvm(p1 - q1) + 4
        paddsb      xmm2, [t3 GLOBAL]         ; 3* (q0 - p0) + hvm(p1 - q1) + 3

        pxor        xmm0, xmm0           ;
        pxor        xmm5, xmm5
        punpcklbw   xmm0, xmm2          ;
        punpckhbw   xmm5, xmm2          ;
        psraw       xmm0, 11                ;
        psraw       xmm5, 11
        packsswb    xmm0, xmm5
        movdqa      xmm2, xmm0          ;  (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3;

        pxor        xmm0, xmm0            ; 0
        movdqa      xmm5, xmm1            ; abcdefgh
        punpcklbw   xmm0, xmm1            ; e0f0g0h0
        psraw       xmm0, 11                  ; sign extended shift right by 3
        pxor        xmm1, xmm1            ; 0
        punpckhbw   xmm1, xmm5            ; a0b0c0d0
        psraw       xmm1, 11                  ; sign extended shift right by 3
        movdqa      xmm5, xmm0              ; save results

        packsswb    xmm0, xmm1            ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3
        paddsw      xmm5, [ones GLOBAL]
        paddsw      xmm1, [ones GLOBAL]
        psraw       xmm5, 1               ; partial shifted one more time for 2nd tap
        psraw       xmm1, 1               ; partial shifted one more time for 2nd tap
        packsswb    xmm5, xmm1            ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4
        pandn       xmm4, xmm5            ; high edge variance additive

        paddsb      xmm6, xmm2            ; p0+= p0 add
        pxor        xmm6, [t80 GLOBAL]    ; unoffset
        movdqu      [rsi+rax], xmm6       ; write back

        movdqu      xmm6, [rsi+2*rax]     ; p1
        pxor        xmm6, [t80 GLOBAL]    ; reoffset
        paddsb      xmm6, xmm4            ; p1+= p1 add
        pxor        xmm6, [t80 GLOBAL]    ; unoffset
        movdqu      [rsi+2*rax], xmm6     ; write back

        psubsb      xmm3, xmm0            ; q0-= q0 add
        pxor        xmm3, [t80 GLOBAL]    ; unoffset
        movdqu      [rsi], xmm3           ; write back

        psubsb      xmm7, xmm4            ; q1-= q1 add
        pxor        xmm7, [t80 GLOBAL]    ; unoffset
        movdqu      [rdi], xmm7           ; write back

    add rsp, 32
    pop rsp
    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret


;void vp8_loop_filter_vertical_edge_sse2
;(
;    unsigned char *src_ptr,
;    int            src_pixel_step,
;    const char    *flimit,
;    const char    *limit,
;    const char    *thresh,
;    int            count
;)
public sym(vp8_loop_filter_vertical_edge_sse2)
sym(vp8_loop_filter_vertical_edge_sse2):
    push        rbp
    mov         rbp, rsp
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx
    push        rsi
    push        rdi
    ; end prolog

    ALIGN_STACK 16, rax
    sub          rsp, 96      ; reserve 96 bytes
t0 textequ <[rsp + 0]>    ;__declspec(align(16)) char t0[16];
t1 textequ <[rsp + 16]>   ;__declspec(align(16)) char t1[16];
srct textequ <[rsp + 32]>   ;__declspec(align(16)) char srct[64];

        mov         rsi,        arg(0) ;src_ptr
        movsxd      rax,        dword ptr arg(1) ;src_pixel_step     ; destination pitch?

        lea         rsi,        [rsi + rax*4 - 4]
        mov         rdi,        rsi           ; rdi points to row +1 for indirect addressing

        add         rdi,        rax
        lea         rcx,        [rdi + rax *8]

        ;transpose
        movq        xmm7,       QWORD PTR [rsi+2*rax]                 ; 67 66 65 64 63 62 61 60
        movq        xmm6,       QWORD PTR [rdi+2*rax]                 ; 77 76 75 74 73 72 71 70

        punpcklbw   xmm7,       xmm6                        ; 77 67 76 66 75 65 74 64 73 63 72 62 71 61 70 60
        movq        xmm5,       QWORD PTR [rsi]                       ; 47 46 45 44 43 42 41 40

        movq        xmm4,       QWORD PTR [rsi+rax]                   ; 57 56 55 54 53 52 51 50
        punpcklbw   xmm5,       xmm4                        ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40

        movdqa      xmm3,       xmm5                        ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40
        punpckhwd   xmm5,       xmm7                        ; 77 67 57 47 76 66 56 46 75 65 55 45 74 64 54 44

        lea         rsi,        [rsi+ rax*8]

        punpcklwd   xmm3,       xmm7                        ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40
        movq        xmm6,       QWORD PTR [rsi + 2*rax]               ; e7 e6 e5 e4 e3 e2 e1 e0

        movq        xmm7,       QWORD PTR [rcx + 2*rax]               ; f7 f6 f5 f4 f3 f2 f1 f0
        punpcklbw   xmm6,       xmm7                        ; f7 e7 f6 e6 f5 e5 f4 e4 f3 e3 f2 e2 f1 e1 f0 e0

        movq        xmm4,       QWORD PTR [rsi]                       ; c7 c6 c5 c4 c3 c2 c1 c0
        movq        xmm7,       QWORD PTR [rsi + rax]                 ; d7 d6 d5 d4 d3 d2 d1 d0

        punpcklbw   xmm4,       xmm7                        ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 c1 d0 c0
        movdqa      xmm7,       xmm4                        ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 c1 d0 c0

        punpckhwd   xmm7,       xmm6                        ; f7 e7 d7 c7 f6 e6 d6 c6 f5 e5 d5 c5 f4 e4 d4 c4
        punpcklwd   xmm4,       xmm6                        ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0

        ; xmm3 xmm4, xmm5 xmm7   in use
        neg         rax

        lea         rsi,        [rsi+rax*8]
        movq        xmm6,       QWORD PTR [rsi+rax*2]                 ; 27 26 25 24 23 22 21 20

        movq        xmm1,       QWORD PTR [rsi+rax  ]                 ; 37 36 35 34 33 32 31 30
        punpcklbw   xmm6,       xmm1                        ; 37 27 36 26 35 25 34 24 33 23 32 22 31 21 30 20

        movq        xmm2,       QWORD PTR [rsi+rax*4]                 ; 07 06 05 04 03 02 01 00
        movq        xmm1,       QWORD PTR [rdi+rax*4]                 ; 17 16 15 14 13 12 11 10

        punpcklbw   xmm2,       xmm1                        ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00
        movdqa      xmm0,       xmm2

        punpckhwd   xmm2,       xmm6                        ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04
        punpcklwd   xmm0,       xmm6                        ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00

        movdqa      xmm6,       xmm2
        punpckldq   xmm2,       xmm5                        ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04

        punpckhdq   xmm6,       xmm5                        ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06
        ;xmm0 xmm2 xmm3 xmm4, xmm6, xmm7

        movdqa      xmm5,       xmm0                        ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
        punpckhdq   xmm5,       xmm3                        ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02

        punpckldq   xmm0,       xmm3                        ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
        lea         rsi,        [rcx+rax]
        ; xmm1, xmm3 free
        movq        xmm1,       QWORD PTR [rsi+rax*2]                 ; a7 a6 a5 a4 a3 a2 a1 a0
        movq        xmm3,       QWORD PTR [rsi+rax]                   ; b7 b6 b5 b4 b3 b2 b1 b0

        punpcklbw   xmm1,       xmm3                        ;
        lea         rdx,        srct                        ;

        movdqa      [rdx+16],   xmm1                        ; b7 a7 b6 a6 b5 a5 b4 a4 b3 a3 b2 a2 b1 a1 b0 a0
        movq        xmm3,       QWORD PTR [rsi+rax*4]                 ; 87 86 85 84 83 82 81 80

        movq        xmm1,       QWORD PTR [rcx+rax*4]
        punpcklbw   xmm3,       xmm1                        ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80

        movdqa      [rdx],      xmm3                        ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80

        punpckhwd   xmm3,       [rdx+16]                    ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84
        movdqa      xmm1,       xmm3                        ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84

        punpckhdq   xmm1,       xmm7                        ; f7 e7 d7 c7 b7 a7 97 87 f6 e6 d6 c6 b6 a6 96 86
        punpckldq   xmm3,       xmm7                        ; f5 e5 d5 c5 b5 a5 95 85 f4 e4 d4 c4 b4 a4 94 84

        movdqa      xmm7,       xmm2                        ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04
        punpcklqdq  xmm7,       xmm3                        ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04

        punpckhqdq  xmm2,       xmm3                        ; f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05
        movdqa      [rdx+32],   xmm7                        ; save 4s

        movdqa      [rdx+48],   xmm2                        ; save 5s
        movdqa      xmm7,       xmm6                        ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06

        punpckhqdq  xmm7,       xmm1                        ; f7 e7 d7 c7 b7 a7 97 87 77 67 57 47 37 27 17 07 = q3
        punpcklqdq  xmm6,       xmm1                        ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 = q2

        ; free 1, 3   xmm7-7s xmm6-6s, xmm2-5s
        movq        xmm1,       QWORD PTR [rdx]                       ; 93 83 92 82 91 81 90 80
        movq        xmm3,       QWORD PTR [rdx+16]                    ; b3 a3 b2 a2 b1 a1 b0 a0

        punpcklwd   xmm1,       xmm3                        ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80
        movdqa      xmm3,       xmm1                        ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80

        punpckhdq   xmm3,       xmm4                        ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
        punpckldq   xmm1,       xmm4                        ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80

        movdqa      xmm4,       xmm5                        ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
        punpcklqdq  xmm5,       xmm3                        ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02

        punpckhqdq  xmm4,       xmm3                        ; f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
        movdqa      [rdx],      xmm5                        ; save 2s

        movdqa      [rdx+16],   xmm4                        ; save 3s

        movdqa      xmm3,       xmm6                        ;
        psubusb     xmm3,       xmm7                        ; q3 - q2

        psubusb     xmm7,       xmm6                        ; q2 - q3
        por         xmm7,       xmm3                        ; abs(q3-q2)

        movdqa      xmm3,       xmm2                        ; q1
        psubusb     xmm3,       xmm6                        ; q1 - q2

        psubusb     xmm6,       xmm2                        ; q2 - q1
        por         xmm6,       xmm3                        ; abs(q2-q1)


        movdqa      xmm3,       xmm0                        ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
        punpcklqdq  xmm0,       xmm1                        ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00

        punpckhqdq  xmm3,       xmm1                        ; f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
        movdqa      xmm1,       xmm3

        psubusb     xmm3,       xmm0                        ; p2-p3
        psubusb     xmm0,       xmm1                        ; p3-p2

        por         xmm0,       xmm3                        ; abs(p3-p2)
        movdqa      xmm3,       xmm5                        ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02

        psubusb     xmm3,       xmm1                        ; p1-p2
        psubusb     xmm1,       xmm5                        ; p2-p1

        por         xmm1,       xmm3                        ; abs(p1-p2)
        mov         rdx,        arg(3) ;limit

        movdqa      xmm3,       [rdx]                       ; limit

        psubusb     xmm7,       xmm3
        psubusb     xmm0,       xmm3

        psubusb     xmm1,       xmm3
        psubusb     xmm6,       xmm3

        por         xmm7,       xmm6
        por         xmm0,       xmm1

        por         xmm0,       xmm7                         ;   abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit

        movdqa      xmm1,       xmm5                         ; p1

        movdqa      xmm7,       xmm4                        ; xmm4 xmm7 = p0

        psubusb     xmm7,       xmm5                        ; p0 - p1
        psubusb     xmm5,       xmm4                        ; p1 - p0

        por         xmm5,       xmm7                        ; abs(p1-p0)
        movdqa        t0,       xmm5                        ; save abs(p1-p0)

        lea         rdx,        srct
        psubusb     xmm5,       xmm3

        por         xmm0,       xmm5                        ; xmm0=mask
        movdqa      xmm5,       [rdx+32]                    ; xmm5=q0

        movdqa      xmm7,       [rdx+48]                    ; xmm7=q1
        movdqa      xmm6,       xmm5                        ; mm6=q0

        movdqa      xmm2,       xmm7                        ; q1

        psubusb     xmm5,       xmm7                        ; q0-q1
        psubusb     xmm7,       xmm6                        ; q1-q0

        por         xmm7,       xmm5                        ; abs(q1-q0)
        movdqa        t1,       xmm7                        ; save abs(q1-q0)

        psubusb     xmm7,       xmm3
        por         xmm0,       xmm7                        ; mask

        movdqa      xmm5,       xmm2                        ; q1
        psubusb     xmm5,       xmm1                        ; q1-=p1
        psubusb     xmm1,       xmm2                        ; p1-=q1
        por         xmm5,       xmm1                        ; abs(p1-q1)
        pand        xmm5,       [tfe GLOBAL]                ; set lsb of each byte to zero
        psrlw       xmm5,       1                           ; abs(p1-q1)/2

        mov         rdx,        arg(2) ;flimit                      ;
        movdqa        xmm2,       [rdx]                       ;flimit  xmm2

        movdqa      xmm1,       xmm4                        ; xmm1=xmm4=p0

        movdqa      xmm7,       xmm6                        ; xmm7=xmm6=q0
        psubusb     xmm1,       xmm7                        ; p0-q0

        psubusb     xmm7,       xmm4                        ; q0-p0
        por         xmm1,       xmm7                        ; abs(q0-p0)
        paddusb     xmm1,       xmm1                        ; abs(q0-p0)*2
        paddusb     xmm1,       xmm5                        ; abs (p0 - q0) *2 + abs(p1-q1)/2

        paddb       xmm2,       xmm2                        ; flimit*2 (less than 255)
        paddb       xmm3,       xmm2                        ; flimit * 2 + limit (less than 255)

        psubusb     xmm1,       xmm3                         ; abs (p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit

        por         xmm1,       xmm0;                       ; mask

        pxor        xmm0,       xmm0
        pcmpeqb     xmm1,       xmm0
        ; calculate high edge variance
        mov         rdx,        arg(4) ;thresh            ; get thresh
        movdqa      xmm7,       [rdx]

        ;
        movdqa      xmm4,       t0              ; get abs (q1 - q0)
        psubusb     xmm4,       xmm7

        movdqa      xmm3,       t1              ; get abs (p1 - p0)
        psubusb     xmm3,       xmm7

        por         xmm4,       xmm3            ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh
        pcmpeqb     xmm4,       xmm0

        pcmpeqb     xmm0,       xmm0
        pxor        xmm4,       xmm0

        ; start work on filters
        lea         rdx,        srct

        movdqa      xmm2,       [rdx]           ; p1
        movdqa      xmm7,       [rdx+48]        ; q1

        movdqa      xmm6,       [rdx+16]        ; p0
        movdqa      xmm0,       [rdx+32]        ; q0

        pxor        xmm2,       [t80 GLOBAL]    ; p1 offset to convert to signed values
        pxor        xmm7,       [t80 GLOBAL]    ; q1 offset to convert to signed values

        psubsb      xmm2,       xmm7            ; p1 - q1
        pand        xmm2,       xmm4            ; high var mask (hvm)(p1 - q1)

        pxor        xmm6,       [t80 GLOBAL]    ; offset to convert to signed values
        pxor        xmm0,       [t80 GLOBAL]    ; offset to convert to signed values

        movdqa      xmm3,       xmm0            ; q0
        psubsb      xmm0,       xmm6            ; q0 - p0

        paddsb      xmm2,       xmm0            ; 1 * (q0 - p0) + hvm(p1 - q1)
        paddsb      xmm2,       xmm0            ; 2 * (q0 - p0) + hvm(p1 - q1)

        paddsb      xmm2,       xmm0            ; 3 * (q0 - p0) + hvm(p1 - q1)
        pand        xmm1,       xmm2            ; mask filter values we don't care about

        movdqa      xmm2,       xmm1
        paddsb      xmm1,       [t4 GLOBAL]       ; 3* (q0 - p0) + hvm(p1 - q1) + 4

        paddsb      xmm2,       [t3 GLOBAL]       ; 3* (q0 - p0) + hvm(p1 - q1) + 3
        pxor        xmm0,       xmm0             ;

        pxor        xmm5,       xmm5
        punpcklbw   xmm0,       xmm2            ;

        punpckhbw   xmm5,       xmm2            ;
        psraw       xmm0,       11              ;

        psraw       xmm5,       11
        packsswb    xmm0,       xmm5

        movdqa      xmm2,       xmm0            ;  (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3;

        pxor        xmm0,       xmm0              ; 0
        movdqa      xmm5,       xmm1              ; abcdefgh

        punpcklbw   xmm0,       xmm1              ; e0f0g0h0
        psraw       xmm0,       11                ; sign extended shift right by 3

        pxor        xmm1,       xmm1              ; 0
        punpckhbw   xmm1,       xmm5              ; a0b0c0d0

        psraw       xmm1,       11                ; sign extended shift right by 3
        movdqa      xmm5,       xmm0              ; save results

        packsswb    xmm0,       xmm1              ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3
        paddsw      xmm5,       [ones GLOBAL]

        paddsw      xmm1,       [ones GLOBAL]
        psraw       xmm5,       1                 ; partial shifted one more time for 2nd tap

        psraw       xmm1,       1                 ; partial shifted one more time for 2nd tap
        packsswb    xmm5,       xmm1              ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4

        pandn       xmm4,       xmm5            ; high edge variance additive

        paddsb      xmm6,       xmm2            ; p0+= p0 add
        pxor        xmm6,       [t80 GLOBAL]    ; unoffset

        ; mm6=p0                               ;
        movdqa      xmm1,       [rdx]           ; p1
        pxor        xmm1,       [t80 GLOBAL]    ; reoffset

        paddsb      xmm1,       xmm4            ; p1+= p1 add
        pxor        xmm1,       [t80 GLOBAL]    ; unoffset
        ; mm6 = p0 mm1 = p1

        psubsb      xmm3,       xmm0            ; q0-= q0 add
        pxor        xmm3,       [t80 GLOBAL]    ; unoffset

        ; mm3 = q0
        psubsb      xmm7,       xmm4            ; q1-= q1 add
        pxor        xmm7,       [t80 GLOBAL]    ; unoffset
        ; mm7 = q1

        ; tranpose and write back
        ; xmm1 =    f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
        ; xmm6 =    f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
        ; xmm3 =    f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04
        ; xmm7 =    f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05
        movdqa      xmm2,       xmm1            ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
        punpcklbw   xmm2,       xmm6            ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02

        movdqa      xmm4,       xmm3            ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04
        punpckhbw   xmm1,       xmm6            ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82

        punpcklbw   xmm4,       xmm7            ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04
        punpckhbw   xmm3,       xmm7            ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84

        movdqa      xmm6,       xmm2            ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
        punpcklwd   xmm2,       xmm4            ; 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02

        punpckhwd   xmm6,       xmm4            ; 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42
        movdqa      xmm5,       xmm1            ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82

        punpcklwd   xmm1,       xmm3            ; f5 f4 f3 f2 e5 e4 e3 e2 d5 d4 d3 d2 c5 c4 c3 c2
        punpckhwd   xmm5,       xmm3            ; b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82

        ; xmm2 = 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02
        ; xmm6 = 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42
        ; xmm5 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82
        ; xmm1 = b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82
        lea         rsi,           [rsi+rax*8]

        movd        dword ptr [rsi+rax*4+2], xmm2
        psrldq      xmm2,   4

        movd        dword ptr [rdi+rax*4+2], xmm2
        psrldq      xmm2,   4

        movd        dword ptr [rsi+rax*2+2], xmm2
        psrldq      xmm2,   4

        movd        dword ptr [rdi+rax*2+2], xmm2
        movd        dword ptr [rsi+2],       xmm6

        psrldq      xmm6,   4
        movd        dword ptr [rdi+2],       xmm6

        psrldq      xmm6,   4
        neg         rax

        movd        dword ptr [rdi+rax+2],    xmm6
        psrldq      xmm6,   4

        movd        dword ptr [rdi+rax*2+2],  xmm6
        lea         rsi,       [rsi+rax*8]

        neg         rax
        ;;;;;;;;;;;;;;;;;;;;/
        movd        dword ptr [rsi+rax*4+2], xmm1
        psrldq      xmm1,   4

        movd        dword ptr [rcx+rax*4+2], xmm1
        psrldq      xmm1,   4

        movd        dword ptr [rsi+rax*2+2], xmm1
        psrldq      xmm1,   4

        movd        dword ptr [rcx+rax*2+2], xmm1
        psrldq      xmm1,   4

        movd        dword ptr [rsi+2],       xmm5
        psrldq      xmm5,   4

        movd        dword ptr [rcx+2],        xmm5
        psrldq      xmm5,   4

        neg         rax
        movd        dword ptr [rcx+rax+2],    xmm5

        psrldq      xmm5,   4
        movd        dword ptr [rcx+rax*2+2],  xmm5

    add rsp, 96
    pop rsp
    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret


;void vp8_mbloop_filter_horizontal_edge_sse2
;(
;    unsigned char *src_ptr,
;    int            src_pixel_step,
;    const char    *flimit,
;    const char    *limit,
;    const char    *thresh,
;    int            count
;)
public sym(vp8_mbloop_filter_horizontal_edge_sse2)
sym(vp8_mbloop_filter_horizontal_edge_sse2):
    push        rbp
    mov         rbp, rsp
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx
    push        rsi
    push        rdi
    ; end prolog

    ALIGN_STACK 16, rax
    sub         rsp, 32                         ; reserve 32 bytes
t0 textequ <[rsp + 0]>    ;__declspec(align(16)) char t0[8];
t1 textequ <[rsp + 16]>   ;__declspec(align(16)) char t1[8];

        mov         rsi,                    arg(0) ;src_ptr
        movsxd      rax,                    dword ptr arg(1) ;src_pixel_step     ; destination pitch?

        mov         rdx,                    arg(3) ;limit
        movdqa      xmm7,                   XMMWORD PTR [rdx]

        mov         rdi,                    rsi           ; rdi points to row +1 for indirect addressing
        add         rdi,                    rax

        ; calculate breakout conditions
        movdqa      xmm2,                   XMMWORD PTR [rdi+2*rax]      ; q3
        movdqa      xmm1,                   XMMWORD PTR [rsi+2*rax]      ; q2

        movdqa      xmm6,                   xmm1              ; q2
        psubusb     xmm1,                   xmm2              ; q2-=q3


        psubusb     xmm2,                   xmm6              ; q3-=q2
        por         xmm1,                   xmm2              ; abs(q3-q2)

        psubusb     xmm1,                   xmm7

        ; mm1 = abs(q3-q2), mm6 =q2, mm7 = limit
        movdqa      xmm4,                   XMMWORD PTR [rsi+rax]         ; q1
        movdqa      xmm3,                   xmm4              ; q1

        psubusb     xmm4,                   xmm6              ; q1-=q2
        psubusb     xmm6,                   xmm3              ; q2-=q1

        por         xmm4,                   xmm6              ; abs(q2-q1)
        psubusb     xmm4,                   xmm7

        por         xmm1,                   xmm4
        ; mm1 = mask,      mm3=q1, mm7 = limit

        movdqa      xmm4,                   XMMWORD PTR [rsi]             ; q0
        movdqa      xmm0,                   xmm4              ; q0

        psubusb     xmm4,                   xmm3              ; q0-=q1
        psubusb     xmm3,                   xmm0              ; q1-=q0

        por         xmm4,                   xmm3              ; abs(q0-q1)
        movdqa      t0,                     xmm4                  ; save to t0

        psubusb     xmm4,                   xmm7
        por         xmm1,                   xmm4

        ; mm1 = mask, mm0=q0,  mm7 = limit, t0 = abs(q0-q1)
        neg         rax                   ; negate pitch to deal with above border

        movdqa      xmm2,                   XMMWORD PTR [rsi+4*rax]      ; p3
        movdqa      xmm4,                   XMMWORD PTR [rdi+4*rax]      ; p2

        movdqa      xmm5,                   xmm4              ; p2
        psubusb     xmm4,                   xmm2              ; p2-=p3

        psubusb     xmm2,                   xmm5              ; p3-=p2
        por         xmm4,                   xmm2              ; abs(p3 - p2)

        psubusb     xmm4,                   xmm7
        por         xmm1,                   xmm4

        ; mm1 = mask, mm0=q0,  mm7 = limit, t0 = abs(q0-q1)
        movdqa      xmm4,                   XMMWORD PTR [rsi+2*rax]      ; p1
        movdqa      xmm3,                   xmm4              ; p1

        psubusb     xmm4,                   xmm5              ; p1-=p2
        psubusb     xmm5,                   xmm3              ; p2-=p1

        por         xmm4,                   xmm5              ; abs(p2 - p1)
        psubusb     xmm4,                   xmm7

        por         xmm1,                   xmm4

        movdqa      xmm2,                   xmm3              ; p1

        ; mm1 = mask, mm0=q0,  mm7 = limit, t0 = abs(q0-q1)
        movdqa      xmm4,                   XMMWORD PTR [rsi+rax]         ; p0
        movdqa      xmm5,                   xmm4              ; p0

        psubusb     xmm4,                   xmm3              ; p0-=p1
        psubusb     xmm3,                   xmm5              ; p1-=p0

        por         xmm4,                   xmm3              ; abs(p1 - p0)
        movdqa        t1,                   xmm4                  ; save to t1

        psubusb     xmm4,                   xmm7
        por         xmm1,                   xmm4

        ; mm1 = mask, mm0=q0,  mm7 = limit, t0 = abs(q0-q1) t1 = abs(p1-p0)
        ; mm5 = p0
        movdqa      xmm3,                   XMMWORD PTR [rdi] ; q1
        movdqa      xmm4,                   xmm3              ; q1
        psubusb     xmm3,                   xmm2              ; q1-=p1
        psubusb     xmm2,                   xmm4              ; p1-=q1
        por         xmm2,                   xmm3              ; abs(p1-q1)
        pand        xmm2,                   [tfe GLOBAL]      ; set lsb of each byte to zero
        psrlw       xmm2,                   1                 ; abs(p1-q1)/2

        movdqa      xmm6,                   xmm5              ; p0
        movdqa      xmm3,                   xmm0              ; q0

        psubusb     xmm5,                   xmm3              ; p0-=q0
        psubusb     xmm3,                   xmm6              ; q0-=p0

        por         xmm5,                   xmm3              ; abs(p0 - q0)
        paddusb     xmm5,                   xmm5              ; abs(p0-q0)*2
        paddusb     xmm5,                   xmm2              ; abs (p0 - q0) *2 + abs(p1-q1)/2

        mov         rdx,                    arg(2) ;flimit            ; get flimit
        movdqa      xmm2,                   XMMWORD PTR [rdx]             ;
        paddb       xmm2,                   xmm2              ; flimit*2 (less than 255)
        paddb       xmm7,                   xmm2              ; flimit * 2 + limit (less than 255)

        psubusb     xmm5,                   xmm7              ; abs (p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit
        por         xmm1,                   xmm5
        pxor        xmm5,                   xmm5
        pcmpeqb     xmm1,                   xmm5               ; mask mm1
        ; mm1 = mask, mm0=q0,  mm7 = flimit, t0 = abs(q0-q1) t1 = abs(p1-p0)
        ; mm6 = p0,

        ; calculate high edge variance
        mov         rdx,                    arg(4) ;thresh            ; get thresh
        movdqa      xmm7,                   XMMWORD PTR [rdx]             ;

        movdqa      xmm4,                   t0                ; get abs (q1 - q0)
        psubusb     xmm4,                   xmm7

        movdqa      xmm3,                   t1                ; get abs (p1 - p0)
        psubusb     xmm3,                   xmm7

        paddb       xmm4,                   xmm3              ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh
        pcmpeqb     xmm4,                   xmm5

        pcmpeqb     xmm5,                   xmm5
        pxor        xmm4,                   xmm5
        ; mm1 = mask, mm0=q0,  mm7 = thresh, t0 = abs(q0-q1) t1 = abs(p1-p0)
        ; mm6 = p0, mm4=hev
        ; start work on filters
        movdqa      xmm2,                   XMMWORD PTR [rsi+2*rax]   ; p1
        movdqa      xmm7,                   XMMWORD PTR [rdi]             ; q1

        pxor        xmm2,                   [t80 GLOBAL]  ; p1 offset to convert to signed values
        pxor        xmm7,                   [t80 GLOBAL]  ; q1 offset to convert to signed values

        psubsb      xmm2,                   xmm7              ; p1 - q1
        pxor        xmm6,                   [t80 GLOBAL]  ; offset to convert to signed values

        pxor        xmm0,                   [t80 GLOBAL]  ; offset to convert to signed values
        movdqa      xmm3,                   xmm0              ; q0

        psubsb      xmm0,                   xmm6              ; q0 - p0
        paddsb      xmm2,                   xmm0              ; 1 * (q0 - p0) + (p1 - q1)

        paddsb      xmm2,                   xmm0              ; 2 * (q0 - p0)
        paddsb      xmm2,                   xmm0              ; 3 * (q0 - p0) + (p1 - q1)

        pand        xmm1,                   xmm2              ; mask filter values we don't care about
        ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0
        movdqa      xmm2,                   xmm1              ; vp8_filter
        pand        xmm2,                   xmm4;             ; Filter2 = vp8_filter & hev


        movdqa      xmm5,                   xmm2          ;
        paddsb      xmm5,                   [t3 GLOBAL];

        pxor        xmm0,                   xmm0              ; 0
        pxor        xmm7,                   xmm7              ; 0

        punpcklbw   xmm0,                   xmm5              ; e0f0g0h0
        psraw       xmm0,                   11                ; sign extended shift right by 3

        punpckhbw   xmm7,                   xmm5              ; a0b0c0d0
        psraw       xmm7,                   11                ; sign extended shift right by 3

        packsswb    xmm0,                   xmm7              ; Filter2 >>=3;
        movdqa      xmm5,                   xmm0              ; Filter2

        paddsb      xmm2,                   [t4 GLOBAL]      ; vp8_signed_char_clamp(Filter2 + 4)
        pxor        xmm0,                   xmm0              ; 0

        pxor        xmm7,                   xmm7              ; 0
        punpcklbw   xmm0,                   xmm2              ; e0f0g0h0

        psraw       xmm0,                   11                ; sign extended shift right by 3
        punpckhbw   xmm7,                   xmm2              ; a0b0c0d0

        psraw       xmm7,                   11                ; sign extended shift right by 3
        packsswb    xmm0,                   xmm7              ; Filter2 >>=3;

        ; mm0= filter2 mm1 = vp8_filter,  mm3 =qs0 mm5=s mm4 =hev mm6=ps0
        psubsb      xmm3,                   xmm0              ; qs0 =qs0 - filter1
        paddsb      xmm6,                   xmm5              ; ps0 =ps0 + Fitler2

        ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0
        ; vp8_filter &= ~hev;
        ; Filter2 = vp8_filter;
        pandn       xmm4,                   xmm1              ; vp8_filter&=~hev


        ; mm3=qs0, mm4=filter2, mm6=ps0

        ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7);
        ; s = vp8_signed_char_clamp(qs0 - u);
        ; *oq0 = s^080h;
        ; s = vp8_signed_char_clamp(ps0 + u);
        ; *op0 = s^080h;
        pxor        xmm0,                   xmm0
        pxor        xmm1,                   xmm1

        pxor        xmm2,                   xmm2
        punpcklbw   xmm1,                   xmm4

        punpckhbw   xmm2,                   xmm4
        pmulhw      xmm1,                   [s27 GLOBAL]

        pmulhw      xmm2,                   [s27 GLOBAL]
        paddw       xmm1,                   [s63 GLOBAL]

        paddw       xmm2,                   [s63 GLOBAL]
        psraw       xmm1,                   7

        psraw       xmm2,                   7
        packsswb    xmm1,                   xmm2

        psubsb      xmm3,                   xmm1
        paddsb      xmm6,                   xmm1

        pxor        xmm3,                   [t80 GLOBAL]
        pxor        xmm6,                   [t80 GLOBAL]

        movdqa      XMMWORD PTR [rsi+rax],  xmm6
        movdqa      XMMWORD PTR [rsi],      xmm3

        ; roughly 2/7th difference across boundary
        ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7);
        ; s = vp8_signed_char_clamp(qs1 - u);
        ; *oq1 = s^080h;
        ; s = vp8_signed_char_clamp(ps1 + u);
        ; *op1 = s^080h;
        pxor        xmm1,                   xmm1
        pxor        xmm2,                   xmm2

        punpcklbw   xmm1,                   xmm4
        punpckhbw   xmm2,                   xmm4

        pmulhw      xmm1,                   [s18 GLOBAL]
        pmulhw      xmm2,                   [s18 GLOBAL]

        paddw       xmm1,                   [s63 GLOBAL]
        paddw       xmm2,                   [s63 GLOBAL]

        psraw       xmm1,                   7
        psraw       xmm2,                   7

        packsswb    xmm1,                   xmm2

        movdqa      xmm3,                   XMMWORD PTR [rdi]
        movdqa      xmm6,                   XMMWORD PTR [rsi+rax*2]       ; p1

        pxor        xmm3,                   [t80 GLOBAL]
        pxor        xmm6,                   [t80 GLOBAL]

        paddsb      xmm6,                   xmm1
        psubsb      xmm3,                   xmm1

        pxor        xmm6,                   [t80 GLOBAL]
        pxor        xmm3,                   [t80 GLOBAL]

        movdqa      XMMWORD PTR [rdi],      xmm3
        movdqa      XMMWORD PTR [rsi+rax*2],xmm6

        ; roughly 1/7th difference across boundary
        ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7);
        ; s = vp8_signed_char_clamp(qs2 - u);
        ; *oq2 = s^080h;
        ; s = vp8_signed_char_clamp(ps2 + u);
        ; *op2 = s^080h;
        pxor        xmm1,                   xmm1
        pxor        xmm2,                   xmm2

        punpcklbw   xmm1,                   xmm4
        punpckhbw   xmm2,                   xmm4

        pmulhw      xmm1,                   [s9 GLOBAL]
        pmulhw      xmm2,                   [s9 GLOBAL]

        paddw       xmm1,                   [s63 GLOBAL]
        paddw       xmm2,                   [s63 GLOBAL]

        psraw       xmm1,                   7
        psraw       xmm2,                   7

        packsswb    xmm1,                   xmm2


        movdqa      xmm6,                   XMMWORD PTR [rdi+rax*4]
        neg         rax

        movdqa      xmm3,                   XMMWORD PTR [rdi+rax  ]

        pxor        xmm6,                   [t80 GLOBAL]
        pxor        xmm3,                   [t80 GLOBAL]

        paddsb      xmm6,                   xmm1
        psubsb      xmm3,                   xmm1

        pxor        xmm6,                   [t80 GLOBAL]
        pxor        xmm3,                   [t80 GLOBAL]

        movdqa      XMMWORD PTR [rdi+rax  ], xmm3
        neg         rax

        movdqa      XMMWORD PTR [rdi+rax*4], xmm6

    add rsp, 32
    pop rsp
    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret


;void vp8_mbloop_filter_vertical_edge_sse2
;(
;    unsigned char *src_ptr,
;    int            src_pixel_step,
;    const char    *flimit,
;    const char    *limit,
;    const char    *thresh,
;    int            count
;)
public sym(vp8_mbloop_filter_vertical_edge_sse2)
sym(vp8_mbloop_filter_vertical_edge_sse2):
    push        rbp
    mov         rbp, rsp
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx
    push        rsi
    push        rdi
    ; end prolog

    ALIGN_STACK 16, rax
    sub          rsp, 160     ; reserve 160 bytes
t0 textequ <[rsp + 0]>    ;__declspec(align(16)) char t0[16];
t1 textequ <[rsp + 16]>   ;__declspec(align(16)) char t1[16];
srct textequ <[rsp + 32]>   ;__declspec(align(16)) char srct[128];


        mov         rsi,                arg(0) ;src_ptr
        movsxd      rax,                dword ptr arg(1) ;src_pixel_step                    ; destination pitch?

        lea         rsi,                [rsi + rax*4 - 4]
        lea         rdi,                [rsi + rax]                     ; rdi points to row +1 for indirect addressing

        mov         rcx,                rax
        neg         rcx

        ; Transpose
        movq        xmm0,               QWORD PTR [rdi+rax*2]           ; xx xx xx xx xx xx xx xx 77 76 75 74 73 72 71 70
        movq        xmm7,               QWORD PTR [rsi+rax*2]           ; xx xx xx xx xx xx xx xx 67 66 65 64 63 62 61 60

        punpcklbw   xmm7,               xmm0                            ; 77 67 76 66 75 65 74 64 73 63 72 62 71 61 70 60
        movq        xmm0,               QWORD PTR [rsi+rax]             ;

        movq        xmm5,               QWORD PTR [rsi]                 ;
        punpcklbw   xmm5,               xmm0                            ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40

        movdqa      xmm6,               xmm5                            ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40
        punpcklwd   xmm5,               xmm7                            ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40

        punpckhwd   xmm6,               xmm7                            ; 77 67 57 47 76 66 56 46 75 65 55 45 74 64 54 44
        movq        xmm7,               QWORD PTR [rsi + rcx]           ; xx xx xx xx xx xx xx xx 37 36 35 34 33 32 31 30

        movq        xmm0,               QWORD PTR [rsi + rcx*2]         ; xx xx xx xx xx xx xx xx 27 26 25 24 23 22 21 20
        punpcklbw   xmm0,               xmm7                            ; 37 27 36 36 35 25 34 24 33 23 32 22 31 21 30 20

        movq        xmm4,               QWORD PTR [rsi + rcx*4]         ; xx xx xx xx xx xx xx xx 07 06 05 04 03 02 01 00
        movq        xmm7,               QWORD PTR [rdi + rcx*4]         ; xx xx xx xx xx xx xx xx 17 16 15 14 13 12 11 10

        punpcklbw   xmm4,               xmm7                            ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00
        movdqa      xmm3,               xmm4                            ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00

        punpcklwd   xmm3,               xmm0                            ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
        punpckhwd   xmm4,               xmm0                            ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04

        movdqa      xmm7,               xmm4                            ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04
        movdqa      xmm2,               xmm3                            ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00

        punpckhdq   xmm7,               xmm6                            ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06
        punpckldq   xmm4,               xmm6                            ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04

        punpckhdq   xmm3,               xmm5                            ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
        punpckldq   xmm2,               xmm5                            ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00

        movdqa      t0,                 xmm2                            ; save to free XMM2
        ;movdqa        t1,                 xmm3

        ; XMM3 XMM4 XMM7 in use
        lea         rsi,                [rsi+rax*8]
        lea         rdi,                [rdi+rax*8]

        movq        xmm6,               QWORD PTR [rdi+rax*2]           ; xx xx xx xx xx xx xx xx f7 f6 f5 f4 f3 f2 f1 f0
        movq        xmm5,               QWORD PTR [rsi+rax*2]           ; xx xx xx xx xx xx xx xx e7 e6 e5 e4 e3 e2 e1 e0

        punpcklbw   xmm5,               xmm6                            ; f7 e7 f6 e6 f5 e5 f4 e4 f3 e3 f2 e2 f1 e1 f0 e0
        movq        xmm6,               QWORD PTR [rsi+rax]             ; xx xx xx xx xx xx xx xx d7 d6 d5 d4 d3 d2 d1 d0

        movq        xmm1,               QWORD PTR [rsi]                 ; xx xx xx xx xx xx xx xx c7 c6 c5 c4 c3 c2 c1 c0
        punpcklbw   xmm1,               xmm6                            ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 e1 d0 c0

        movdqa      xmm6,               xmm1                            ;
        punpckhwd   xmm6,               xmm5                            ; f7 e7 d7 c7 f6 e6 d6 c6 f5 e5 d5 c5 f4 e4 d4 c4

        punpcklwd   xmm1,               xmm5                            ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0
        movq        xmm5,               QWORD PTR [rsi+rcx]             ; xx xx xx xx xx xx xx xx b7 b6 b5 b4 b3 b2 b1 b0

        movq        xmm0,               QWORD PTR [rsi+rcx*2]           ; xx xx xx xx xx xx xx xx a7 a6 a5 a4 a3 a2 a1 a0
        punpcklbw   xmm0,               xmm5                            ; b7 a7 b6 a6 b5 a5 b4 a4 b3 a3 b2 a2 b1 a1 b0 a0

        movq        xmm2,               QWORD PTR [rsi+rcx*4]           ; xx xx xx xx xx xx xx xx 87 86 85 84 83 82 81 80
        movq        xmm5,               QWORD PTR [rdi+rcx*4]           ; xx xx xx xx xx xx xx xx 97 96 95 94 93 92 91 90

        punpcklbw   xmm2,               xmm5                            ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80
        movdqa      xmm5,               xmm2                            ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80

        punpcklwd   xmm5,               xmm0                            ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80
        punpckhwd   xmm2,               xmm0                            ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84

        movdqa      xmm0,               xmm5
        punpckldq   xmm0,               xmm1                            ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80


        punpckhdq   xmm5,               xmm1                            ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
        movdqa      xmm1,               xmm2                            ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84

        punpckldq   xmm1,               xmm6                            ; f5 e5 d5 c5 b5 a5 95 85 f4 e4 d4 c4 b4 a4 94 84
        punpckhdq   xmm2,               xmm6                            ; f7 e7 d7 c7 b7 a7 97 87 f6 e6 d6 c6 b6 a6 96 86

        movdqa      xmm6,               xmm7                            ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06
        punpcklqdq  xmm6,               xmm2                            ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06


        lea         rdx,                srct
        punpckhqdq  xmm7,               xmm2                            ; f7 e7 d7 c7 b7 a7 97 87 77 67 57 47 37 27 17 07

        movdqa      [rdx+112],          xmm7                            ; save 7
        movdqa      xmm2,               xmm3                            ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02

        movdqa      [rdx+96],           xmm6                            ; save 6
        punpcklqdq  xmm2,               xmm5                            ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02

        punpckhqdq  xmm3,               xmm5                            ; f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
        movdqa      [rdx+32],           xmm2                            ; save 2

        movdqa      xmm5,               xmm4                            ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04
        punpcklqdq  xmm4,               xmm1                            ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04

        movdqa      [rdx+48],           xmm3                            ; save 3
        punpckhqdq  xmm5,               xmm1                            ; f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05

        movdqa      [rdx+64],           xmm4                            ; save 4
        movdqa      [rdx+80],           xmm5                            ; save 5

        movdqa      xmm1,               t0                              ; get
        movdqa      xmm2,               xmm1                            ;

        punpckhqdq  xmm1,               xmm0                            ; f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
        punpcklqdq  xmm2,               xmm0                            ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00

        movdqa      [rdx+16],           xmm1
        movdqa      [rdx],              xmm2

        movdqa      xmm0,               xmm6                            ; q2
        psubusb     xmm0,               xmm7                            ; q2-q3

        psubusb     xmm7,               xmm6                            ; q3-q2
        por         xmm7,               xmm0                            ; abs (q3-q2)

        movdqa      xmm1,               xmm5                            ; q1
        psubusb     xmm1,               xmm6                            ; q1-q2

        psubusb     xmm6,               xmm5                            ; q2-q1
        por         xmm6,               xmm1                            ; abs (q2-q1)

        ;/*
        ;movdqa      xmm0,               xmm4                            ; q0
        ;psubusb     xmm0                xmm5                            ; q0-q1
        ;
        ;pusbusb     xmm5,               xmm4                            ; q1-q0
        ;por         xmm5,               xmm0                            ; abs (q1-q0)
        ;*/

        movdqa      xmm1,               [rdx+16]                        ; p2
        movdqa      xmm0,               xmm1

        psubusb     xmm0,               xmm2                            ; p2 - p3;
        psubusb     xmm2,               xmm1                            ; p3 - p2;

        por         xmm0,               xmm2                            ; abs(p2-p3)

        movdqa      xmm2,               [rdx+32]                        ; p1
        movdqa      xmm5,               xmm2                            ; p1

        psubusb     xmm5,               xmm1                            ; p1-p2
        psubusb     xmm1,               xmm2                            ; p2-p1

        por         xmm1,               xmm5                            ; abs(p2-p1)
        mov         rdx,                arg(3) ;limit

        movdqa      xmm4,               [rdx]                           ; limit
        psubusb     xmm7,               xmm4                            ;


        psubusb     xmm0,               xmm4                            ; abs(p3-p2) > limit
        psubusb     xmm1,               xmm4                            ; abs(p2-p1) > limit

        psubusb     xmm6,               xmm4                            ; abs(q2-q1) > limit
        por         xmm7,               xmm6                            ; or

        por         xmm0,               xmm1                            ;
        por         xmm0,               xmm7                            ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit

        movdqa      xmm1,               xmm2                            ; p1

        movdqa      xmm7,               xmm3                            ; p0
        psubusb     xmm7,               xmm2                            ; p0-p1

        psubusb     xmm2,               xmm3                            ; p1-p0
        por         xmm2,               xmm7                            ; abs(p1-p0)

        movdqa      t0,                 xmm2                            ; save abs(p1-p0)
        lea         rdx,                srct

        psubusb     xmm2,               xmm4                            ; abs(p1-p0)>limit
        por         xmm0,               xmm2                            ; mask

        movdqa      xmm5,               [rdx+64]                        ; q0
        movdqa      xmm7,               [rdx+80]                        ; q1

        movdqa      xmm6,               xmm5                            ; q0
        movdqa      xmm2,               xmm7                            ; q1
        psubusb     xmm5,               xmm7                            ; q0-q1

        psubusb     xmm7,               xmm6                            ; q1-q0
        por         xmm7,               xmm5                            ; abs(q1-q0)

        movdqa      t1,                 xmm7                            ; save abs(q1-q0)
        psubusb     xmm7,               xmm4                            ; abs(q1-q0)> limit

        por         xmm0,               xmm7                            ; mask

        movdqa      xmm5,                xmm2                           ; q1
        psubusb     xmm5,                xmm1                           ; q1-=p1
        psubusb     xmm1,                xmm2                           ; p1-=q1
        por         xmm5,                xmm1                           ; abs(p1-q1)
        pand        xmm5,                [tfe GLOBAL]                   ; set lsb of each byte to zero
        psrlw       xmm5,                1                              ; abs(p1-q1)/2

        mov         rdx,                arg(2) ;flimit                          ;
        movdqa      xmm2,               [rdx]                           ; flimit

        movdqa      xmm1,               xmm3                            ; p0
        movdqa      xmm7,               xmm6                            ; q0
        psubusb     xmm1,               xmm7                            ; p0-q0
        psubusb     xmm7,               xmm3                            ; q0-p0
        por         xmm1,               xmm7                            ; abs(q0-p0)
        paddusb     xmm1,               xmm1                            ; abs(q0-p0)*2
        paddusb     xmm1,               xmm5                            ; abs (p0 - q0) *2 + abs(p1-q1)/2

        paddb       xmm2,               xmm2                            ; flimit*2 (less than 255)
        paddb       xmm4,               xmm2                            ; flimit * 2 + limit (less than 255)

        psubusb     xmm1,               xmm4                            ; abs (p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit
        por         xmm1,               xmm0;                           ; mask
        pxor        xmm0,               xmm0
        pcmpeqb     xmm1,               xmm0

        ; calculate high edge variance
        mov         rdx,                arg(4) ;thresh                          ; get thresh
        movdqa      xmm7,               [rdx]

        movdqa      xmm4,               t0                              ; get abs (q1 - q0)
        psubusb     xmm4,               xmm7                            ; abs(q1 - q0) > thresh

        movdqa      xmm3,               t1                              ; get abs (p1 - p0)
        psubusb     xmm3,               xmm7                            ; abs(p1 - p0)> thresh

        por         xmm4,               xmm3                            ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh
        pcmpeqb     xmm4,               xmm0

        pcmpeqb     xmm0,               xmm0
        pxor        xmm4,               xmm0


        ; start work on filters
        lea         rdx,                srct

        ; start work on filters
        movdqa      xmm2,               [rdx+32]                        ; p1
        movdqa      xmm7,               [rdx+80]                        ; q1

        pxor        xmm2,               [t80 GLOBAL]                    ; p1 offset to convert to signed values
        pxor        xmm7,               [t80 GLOBAL]                    ; q1 offset to convert to signed values

        psubsb      xmm2,               xmm7                            ; p1 - q1
        movdqa      xmm6,               [rdx+48]                        ; p0

        movdqa      xmm0,               [rdx+64]                        ; q0
        pxor        xmm6,               [t80 GLOBAL]                    ; offset to convert to signed values

        pxor        xmm0,               [t80 GLOBAL]                    ; offset to convert to signed values
        movdqa      xmm3,               xmm0                            ; q0

        psubsb      xmm0,               xmm6                            ; q0 - p0
        paddsb      xmm2,               xmm0                            ; 1 * (q0 - p0) + (p1 - q1)

        paddsb      xmm2,               xmm0                            ; 2 * (q0 - p0)
        paddsb      xmm2,               xmm0                            ; 3 * (q0 - p0)+ (p1 - q1)

        pand        xmm1,               xmm2                            ; mask filter values we don't care about

        ; xmm1 = vp8_filter, xmm4=hev, xmm6=ps0, xmm3=qs0
        movdqa      xmm2,               xmm1                            ; vp8_filter
        pand        xmm2,               xmm4;                           ; Filter2 = vp8_filter & hev

        movdqa      xmm5,               xmm2
        paddsb      xmm5,               [t3 GLOBAL]

        pxor        xmm0,               xmm0                            ; 0
        pxor        xmm7,               xmm7                            ; 0

        punpcklbw   xmm0,               xmm5                            ; e0f0g0h0
        psraw       xmm0,               11                              ; sign extended shift right by 3

        punpckhbw   xmm7,               xmm5                            ; a0b0c0d0
        psraw       xmm7,               11                              ; sign extended shift right by 3

        packsswb    xmm0,               xmm7                            ; Filter2 >>=3;
        movdqa      xmm5,               xmm0                            ; Filter2

        paddsb      xmm2,               [t4 GLOBAL]                     ; vp8_signed_char_clamp(Filter2 + 4)
        pxor        xmm0,               xmm0                            ; 0

        pxor        xmm7,               xmm7                            ; 0
        punpcklbw   xmm0,               xmm2                            ; e0f0g0h0

        psraw       xmm0,               11                              ; sign extended shift right by 3
        punpckhbw   xmm7,               xmm2                            ; a0b0c0d0

        psraw       xmm7,               11                              ; sign extended shift right by 3
        packsswb    xmm0,               xmm7                            ; Filter2 >>=3;

        ; xmm0= filter2 xmm1 = vp8_filter,  xmm3 =qs0 xmm5=s xmm4 =hev xmm6=ps0
        psubsb      xmm3,               xmm0                            ; qs0 =qs0 - filter1
        paddsb      xmm6,               xmm5                            ; ps0 =ps0 + Fitler2


        ; xmm1=vp8_filter, xmm3=qs0, xmm4 =hev xmm6=ps0
        ; vp8_filter &= ~hev;
        ; Filter2 = vp8_filter;
        pandn       xmm4,                   xmm1                        ; vp8_filter&=~hev

        ; xmm3=qs0, xmm4=filter2, xmm6=ps0
        ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7);
        ; s = vp8_signed_char_clamp(qs0 - u);
        ; *oq0 = s^080h;
        ; s = vp8_signed_char_clamp(ps0 + u);
        ; *op0 = s^080h;
        pxor        xmm0,                   xmm0
        pxor        xmm1,                   xmm1

        pxor        xmm2,                   xmm2
        punpcklbw   xmm1,                   xmm4

        punpckhbw   xmm2,                   xmm4
        pmulhw      xmm1,                   [s27 GLOBAL]

        pmulhw      xmm2,                   [s27 GLOBAL]
        paddw       xmm1,                   [s63 GLOBAL]

        paddw       xmm2,                   [s63 GLOBAL]
        psraw       xmm1,                   7

        psraw       xmm2,                   7
        packsswb    xmm1,                   xmm2

        psubsb      xmm3,                   xmm1
        paddsb      xmm6,                   xmm1

        pxor        xmm3,                   [t80 GLOBAL]
        pxor        xmm6,                   [t80 GLOBAL]

        movdqa      [rdx+48],               xmm6
        movdqa      [rdx+64],               xmm3

        ; roughly 2/7th difference across boundary
        ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7);
        ; s = vp8_signed_char_clamp(qs1 - u);
        ; *oq1 = s^080h;
        ; s = vp8_signed_char_clamp(ps1 + u);
        ; *op1 = s^080h;
        pxor        xmm1,                       xmm1
        pxor        xmm2,                       xmm2

        punpcklbw   xmm1,                       xmm4
        punpckhbw   xmm2,                       xmm4

        pmulhw      xmm1,                       [s18 GLOBAL]
        pmulhw      xmm2,                       [s18 GLOBAL]

        paddw       xmm1,                       [s63 GLOBAL]
        paddw       xmm2,                       [s63 GLOBAL]

        psraw       xmm1,                       7
        psraw       xmm2,                       7

        packsswb    xmm1,                       xmm2

        movdqa      xmm3,                       [rdx + 80]              ;/q1
        movdqa      xmm6,                       [rdx + 32]              ; p1

        pxor        xmm3,                       [t80 GLOBAL]
        pxor        xmm6,                       [t80 GLOBAL]

        paddsb      xmm6,                       xmm1
        psubsb      xmm3,                       xmm1

        pxor        xmm6,                       [t80 GLOBAL]
        pxor        xmm3,                       [t80 GLOBAL]

        movdqa      [rdx + 80],                 xmm3
        movdqa      [rdx + 32],                 xmm6


        ; roughly 1/7th difference across boundary
        ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7);
        ; s = vp8_signed_char_clamp(qs2 - u);
        ; *oq2 = s^080h;
        ; s = vp8_signed_char_clamp(ps2 + u);
        ; *op2 = s^080h;
        pxor        xmm1,                       xmm1
        pxor        xmm2,                       xmm2

        punpcklbw   xmm1,                       xmm4
        punpckhbw   xmm2,                       xmm4

        pmulhw      xmm1,                       [s9 GLOBAL]
        pmulhw      xmm2,                       [s9 GLOBAL]

        paddw       xmm1,                       [s63 GLOBAL]
        paddw       xmm2,                       [s63 GLOBAL]

        psraw       xmm1,                       7
        psraw       xmm2,                       7

        packsswb    xmm1,                       xmm2

        movdqa      xmm6,                       [rdx+16]
        movdqa      xmm3,                       [rdx+96]

        pxor        xmm6,                       [t80 GLOBAL]
        pxor        xmm3,                       [t80 GLOBAL]

        paddsb      xmm6,                       xmm1
        psubsb      xmm3,                       xmm1

        pxor        xmm6,                       [t80 GLOBAL]        ; xmm6 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
        pxor        xmm3,                       [t80 GLOBAL]        ; xmm3 = f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 15 06


        ; transpose and write back
        movdqa      xmm0,                       [rdx]               ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
        movdqa      xmm1,                       xmm0                ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00

        punpcklbw   xmm0,                       xmm6                ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
        punpckhbw   xmm1,                       xmm6                ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80

        movdqa      xmm2,                       [rdx+32]            ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
        movdqa      xmm6,                       xmm2                ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02

        punpcklbw   xmm2,                       [rdx+48]            ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
        punpckhbw   xmm6,                       [rdx+48]            ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82

        movdqa      xmm5,                       xmm0                ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
        punpcklwd   xmm0,                       xmm2                ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00

        punpckhwd   xmm5,                       xmm2                ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40
        movdqa      xmm4,                       xmm1                ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80

        punpcklwd   xmm1,                       xmm6                ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
        punpckhwd   xmm4,                       xmm6                ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0

        movdqa      xmm2,                       [rdx+64]            ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04
        punpcklbw   xmm2,                       [rdx+80]            ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04

        movdqa      xmm6,                       xmm3                ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06
        punpcklbw   xmm6,                       [rdx+112]           ; 77 76 67 66 57 56 47 46 37 36 27 26 17 16 07 06

        movdqa      xmm7,                       xmm2                ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04
        punpcklwd   xmm2,                       xmm6                ; 37 36 35 34 27 26 25 24 17 16 15 14 07 06 05 04

        punpckhwd   xmm7,                       xmm6                ; 77 76 75 74 67 66 65 64 57 56 55 54 47 46 45 44
        movdqa      xmm6,                       xmm0                ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00

        punpckldq   xmm0,                       xmm2                ; 17 16 15 14 13 12 11 10 07 06 05 04 03 02 01 00
        punpckhdq   xmm6,                       xmm2                ; 37 36 35 34 33 32 31 30 27 26 25 24 23 22 21 20

        lea         rsi,                        [rsi+rcx*8]
        lea         rdi,                        [rdi+rcx*8]

        movq        QWORD PTR [rsi+rcx*4],      xmm0
        psrldq      xmm0,                       8

        movq        QWORD PTR [rsi+rcx*2],      xmm6
        psrldq      xmm6,                       8

        movq        QWORD PTR [rdi+rcx*4],      xmm0
        movq        QWORD PTR [rsi+rcx],        xmm6

        movdqa      xmm0,                       xmm5                ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40
        punpckldq   xmm0,                       xmm7                ; 57 56 55 54 53 52 51 50 47 46 45 44 43 42 41 40

        punpckhdq   xmm5,                       xmm7                ; 77 76 75 74 73 72 71 70 67 66 65 64 63 62 61 60

        movq        QWORD PTR [rsi],            xmm0
        psrldq      xmm0,                       8

        movq        QWORD PTR [rsi+rax*2],      xmm5
        psrldq      xmm5,                       8

        movq        QWORD PTR [rsi+rax],        xmm0
        movq        QWORD PTR [rdi+rax*2],      xmm5

        movdqa      xmm2,                       [rdx+64]            ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04
        punpckhbw   xmm2,                       [rdx+80]            ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84

        punpckhbw   xmm3,                       [rdx+112]           ; f7 f6 e7 e6 d7 d6 c7 c6 b7 b6 a7 a6 97 96 87 86
        movdqa      xmm0,                       xmm2

        punpcklwd   xmm0,                       xmm3                ; b7 b6 b4 b4 a7 a6 a5 a4 97 96 95 94 87 86 85 84
        punpckhwd   xmm2,                       xmm3                ; f7 f6 f5 f4 e7 e6 e5 e4 d7 d6 d5 d4 c7 c6 c5 c4

        movdqa      xmm3,                       xmm1                ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
        punpckldq   xmm1,                       xmm0                ; 97 96 95 94 93 92 91 90 87 86 85 83 84 82 81 80

        punpckhdq   xmm3,                       xmm0                ; b7 b6 b5 b4 b3 b2 b1 b0 a7 a6 a5 a4 a3 a2 a1 a0

        lea         rsi,                        [rsi+rax*8]
        lea         rdi,                        [rdi+rax*8]

        movq        QWORD PTR [rsi+rcx*4],      xmm1
        psrldq      xmm1,                       8

        movq        QWORD PTR [rsi+rcx*2],      xmm3
        psrldq      xmm3,                       8

        movq        QWORD PTR [rdi+rcx*4],      xmm1
        movq        QWORD PTR [rsi+rcx],        xmm3

        movdqa      xmm1,                       xmm4                ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0
        punpckldq   xmm1,                       xmm2                ; d7 d6 d5 d4 d3 d2 d1 d0 c7 c6 c5 c4 c3 c2 c1 c0

        punpckhdq   xmm4,                       xmm2                ; f7 f6 f4 f4 f3 f2 f1 f0 e7 e6 e5 e4 e3 e2 e1 e0
        movq        QWORD PTR [rsi],            xmm1

        psrldq      xmm1,                       8

        movq        QWORD PTR [rsi+rax*2],      xmm4
        psrldq      xmm4,                       8

        movq        QWORD PTR [rsi+rax],        xmm1
        movq        QWORD PTR [rdi+rax*2],      xmm4

    add rsp, 160
    pop rsp
    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret


;void vp8_loop_filter_simple_horizontal_edge_sse2
;(
;    unsigned char *src_ptr,
;    int  src_pixel_step,
;    const char *flimit,
;    const char *limit,
;    const char *thresh,
;    int count
;)
public sym(vp8_loop_filter_simple_horizontal_edge_sse2)
sym(vp8_loop_filter_simple_horizontal_edge_sse2):
    push        rbp
    mov         rbp, rsp
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx
    push        rsi
    push        rdi
    ; end prolog

        mov         rsi, arg(0)             ;src_ptr
        movsxd      rax, dword ptr arg(1)   ;src_pixel_step     ; destination pitch?
        mov         rdx, arg(2) ;flimit     ; get flimit
        movdqa      xmm3, XMMWORD PTR [rdx]
        mov         rdx, arg(3) ;limit
        movdqa      xmm7, XMMWORD PTR [rdx]

        paddb       xmm3, xmm3              ; flimit*2 (less than 255)
        paddb       xmm3, xmm7              ; flimit * 2 + limit (less than 255)

        mov         rdi, rsi                ; rdi points to row +1 for indirect addressing
        add         rdi, rax
        neg         rax

        ; calculate mask
        movdqu      xmm1, [rsi+2*rax]       ; p1
        movdqu      xmm0, [rdi]             ; q1
        movdqa      xmm2, xmm1
        movdqa      xmm7, xmm0
        movdqa      xmm4, xmm0
        psubusb     xmm0, xmm1              ; q1-=p1
        psubusb     xmm1, xmm4              ; p1-=q1
        por         xmm1, xmm0              ; abs(p1-q1)
        pand        xmm1, [tfe GLOBAL]      ; set lsb of each byte to zero
        psrlw       xmm1, 1                 ; abs(p1-q1)/2

        movdqu      xmm5, [rsi+rax]         ; p0
        movdqu      xmm4, [rsi]             ; q0
        movdqa      xmm0, xmm4              ; q0
        movdqa      xmm6, xmm5              ; p0
        psubusb     xmm5, xmm4              ; p0-=q0
        psubusb     xmm4, xmm6              ; q0-=p0
        por         xmm5, xmm4              ; abs(p0 - q0)
        paddusb     xmm5, xmm5              ; abs(p0-q0)*2
        paddusb     xmm5, xmm1              ; abs (p0 - q0) *2 + abs(p1-q1)/2

        psubusb     xmm5, xmm3              ; abs(p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit
        pxor        xmm3, xmm3
        pcmpeqb     xmm5, xmm3

        ; start work on filters
        pxor        xmm2, [t80 GLOBAL]      ; p1 offset to convert to signed values
        pxor        xmm7, [t80 GLOBAL]      ; q1 offset to convert to signed values
        psubsb      xmm2, xmm7              ; p1 - q1

        pxor        xmm6, [t80 GLOBAL]      ; offset to convert to signed values
        pxor        xmm0, [t80 GLOBAL]      ; offset to convert to signed values
        movdqa      xmm3, xmm0              ; q0
        psubsb      xmm0, xmm6              ; q0 - p0
        paddsb      xmm2, xmm0              ; p1 - q1 + 1 * (q0 - p0)
        paddsb      xmm2, xmm0              ; p1 - q1 + 2 * (q0 - p0)
        paddsb      xmm2, xmm0              ; p1 - q1 + 3 * (q0 - p0)
        pand        xmm5, xmm2              ; mask filter values we don't care about

        ; do + 4 side
        paddsb      xmm5, [t4 GLOBAL]       ; 3* (q0 - p0) + (p1 - q1) + 4

        movdqa      xmm0, xmm5              ; get a copy of filters
        psllw       xmm0, 8                 ; shift left 8
        psraw       xmm0, 3                 ; arithmetic shift right 11
        psrlw       xmm0, 8
        movdqa      xmm1, xmm5              ; get a copy of filters
        psraw       xmm1, 11                ; arithmetic shift right 11
        psllw       xmm1, 8                 ; shift left 8 to put it back

        por         xmm0, xmm1              ; put the two together to get result

        psubsb      xmm3, xmm0              ; q0-= q0 add
        pxor        xmm3, [t80 GLOBAL]      ; unoffset
        movdqu      [rsi], xmm3             ; write back

        ; now do +3 side
        psubsb      xmm5, [t1s GLOBAL]      ; +3 instead of +4

        movdqa      xmm0, xmm5              ; get a copy of filters
        psllw       xmm0, 8                 ; shift left 8
        psraw       xmm0, 3                 ; arithmetic shift right 11
        psrlw       xmm0, 8
        psraw       xmm5, 11                ; arithmetic shift right 11
        psllw       xmm5, 8                 ; shift left 8 to put it back
        por         xmm0, xmm5              ; put the two together to get result


        paddsb      xmm6, xmm0              ; p0+= p0 add
        pxor        xmm6, [t80 GLOBAL]      ; unoffset
        movdqu      [rsi+rax], xmm6         ; write back

    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret


;void vp8_loop_filter_simple_vertical_edge_sse2
;(
;    unsigned char *src_ptr,
;    int  src_pixel_step,
;    const char *flimit,
;    const char *limit,
;    const char *thresh,
;    int count
;)
public sym(vp8_loop_filter_simple_vertical_edge_sse2)
sym(vp8_loop_filter_simple_vertical_edge_sse2):
    push        rbp         ; save old base pointer value.
    mov         rbp, rsp    ; set new base pointer value.
    SHADOW_ARGS_TO_STACK 6
    GET_GOT     rbx         ; save callee-saved reg
    push        rsi
    push        rdi
    ; end prolog

    ALIGN_STACK 16, rax
    sub         rsp, 32                         ; reserve 32 bytes
t0 textequ <[rsp + 0]>    ;__declspec(align(16)) char t0[16];
t1 textequ <[rsp + 16]>   ;__declspec(align(16)) char t1[16];

        mov         rsi, arg(0) ;src_ptr
        movsxd      rax, dword ptr arg(1) ;src_pixel_step     ; destination pitch?

        lea         rsi,        [rsi - 2 ]
        lea         rdi,        [rsi + rax]
        lea         rdx,        [rsi + rax*4]
        lea         rcx,        [rdx + rax]

        movdqu      xmm0,       [rsi]                   ; (high 96 bits unused) 03 02 01 00
        movdqu      xmm1,       [rdx]                   ; (high 96 bits unused) 43 42 41 40
        movdqu      xmm2,       [rdi]                   ; 13 12 11 10
        movdqu      xmm3,       [rcx]                   ; 53 52 51 50
        punpckldq   xmm0,       xmm1                    ; (high 64 bits unused) 43 42 41 40 03 02 01 00
        punpckldq   xmm2,       xmm3                    ; 53 52 51 50 13 12 11 10

        movdqu      xmm4,       [rsi + rax*2]           ; 23 22 21 20
        movdqu      xmm5,       [rdx + rax*2]           ; 63 62 61 60
        movdqu      xmm6,       [rdi + rax*2]           ; 33 32 31 30
        movdqu      xmm7,       [rcx + rax*2]           ; 73 72 71 70
        punpckldq   xmm4,       xmm5                    ; 63 62 61 60 23 22 21 20
        punpckldq   xmm6,       xmm7                    ; 73 72 71 70 33 32 31 30

        punpcklbw   xmm0,       xmm2                    ; 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00
        punpcklbw   xmm4,       xmm6                    ; 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20

        movdqa      xmm1,       xmm0
        punpcklwd   xmm0,       xmm4                    ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
        punpckhwd   xmm1,       xmm4                    ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40

        movdqa      xmm2,       xmm0
        punpckldq   xmm0,       xmm1                    ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
        punpckhdq   xmm2,       xmm1                    ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02

        movdqa      t0,         xmm0                    ; save to t0
        movdqa      t1,         xmm2                    ; save to t1

        lea         rsi,        [rsi + rax*8]
        lea         rdi,        [rsi + rax]
        lea         rdx,        [rsi + rax*4]
        lea         rcx,        [rdx + rax]

        movdqu      xmm4,       [rsi]                   ; 83 82 81 80
        movdqu      xmm1,       [rdx]                   ; c3 c2 c1 c0
        movdqu      xmm6,       [rdi]                   ; 93 92 91 90
        movdqu      xmm3,       [rcx]                   ; d3 d2 d1 d0
        punpckldq   xmm4,       xmm1                    ; c3 c2 c1 c0 83 82 81 80
        punpckldq   xmm6,       xmm3                    ; d3 d2 d1 d0 93 92 91 90

        movdqu      xmm0,       [rsi + rax*2]           ; a3 a2 a1 a0
        movdqu      xmm5,       [rdx + rax*2]           ; e3 e2 e1 e0
        movdqu      xmm2,       [rdi + rax*2]           ; b3 b2 b1 b0
        movdqu      xmm7,       [rcx + rax*2]           ; f3 f2 f1 f0
        punpckldq   xmm0,       xmm5                    ; e3 e2 e1 e0 a3 a2 a1 a0
        punpckldq   xmm2,       xmm7                    ; f3 f2 f1 f0 b3 b2 b1 b0

        punpcklbw   xmm4,       xmm6                    ; d3 c3 d2 c2 d1 c1 d0 c0 93 83 92 82 91 81 90 80
        punpcklbw   xmm0,       xmm2                    ; f3 e3 f2 e2 f1 e1 f0 e0 b3 a3 b2 a2 b1 a1 b0 a0

        movdqa      xmm1,       xmm4
        punpcklwd   xmm4,       xmm0                    ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80
        punpckhwd   xmm1,       xmm0                    ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0

        movdqa      xmm6,       xmm4
        punpckldq   xmm4,       xmm1                    ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80
        punpckhdq   xmm6,       xmm1                    ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82

        movdqa      xmm0,       t0                      ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
        movdqa      xmm2,       t1                      ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
        movdqa      xmm1,       xmm0
        movdqa      xmm3,       xmm2

        punpcklqdq  xmm0,       xmm4                    ; p1  f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
        punpckhqdq  xmm1,       xmm4                    ; p0  f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
        punpcklqdq  xmm2,       xmm6                    ; q0  f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
        punpckhqdq  xmm3,       xmm6                    ; q1  f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03

        ; calculate mask
        movdqa      xmm6,       xmm0                            ; p1
        movdqa      xmm7,       xmm3                            ; q1
        psubusb     xmm7,       xmm0                            ; q1-=p1
        psubusb     xmm6,       xmm3                            ; p1-=q1
        por         xmm6,       xmm7                            ; abs(p1-q1)
        pand        xmm6,       [tfe GLOBAL]                    ; set lsb of each byte to zero
        psrlw       xmm6,       1                               ; abs(p1-q1)/2

        movdqa      xmm5,       xmm1                            ; p0
        movdqa      xmm4,       xmm2                            ; q0
        psubusb     xmm5,       xmm2                            ; p0-=q0
        psubusb     xmm4,       xmm1                            ; q0-=p0
        por         xmm5,       xmm4                            ; abs(p0 - q0)
        paddusb     xmm5,       xmm5                            ; abs(p0-q0)*2
        paddusb     xmm5,       xmm6                            ; abs (p0 - q0) *2 + abs(p1-q1)/2

        mov         rdx,        arg(2)                          ;flimit
        movdqa      xmm7, XMMWORD PTR [rdx]
        mov         rdx,        arg(3)                          ; get limit
        movdqa      xmm6, XMMWORD PTR [rdx]
        paddb       xmm7,        xmm7                           ; flimit*2 (less than 255)
        paddb       xmm7,        xmm6                           ; flimit * 2 + limit (less than 255)

        psubusb     xmm5,        xmm7                           ; abs(p0 - q0) *2 + abs(p1-q1)/2  > flimit * 2 + limit
        pxor        xmm7,        xmm7
        pcmpeqb     xmm5,        xmm7                           ; mm5 = mask

        ; start work on filters
        movdqa        t0,        xmm0
        movdqa        t1,        xmm3

        pxor        xmm0,        [t80 GLOBAL]                   ; p1 offset to convert to signed values
        pxor        xmm3,        [t80 GLOBAL]                   ; q1 offset to convert to signed values

        psubsb      xmm0,        xmm3                           ; p1 - q1
        movdqa      xmm6,        xmm1                           ; p0

        movdqa      xmm7,        xmm2                           ; q0
        pxor        xmm6,        [t80 GLOBAL]                   ; offset to convert to signed values

        pxor        xmm7,        [t80 GLOBAL]                   ; offset to convert to signed values
        movdqa      xmm3,        xmm7                           ; offseted ; q0

        psubsb      xmm7,        xmm6                           ; q0 - p0
        paddsb      xmm0,        xmm7                           ; p1 - q1 + 1 * (q0 - p0)

        paddsb      xmm0,        xmm7                           ; p1 - q1 + 2 * (q0 - p0)
        paddsb      xmm0,        xmm7                           ; p1 - q1 + 3 * (q0 - p0)

        pand        xmm5,        xmm0                           ; mask filter values we don't care about


        paddsb      xmm5,        [t4 GLOBAL]                    ;  3* (q0 - p0) + (p1 - q1) + 4

        movdqa      xmm0,        xmm5                           ; get a copy of filters
        psllw       xmm0,        8                              ; shift left 8

        psraw       xmm0,        3                              ; arithmetic shift right 11
        psrlw       xmm0,        8

        movdqa      xmm7,        xmm5                           ; get a copy of filters
        psraw       xmm7,        11                             ; arithmetic shift right 11

        psllw       xmm7,        8                              ; shift left 8 to put it back
        por         xmm0,        xmm7                           ; put the two together to get result

        psubsb      xmm3,        xmm0                           ; q0-= q0sz add
        pxor        xmm3,        [t80 GLOBAL]                   ; unoffset   q0

        ; now do +3 side
        psubsb      xmm5,        [t1s GLOBAL]                   ; +3 instead of +4
        movdqa      xmm0,        xmm5                           ; get a copy of filters

        psllw       xmm0,        8                              ; shift left 8
        psraw       xmm0,        3                              ; arithmetic shift right 11

        psrlw       xmm0,        8
        psraw       xmm5,        11                             ; arithmetic shift right 11

        psllw       xmm5,        8                              ; shift left 8 to put it back
        por         xmm0,        xmm5                           ; put the two together to get result

        paddsb      xmm6,        xmm0                           ; p0+= p0 add
        pxor        xmm6,        [t80 GLOBAL]                   ; unoffset   p0

        movdqa      xmm0,        t0                             ; p1
        movdqa      xmm4,        t1                             ; q1

        ; transpose back to write out
        ; p1  f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
        ; p0  f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
        ; q0  f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
        ; q1  f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
        movdqa      xmm1,       xmm0
        punpcklbw   xmm0,       xmm6                               ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
        punpckhbw   xmm1,       xmm6                               ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80

        movdqa      xmm5,       xmm3
        punpcklbw   xmm3,       xmm4                               ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
        punpckhbw   xmm5,       xmm4                               ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82

        movdqa      xmm2,       xmm0
        punpcklwd   xmm0,       xmm3                               ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00
        punpckhwd   xmm2,       xmm3                               ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40

        movdqa      xmm3,       xmm1
        punpcklwd   xmm1,       xmm5                               ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
        punpckhwd   xmm3,       xmm5                               ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0

        ; write out order: xmm0 xmm2 xmm1 xmm3
        lea         rdx,        [rsi + rax*4]

        movd        dword ptr [rsi],      xmm1                               ; write the second 8-line result
        psrldq      xmm1,       4
        movd        dword ptr [rdi],      xmm1
        psrldq      xmm1,       4
        movd        dword ptr [rsi + rax*2], xmm1
        psrldq      xmm1,       4
        movd        dword ptr [rdi + rax*2], xmm1

        movd        dword ptr [rdx],      xmm3
        psrldq      xmm3,       4
        movd        dword ptr [rcx],      xmm3
        psrldq      xmm3,       4
        movd        dword ptr [rdx + rax*2], xmm3
        psrldq      xmm3,       4
        movd        dword ptr [rcx + rax*2], xmm3

        neg         rax
        lea         rsi,        [rsi + rax*8]
        neg         rax
        lea         rdi,        [rsi + rax]
        lea         rdx,        [rsi + rax*4]
        lea         rcx,        [rdx + rax]

        movd        dword ptr [rsi],      xmm0                                ; write the first 8-line result
        psrldq      xmm0,       4
        movd        dword ptr [rdi],      xmm0
        psrldq      xmm0,       4
        movd        dword ptr [rsi + rax*2], xmm0
        psrldq      xmm0,       4
        movd        dword ptr [rdi + rax*2], xmm0

        movd        dword ptr [rdx],      xmm2
        psrldq      xmm2,       4
        movd        dword ptr [rcx],      xmm2
        psrldq      xmm2,       4
        movd        dword ptr [rdx + rax*2], xmm2
        psrldq      xmm2,       4
        movd        dword ptr [rcx + rax*2], xmm2

    add rsp, 32
    pop rsp
    ; begin epilog
    pop rdi
    pop rsi
    RESTORE_GOT
    UNSHADOW_ARGS
    pop         rbp
    ret

SECTION_RODATA
align 16

tfe equ this xmmword
 db 16 dup (0feh)
align 16

t80 equ this xmmword
 db 16 dup (080h)
align 16

t1s equ this xmmword
 db 16 dup (001h)
align 16

t3 equ this xmmword
 db 16 dup (003h)
align 16

t4 equ this xmmword
 db 16 dup (004h)
align 16

ones dw 8 dup (00001h)
align 16

s27 dw 8 dup (01b00h)
align 16

s18 dw 8 dup (01200h)
align 16

s9 dw 8 dup (00900h)
align 16

s63 dw 8 dup (0003fh)
end
