| ; | 
 | ; jdsamss2.asm - upsampling (SSE2) | 
 | ; | 
 | ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB | 
 | ; | 
 | ; Based on | 
 | ; x86 SIMD extension for IJG JPEG library | 
 | ; Copyright (C) 1999-2006, MIYASAKA Masaru. | 
 | ; For conditions of distribution and use, see copyright notice in jsimdext.inc | 
 | ; | 
 | ; This file should be assembled with NASM (Netwide Assembler), | 
 | ; can *not* be assembled with Microsoft's MASM or any compatible | 
 | ; assembler (including Borland's Turbo Assembler). | 
 | ; NASM is available from http://nasm.sourceforge.net/ or | 
 | ; http://sourceforge.net/project/showfiles.php?group_id=6208 | 
 | ; | 
 | ; [TAB8] | 
 |  | 
 | %include "jsimdext.inc" | 
 |  | 
 | ; -------------------------------------------------------------------------- | 
 | 	SECTION	SEG_CONST | 
 |  | 
 | 	alignz	16 | 
 | 	global	EXTN(jconst_fancy_upsample_sse2) | 
 |  | 
 | EXTN(jconst_fancy_upsample_sse2): | 
 |  | 
 | PW_ONE		times 8 dw  1 | 
 | PW_TWO		times 8 dw  2 | 
 | PW_THREE	times 8 dw  3 | 
 | PW_SEVEN	times 8 dw  7 | 
 | PW_EIGHT	times 8 dw  8 | 
 |  | 
 | 	alignz	16 | 
 |  | 
 | ; -------------------------------------------------------------------------- | 
 | 	SECTION	SEG_TEXT | 
 | 	BITS	32 | 
 | ; | 
 | ; Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. | 
 | ; | 
 | ; The upsampling algorithm is linear interpolation between pixel centers, | 
 | ; also known as a "triangle filter".  This is a good compromise between | 
 | ; speed and visual quality.  The centers of the output pixels are 1/4 and 3/4 | 
 | ; of the way between input pixel centers. | 
 | ; | 
 | ; GLOBAL(void) | 
 | ; jsimd_h2v1_fancy_upsample_sse2 (int max_v_samp_factor, | 
 | ;                                 JDIMENSION downsampled_width, | 
 | ;                                 JSAMPARRAY input_data, | 
 | ;                                 JSAMPARRAY * output_data_ptr); | 
 | ; | 
 |  | 
 | %define max_v_samp(b)		(b)+8			; int max_v_samp_factor | 
 | %define downsamp_width(b)	(b)+12	; JDIMENSION downsampled_width | 
 | %define input_data(b)		(b)+16		; JSAMPARRAY input_data | 
 | %define output_data_ptr(b)	(b)+20		; JSAMPARRAY * output_data_ptr | 
 |  | 
 | 	align	16 | 
 | 	global	EXTN(jsimd_h2v1_fancy_upsample_sse2) | 
 |  | 
 | EXTN(jsimd_h2v1_fancy_upsample_sse2): | 
 | 	push	ebp | 
 | 	mov	ebp,esp | 
 | 	pushpic	ebx | 
 | ;	push	ecx		; need not be preserved | 
 | ;	push	edx		; need not be preserved | 
 | 	push	esi | 
 | 	push	edi | 
 |  | 
 | 	get_GOT	ebx		; get GOT address | 
 |  | 
 | 	mov	eax, JDIMENSION [downsamp_width(ebp)]  ; colctr | 
 | 	test	eax,eax | 
 | 	jz	near .return | 
 |  | 
 | 	mov	ecx, INT [max_v_samp(ebp)]	; rowctr | 
 | 	test	ecx,ecx | 
 | 	jz	near .return | 
 |  | 
 | 	mov	esi, JSAMPARRAY [input_data(ebp)]	; input_data | 
 | 	mov	edi, POINTER [output_data_ptr(ebp)] | 
 | 	mov	edi, JSAMPARRAY [edi]			; output_data | 
 | 	alignx	16,7 | 
 | .rowloop: | 
 | 	push	eax			; colctr | 
 | 	push	edi | 
 | 	push	esi | 
 |  | 
 | 	mov	esi, JSAMPROW [esi]	; inptr | 
 | 	mov	edi, JSAMPROW [edi]	; outptr | 
 |  | 
 | 	test	eax, SIZEOF_XMMWORD-1 | 
 | 	jz	short .skip | 
 | 	mov	dl, JSAMPLE [esi+(eax-1)*SIZEOF_JSAMPLE] | 
 | 	mov	JSAMPLE [esi+eax*SIZEOF_JSAMPLE], dl	; insert a dummy sample | 
 | .skip: | 
 | 	pxor	xmm0,xmm0		; xmm0=(all 0's) | 
 | 	pcmpeqb	xmm7,xmm7 | 
 | 	psrldq	xmm7,(SIZEOF_XMMWORD-1) | 
 | 	pand	xmm7, XMMWORD [esi+0*SIZEOF_XMMWORD] | 
 |  | 
 | 	add	eax, byte SIZEOF_XMMWORD-1 | 
 | 	and	eax, byte -SIZEOF_XMMWORD | 
 | 	cmp	eax, byte SIZEOF_XMMWORD | 
 | 	ja	short .columnloop | 
 | 	alignx	16,7 | 
 |  | 
 | .columnloop_last: | 
 | 	pcmpeqb	xmm6,xmm6 | 
 | 	pslldq	xmm6,(SIZEOF_XMMWORD-1) | 
 | 	pand	xmm6, XMMWORD [esi+0*SIZEOF_XMMWORD] | 
 | 	jmp	short .upsample | 
 | 	alignx	16,7 | 
 |  | 
 | .columnloop: | 
 | 	movdqa	xmm6, XMMWORD [esi+1*SIZEOF_XMMWORD] | 
 | 	pslldq	xmm6,(SIZEOF_XMMWORD-1) | 
 |  | 
 | .upsample: | 
 | 	movdqa	xmm1, XMMWORD [esi+0*SIZEOF_XMMWORD] | 
 | 	movdqa	xmm2,xmm1 | 
 | 	movdqa	xmm3,xmm1		; xmm1=( 0  1  2 ... 13 14 15) | 
 | 	pslldq	xmm2,1			; xmm2=(--  0  1 ... 12 13 14) | 
 | 	psrldq	xmm3,1			; xmm3=( 1  2  3 ... 14 15 --) | 
 |  | 
 | 	por	xmm2,xmm7		; xmm2=(-1  0  1 ... 12 13 14) | 
 | 	por	xmm3,xmm6		; xmm3=( 1  2  3 ... 14 15 16) | 
 |  | 
 | 	movdqa	xmm7,xmm1 | 
 | 	psrldq	xmm7,(SIZEOF_XMMWORD-1)	; xmm7=(15 -- -- ... -- -- --) | 
 |  | 
 | 	movdqa    xmm4,xmm1 | 
 | 	punpcklbw xmm1,xmm0		; xmm1=( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm4,xmm0		; xmm4=( 8  9 10 11 12 13 14 15) | 
 | 	movdqa    xmm5,xmm2 | 
 | 	punpcklbw xmm2,xmm0		; xmm2=(-1  0  1  2  3  4  5  6) | 
 | 	punpckhbw xmm5,xmm0		; xmm5=( 7  8  9 10 11 12 13 14) | 
 | 	movdqa    xmm6,xmm3 | 
 | 	punpcklbw xmm3,xmm0		; xmm3=( 1  2  3  4  5  6  7  8) | 
 | 	punpckhbw xmm6,xmm0		; xmm6=( 9 10 11 12 13 14 15 16) | 
 |  | 
 | 	pmullw	xmm1,[GOTOFF(ebx,PW_THREE)] | 
 | 	pmullw	xmm4,[GOTOFF(ebx,PW_THREE)] | 
 | 	paddw	xmm2,[GOTOFF(ebx,PW_ONE)] | 
 | 	paddw	xmm5,[GOTOFF(ebx,PW_ONE)] | 
 | 	paddw	xmm3,[GOTOFF(ebx,PW_TWO)] | 
 | 	paddw	xmm6,[GOTOFF(ebx,PW_TWO)] | 
 |  | 
 | 	paddw	xmm2,xmm1 | 
 | 	paddw	xmm5,xmm4 | 
 | 	psrlw	xmm2,2			; xmm2=OutLE=( 0  2  4  6  8 10 12 14) | 
 | 	psrlw	xmm5,2			; xmm5=OutHE=(16 18 20 22 24 26 28 30) | 
 | 	paddw	xmm3,xmm1 | 
 | 	paddw	xmm6,xmm4 | 
 | 	psrlw	xmm3,2			; xmm3=OutLO=( 1  3  5  7  9 11 13 15) | 
 | 	psrlw	xmm6,2			; xmm6=OutHO=(17 19 21 23 25 27 29 31) | 
 |  | 
 | 	psllw	xmm3,BYTE_BIT | 
 | 	psllw	xmm6,BYTE_BIT | 
 | 	por	xmm2,xmm3		; xmm2=OutL=( 0  1  2 ... 13 14 15) | 
 | 	por	xmm5,xmm6		; xmm5=OutH=(16 17 18 ... 29 30 31) | 
 |  | 
 | 	movdqa	XMMWORD [edi+0*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [edi+1*SIZEOF_XMMWORD], xmm5 | 
 |  | 
 | 	sub	eax, byte SIZEOF_XMMWORD | 
 | 	add	esi, byte 1*SIZEOF_XMMWORD	; inptr | 
 | 	add	edi, byte 2*SIZEOF_XMMWORD	; outptr | 
 | 	cmp	eax, byte SIZEOF_XMMWORD | 
 | 	ja	near .columnloop | 
 | 	test	eax,eax | 
 | 	jnz	near .columnloop_last | 
 |  | 
 | 	pop	esi | 
 | 	pop	edi | 
 | 	pop	eax | 
 |  | 
 | 	add	esi, byte SIZEOF_JSAMPROW	; input_data | 
 | 	add	edi, byte SIZEOF_JSAMPROW	; output_data | 
 | 	dec	ecx				; rowctr | 
 | 	jg	near .rowloop | 
 |  | 
 | .return: | 
 | 	pop	edi | 
 | 	pop	esi | 
 | ;	pop	edx		; need not be preserved | 
 | ;	pop	ecx		; need not be preserved | 
 | 	poppic	ebx | 
 | 	pop	ebp | 
 | 	ret | 
 |  | 
 | ; -------------------------------------------------------------------------- | 
 | ; | 
 | ; Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. | 
 | ; Again a triangle filter; see comments for h2v1 case, above. | 
 | ; | 
 | ; GLOBAL(void) | 
 | ; jsimd_h2v2_fancy_upsample_sse2 (int max_v_samp_factor, | 
 | ;                                 JDIMENSION downsampled_width, | 
 | ;                                 JSAMPARRAY input_data, | 
 | ;                                 JSAMPARRAY * output_data_ptr); | 
 | ; | 
 |  | 
 | %define max_v_samp(b)		(b)+8			; int max_v_samp_factor | 
 | %define downsamp_width(b)	(b)+12	; JDIMENSION downsampled_width | 
 | %define input_data(b)		(b)+16		; JSAMPARRAY input_data | 
 | %define output_data_ptr(b)	(b)+20		; JSAMPARRAY * output_data_ptr | 
 |  | 
 | %define original_ebp	ebp+0 | 
 | %define wk(i)		ebp-(WK_NUM-(i))*SIZEOF_XMMWORD	; xmmword wk[WK_NUM] | 
 | %define WK_NUM		4 | 
 | %define gotptr		wk(0)-SIZEOF_POINTER	; void * gotptr | 
 |  | 
 | 	align	16 | 
 | 	global	EXTN(jsimd_h2v2_fancy_upsample_sse2) | 
 |  | 
 | EXTN(jsimd_h2v2_fancy_upsample_sse2): | 
 | 	push	ebp | 
 | 	mov	eax,esp				; eax = original ebp | 
 | 	sub	esp, byte 4 | 
 | 	and	esp, byte (-SIZEOF_XMMWORD)	; align to 128 bits | 
 | 	mov	[esp],eax | 
 | 	mov	ebp,esp				; ebp = aligned ebp | 
 | 	lea	esp, [wk(0)] | 
 | 	pushpic	eax		; make a room for GOT address | 
 | 	push	ebx | 
 | ;	push	ecx		; need not be preserved | 
 | ;	push	edx		; need not be preserved | 
 | 	push	esi | 
 | 	push	edi | 
 |  | 
 | 	get_GOT	ebx			; get GOT address | 
 | 	movpic	POINTER [gotptr], ebx	; save GOT address | 
 |  | 
 | 	mov	edx,eax				; edx = original ebp | 
 | 	mov	eax, JDIMENSION [downsamp_width(edx)]  ; colctr | 
 | 	test	eax,eax | 
 | 	jz	near .return | 
 |  | 
 | 	mov	ecx, INT [max_v_samp(edx)]	; rowctr | 
 | 	test	ecx,ecx | 
 | 	jz	near .return | 
 |  | 
 | 	mov	esi, JSAMPARRAY [input_data(edx)]	; input_data | 
 | 	mov	edi, POINTER [output_data_ptr(edx)] | 
 | 	mov	edi, JSAMPARRAY [edi]			; output_data | 
 | 	alignx	16,7 | 
 | .rowloop: | 
 | 	push	eax					; colctr | 
 | 	push	ecx | 
 | 	push	edi | 
 | 	push	esi | 
 |  | 
 | 	mov	ecx, JSAMPROW [esi-1*SIZEOF_JSAMPROW]	; inptr1(above) | 
 | 	mov	ebx, JSAMPROW [esi+0*SIZEOF_JSAMPROW]	; inptr0 | 
 | 	mov	esi, JSAMPROW [esi+1*SIZEOF_JSAMPROW]	; inptr1(below) | 
 | 	mov	edx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]	; outptr0 | 
 | 	mov	edi, JSAMPROW [edi+1*SIZEOF_JSAMPROW]	; outptr1 | 
 |  | 
 | 	test	eax, SIZEOF_XMMWORD-1 | 
 | 	jz	short .skip | 
 | 	push	edx | 
 | 	mov	dl, JSAMPLE [ecx+(eax-1)*SIZEOF_JSAMPLE] | 
 | 	mov	JSAMPLE [ecx+eax*SIZEOF_JSAMPLE], dl | 
 | 	mov	dl, JSAMPLE [ebx+(eax-1)*SIZEOF_JSAMPLE] | 
 | 	mov	JSAMPLE [ebx+eax*SIZEOF_JSAMPLE], dl | 
 | 	mov	dl, JSAMPLE [esi+(eax-1)*SIZEOF_JSAMPLE] | 
 | 	mov	JSAMPLE [esi+eax*SIZEOF_JSAMPLE], dl	; insert a dummy sample | 
 | 	pop	edx | 
 | .skip: | 
 | 	; -- process the first column block | 
 |  | 
 | 	movdqa	xmm0, XMMWORD [ebx+0*SIZEOF_XMMWORD]	; xmm0=row[ 0][0] | 
 | 	movdqa	xmm1, XMMWORD [ecx+0*SIZEOF_XMMWORD]	; xmm1=row[-1][0] | 
 | 	movdqa	xmm2, XMMWORD [esi+0*SIZEOF_XMMWORD]	; xmm2=row[+1][0] | 
 |  | 
 | 	pushpic	ebx | 
 | 	movpic	ebx, POINTER [gotptr]	; load GOT address | 
 |  | 
 | 	pxor      xmm3,xmm3		; xmm3=(all 0's) | 
 | 	movdqa    xmm4,xmm0 | 
 | 	punpcklbw xmm0,xmm3		; xmm0=row[ 0]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm4,xmm3		; xmm4=row[ 0]( 8  9 10 11 12 13 14 15) | 
 | 	movdqa    xmm5,xmm1 | 
 | 	punpcklbw xmm1,xmm3		; xmm1=row[-1]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm5,xmm3		; xmm5=row[-1]( 8  9 10 11 12 13 14 15) | 
 | 	movdqa    xmm6,xmm2 | 
 | 	punpcklbw xmm2,xmm3		; xmm2=row[+1]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm6,xmm3		; xmm6=row[+1]( 8  9 10 11 12 13 14 15) | 
 |  | 
 | 	pmullw	xmm0,[GOTOFF(ebx,PW_THREE)] | 
 | 	pmullw	xmm4,[GOTOFF(ebx,PW_THREE)] | 
 |  | 
 | 	pcmpeqb	xmm7,xmm7 | 
 | 	psrldq	xmm7,(SIZEOF_XMMWORD-2) | 
 |  | 
 | 	paddw	xmm1,xmm0		; xmm1=Int0L=( 0  1  2  3  4  5  6  7) | 
 | 	paddw	xmm5,xmm4		; xmm5=Int0H=( 8  9 10 11 12 13 14 15) | 
 | 	paddw	xmm2,xmm0		; xmm2=Int1L=( 0  1  2  3  4  5  6  7) | 
 | 	paddw	xmm6,xmm4		; xmm6=Int1H=( 8  9 10 11 12 13 14 15) | 
 |  | 
 | 	movdqa	XMMWORD [edx+0*SIZEOF_XMMWORD], xmm1	; temporarily save | 
 | 	movdqa	XMMWORD [edx+1*SIZEOF_XMMWORD], xmm5	; the intermediate data | 
 | 	movdqa	XMMWORD [edi+0*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [edi+1*SIZEOF_XMMWORD], xmm6 | 
 |  | 
 | 	pand	xmm1,xmm7		; xmm1=( 0 -- -- -- -- -- -- --) | 
 | 	pand	xmm2,xmm7		; xmm2=( 0 -- -- -- -- -- -- --) | 
 |  | 
 | 	movdqa	XMMWORD [wk(0)], xmm1 | 
 | 	movdqa	XMMWORD [wk(1)], xmm2 | 
 |  | 
 | 	poppic	ebx | 
 |  | 
 | 	add	eax, byte SIZEOF_XMMWORD-1 | 
 | 	and	eax, byte -SIZEOF_XMMWORD | 
 | 	cmp	eax, byte SIZEOF_XMMWORD | 
 | 	ja	short .columnloop | 
 | 	alignx	16,7 | 
 |  | 
 | .columnloop_last: | 
 | 	; -- process the last column block | 
 |  | 
 | 	pushpic	ebx | 
 | 	movpic	ebx, POINTER [gotptr]	; load GOT address | 
 |  | 
 | 	pcmpeqb	xmm1,xmm1 | 
 | 	pslldq	xmm1,(SIZEOF_XMMWORD-2) | 
 | 	movdqa	xmm2,xmm1 | 
 |  | 
 | 	pand	xmm1, XMMWORD [edx+1*SIZEOF_XMMWORD] | 
 | 	pand	xmm2, XMMWORD [edi+1*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa	XMMWORD [wk(2)], xmm1	; xmm1=(-- -- -- -- -- -- -- 15) | 
 | 	movdqa	XMMWORD [wk(3)], xmm2	; xmm2=(-- -- -- -- -- -- -- 15) | 
 |  | 
 | 	jmp	near .upsample | 
 | 	alignx	16,7 | 
 |  | 
 | .columnloop: | 
 | 	; -- process the next column block | 
 |  | 
 | 	movdqa	xmm0, XMMWORD [ebx+1*SIZEOF_XMMWORD]	; xmm0=row[ 0][1] | 
 | 	movdqa	xmm1, XMMWORD [ecx+1*SIZEOF_XMMWORD]	; xmm1=row[-1][1] | 
 | 	movdqa	xmm2, XMMWORD [esi+1*SIZEOF_XMMWORD]	; xmm2=row[+1][1] | 
 |  | 
 | 	pushpic	ebx | 
 | 	movpic	ebx, POINTER [gotptr]	; load GOT address | 
 |  | 
 | 	pxor      xmm3,xmm3		; xmm3=(all 0's) | 
 | 	movdqa    xmm4,xmm0 | 
 | 	punpcklbw xmm0,xmm3		; xmm0=row[ 0]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm4,xmm3		; xmm4=row[ 0]( 8  9 10 11 12 13 14 15) | 
 | 	movdqa    xmm5,xmm1 | 
 | 	punpcklbw xmm1,xmm3		; xmm1=row[-1]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm5,xmm3		; xmm5=row[-1]( 8  9 10 11 12 13 14 15) | 
 | 	movdqa    xmm6,xmm2 | 
 | 	punpcklbw xmm2,xmm3		; xmm2=row[+1]( 0  1  2  3  4  5  6  7) | 
 | 	punpckhbw xmm6,xmm3		; xmm6=row[+1]( 8  9 10 11 12 13 14 15) | 
 |  | 
 | 	pmullw	xmm0,[GOTOFF(ebx,PW_THREE)] | 
 | 	pmullw	xmm4,[GOTOFF(ebx,PW_THREE)] | 
 |  | 
 | 	paddw	xmm1,xmm0		; xmm1=Int0L=( 0  1  2  3  4  5  6  7) | 
 | 	paddw	xmm5,xmm4		; xmm5=Int0H=( 8  9 10 11 12 13 14 15) | 
 | 	paddw	xmm2,xmm0		; xmm2=Int1L=( 0  1  2  3  4  5  6  7) | 
 | 	paddw	xmm6,xmm4		; xmm6=Int1H=( 8  9 10 11 12 13 14 15) | 
 |  | 
 | 	movdqa	XMMWORD [edx+2*SIZEOF_XMMWORD], xmm1	; temporarily save | 
 | 	movdqa	XMMWORD [edx+3*SIZEOF_XMMWORD], xmm5	; the intermediate data | 
 | 	movdqa	XMMWORD [edi+2*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [edi+3*SIZEOF_XMMWORD], xmm6 | 
 |  | 
 | 	pslldq	xmm1,(SIZEOF_XMMWORD-2)	; xmm1=(-- -- -- -- -- -- --  0) | 
 | 	pslldq	xmm2,(SIZEOF_XMMWORD-2)	; xmm2=(-- -- -- -- -- -- --  0) | 
 |  | 
 | 	movdqa	XMMWORD [wk(2)], xmm1 | 
 | 	movdqa	XMMWORD [wk(3)], xmm2 | 
 |  | 
 | .upsample: | 
 | 	; -- process the upper row | 
 |  | 
 | 	movdqa	xmm7, XMMWORD [edx+0*SIZEOF_XMMWORD] | 
 | 	movdqa	xmm3, XMMWORD [edx+1*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa	xmm0,xmm7		; xmm7=Int0L=( 0  1  2  3  4  5  6  7) | 
 | 	movdqa	xmm4,xmm3		; xmm3=Int0H=( 8  9 10 11 12 13 14 15) | 
 | 	psrldq	xmm0,2			; xmm0=( 1  2  3  4  5  6  7 --) | 
 | 	pslldq	xmm4,(SIZEOF_XMMWORD-2)	; xmm4=(-- -- -- -- -- -- --  8) | 
 | 	movdqa	xmm5,xmm7 | 
 | 	movdqa	xmm6,xmm3 | 
 | 	psrldq	xmm5,(SIZEOF_XMMWORD-2)	; xmm5=( 7 -- -- -- -- -- -- --) | 
 | 	pslldq	xmm6,2			; xmm6=(--  8  9 10 11 12 13 14) | 
 |  | 
 | 	por	xmm0,xmm4		; xmm0=( 1  2  3  4  5  6  7  8) | 
 | 	por	xmm5,xmm6		; xmm5=( 7  8  9 10 11 12 13 14) | 
 |  | 
 | 	movdqa	xmm1,xmm7 | 
 | 	movdqa	xmm2,xmm3 | 
 | 	pslldq	xmm1,2			; xmm1=(--  0  1  2  3  4  5  6) | 
 | 	psrldq	xmm2,2			; xmm2=( 9 10 11 12 13 14 15 --) | 
 | 	movdqa	xmm4,xmm3 | 
 | 	psrldq	xmm4,(SIZEOF_XMMWORD-2)	; xmm4=(15 -- -- -- -- -- -- --) | 
 |  | 
 | 	por	xmm1, XMMWORD [wk(0)]	; xmm1=(-1  0  1  2  3  4  5  6) | 
 | 	por	xmm2, XMMWORD [wk(2)]	; xmm2=( 9 10 11 12 13 14 15 16) | 
 |  | 
 | 	movdqa	XMMWORD [wk(0)], xmm4 | 
 |  | 
 | 	pmullw	xmm7,[GOTOFF(ebx,PW_THREE)] | 
 | 	pmullw	xmm3,[GOTOFF(ebx,PW_THREE)] | 
 | 	paddw	xmm1,[GOTOFF(ebx,PW_EIGHT)] | 
 | 	paddw	xmm5,[GOTOFF(ebx,PW_EIGHT)] | 
 | 	paddw	xmm0,[GOTOFF(ebx,PW_SEVEN)] | 
 | 	paddw	xmm2,[GOTOFF(ebx,PW_SEVEN)] | 
 |  | 
 | 	paddw	xmm1,xmm7 | 
 | 	paddw	xmm5,xmm3 | 
 | 	psrlw	xmm1,4			; xmm1=Out0LE=( 0  2  4  6  8 10 12 14) | 
 | 	psrlw	xmm5,4			; xmm5=Out0HE=(16 18 20 22 24 26 28 30) | 
 | 	paddw	xmm0,xmm7 | 
 | 	paddw	xmm2,xmm3 | 
 | 	psrlw	xmm0,4			; xmm0=Out0LO=( 1  3  5  7  9 11 13 15) | 
 | 	psrlw	xmm2,4			; xmm2=Out0HO=(17 19 21 23 25 27 29 31) | 
 |  | 
 | 	psllw	xmm0,BYTE_BIT | 
 | 	psllw	xmm2,BYTE_BIT | 
 | 	por	xmm1,xmm0		; xmm1=Out0L=( 0  1  2 ... 13 14 15) | 
 | 	por	xmm5,xmm2		; xmm5=Out0H=(16 17 18 ... 29 30 31) | 
 |  | 
 | 	movdqa	XMMWORD [edx+0*SIZEOF_XMMWORD], xmm1 | 
 | 	movdqa	XMMWORD [edx+1*SIZEOF_XMMWORD], xmm5 | 
 |  | 
 | 	; -- process the lower row | 
 |  | 
 | 	movdqa	xmm6, XMMWORD [edi+0*SIZEOF_XMMWORD] | 
 | 	movdqa	xmm4, XMMWORD [edi+1*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa	xmm7,xmm6		; xmm6=Int1L=( 0  1  2  3  4  5  6  7) | 
 | 	movdqa	xmm3,xmm4		; xmm4=Int1H=( 8  9 10 11 12 13 14 15) | 
 | 	psrldq	xmm7,2			; xmm7=( 1  2  3  4  5  6  7 --) | 
 | 	pslldq	xmm3,(SIZEOF_XMMWORD-2)	; xmm3=(-- -- -- -- -- -- --  8) | 
 | 	movdqa	xmm0,xmm6 | 
 | 	movdqa	xmm2,xmm4 | 
 | 	psrldq	xmm0,(SIZEOF_XMMWORD-2)	; xmm0=( 7 -- -- -- -- -- -- --) | 
 | 	pslldq	xmm2,2			; xmm2=(--  8  9 10 11 12 13 14) | 
 |  | 
 | 	por	xmm7,xmm3		; xmm7=( 1  2  3  4  5  6  7  8) | 
 | 	por	xmm0,xmm2		; xmm0=( 7  8  9 10 11 12 13 14) | 
 |  | 
 | 	movdqa	xmm1,xmm6 | 
 | 	movdqa	xmm5,xmm4 | 
 | 	pslldq	xmm1,2			; xmm1=(--  0  1  2  3  4  5  6) | 
 | 	psrldq	xmm5,2			; xmm5=( 9 10 11 12 13 14 15 --) | 
 | 	movdqa	xmm3,xmm4 | 
 | 	psrldq	xmm3,(SIZEOF_XMMWORD-2)	; xmm3=(15 -- -- -- -- -- -- --) | 
 |  | 
 | 	por	xmm1, XMMWORD [wk(1)]	; xmm1=(-1  0  1  2  3  4  5  6) | 
 | 	por	xmm5, XMMWORD [wk(3)]	; xmm5=( 9 10 11 12 13 14 15 16) | 
 |  | 
 | 	movdqa	XMMWORD [wk(1)], xmm3 | 
 |  | 
 | 	pmullw	xmm6,[GOTOFF(ebx,PW_THREE)] | 
 | 	pmullw	xmm4,[GOTOFF(ebx,PW_THREE)] | 
 | 	paddw	xmm1,[GOTOFF(ebx,PW_EIGHT)] | 
 | 	paddw	xmm0,[GOTOFF(ebx,PW_EIGHT)] | 
 | 	paddw	xmm7,[GOTOFF(ebx,PW_SEVEN)] | 
 | 	paddw	xmm5,[GOTOFF(ebx,PW_SEVEN)] | 
 |  | 
 | 	paddw	xmm1,xmm6 | 
 | 	paddw	xmm0,xmm4 | 
 | 	psrlw	xmm1,4			; xmm1=Out1LE=( 0  2  4  6  8 10 12 14) | 
 | 	psrlw	xmm0,4			; xmm0=Out1HE=(16 18 20 22 24 26 28 30) | 
 | 	paddw	xmm7,xmm6 | 
 | 	paddw	xmm5,xmm4 | 
 | 	psrlw	xmm7,4			; xmm7=Out1LO=( 1  3  5  7  9 11 13 15) | 
 | 	psrlw	xmm5,4			; xmm5=Out1HO=(17 19 21 23 25 27 29 31) | 
 |  | 
 | 	psllw	xmm7,BYTE_BIT | 
 | 	psllw	xmm5,BYTE_BIT | 
 | 	por	xmm1,xmm7		; xmm1=Out1L=( 0  1  2 ... 13 14 15) | 
 | 	por	xmm0,xmm5		; xmm0=Out1H=(16 17 18 ... 29 30 31) | 
 |  | 
 | 	movdqa	XMMWORD [edi+0*SIZEOF_XMMWORD], xmm1 | 
 | 	movdqa	XMMWORD [edi+1*SIZEOF_XMMWORD], xmm0 | 
 |  | 
 | 	poppic	ebx | 
 |  | 
 | 	sub	eax, byte SIZEOF_XMMWORD | 
 | 	add	ecx, byte 1*SIZEOF_XMMWORD	; inptr1(above) | 
 | 	add	ebx, byte 1*SIZEOF_XMMWORD	; inptr0 | 
 | 	add	esi, byte 1*SIZEOF_XMMWORD	; inptr1(below) | 
 | 	add	edx, byte 2*SIZEOF_XMMWORD	; outptr0 | 
 | 	add	edi, byte 2*SIZEOF_XMMWORD	; outptr1 | 
 | 	cmp	eax, byte SIZEOF_XMMWORD | 
 | 	ja	near .columnloop | 
 | 	test	eax,eax | 
 | 	jnz	near .columnloop_last | 
 |  | 
 | 	pop	esi | 
 | 	pop	edi | 
 | 	pop	ecx | 
 | 	pop	eax | 
 |  | 
 | 	add	esi, byte 1*SIZEOF_JSAMPROW	; input_data | 
 | 	add	edi, byte 2*SIZEOF_JSAMPROW	; output_data | 
 | 	sub	ecx, byte 2			; rowctr | 
 | 	jg	near .rowloop | 
 |  | 
 | .return: | 
 | 	pop	edi | 
 | 	pop	esi | 
 | ;	pop	edx		; need not be preserved | 
 | ;	pop	ecx		; need not be preserved | 
 | 	pop	ebx | 
 | 	mov	esp,ebp		; esp <- aligned ebp | 
 | 	pop	esp		; esp <- original ebp | 
 | 	pop	ebp | 
 | 	ret | 
 |  | 
 | ; -------------------------------------------------------------------------- | 
 | ; | 
 | ; Fast processing for the common case of 2:1 horizontal and 1:1 vertical. | 
 | ; It's still a box filter. | 
 | ; | 
 | ; GLOBAL(void) | 
 | ; jsimd_h2v1_upsample_sse2 (int max_v_samp_factor, | 
 | ;                           JDIMENSION output_width, | 
 | ;                           JSAMPARRAY input_data, | 
 | ;                           JSAMPARRAY * output_data_ptr); | 
 | ; | 
 |  | 
 | %define max_v_samp(b)		(b)+8			; int max_v_samp_factor | 
 | %define output_width(b)	(b)+12		; JDIMENSION output_width | 
 | %define input_data(b)		(b)+16		; JSAMPARRAY input_data | 
 | %define output_data_ptr(b)	(b)+20		; JSAMPARRAY * output_data_ptr | 
 |  | 
 | 	align	16 | 
 | 	global	EXTN(jsimd_h2v1_upsample_sse2) | 
 |  | 
 | EXTN(jsimd_h2v1_upsample_sse2): | 
 | 	push	ebp | 
 | 	mov	ebp,esp | 
 | ;	push	ebx		; unused | 
 | ;	push	ecx		; need not be preserved | 
 | ;	push	edx		; need not be preserved | 
 | 	push	esi | 
 | 	push	edi | 
 |  | 
 | 	mov	edx, JDIMENSION [output_width(ebp)] | 
 | 	add	edx, byte (2*SIZEOF_XMMWORD)-1 | 
 | 	and	edx, byte -(2*SIZEOF_XMMWORD) | 
 | 	jz	short .return | 
 |  | 
 | 	mov	ecx, INT [max_v_samp(ebp)]	; rowctr | 
 | 	test	ecx,ecx | 
 | 	jz	short .return | 
 |  | 
 | 	mov	esi, JSAMPARRAY [input_data(ebp)]	; input_data | 
 | 	mov	edi, POINTER [output_data_ptr(ebp)] | 
 | 	mov	edi, JSAMPARRAY [edi]			; output_data | 
 | 	alignx	16,7 | 
 | .rowloop: | 
 | 	push	edi | 
 | 	push	esi | 
 |  | 
 | 	mov	esi, JSAMPROW [esi]		; inptr | 
 | 	mov	edi, JSAMPROW [edi]		; outptr | 
 | 	mov	eax,edx				; colctr | 
 | 	alignx	16,7 | 
 | .columnloop: | 
 |  | 
 | 	movdqa	xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa    xmm1,xmm0 | 
 | 	punpcklbw xmm0,xmm0 | 
 | 	punpckhbw xmm1,xmm1 | 
 |  | 
 | 	movdqa	XMMWORD [edi+0*SIZEOF_XMMWORD], xmm0 | 
 | 	movdqa	XMMWORD [edi+1*SIZEOF_XMMWORD], xmm1 | 
 |  | 
 | 	sub	eax, byte 2*SIZEOF_XMMWORD | 
 | 	jz	short .nextrow | 
 |  | 
 | 	movdqa	xmm2, XMMWORD [esi+1*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa    xmm3,xmm2 | 
 | 	punpcklbw xmm2,xmm2 | 
 | 	punpckhbw xmm3,xmm3 | 
 |  | 
 | 	movdqa	XMMWORD [edi+2*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [edi+3*SIZEOF_XMMWORD], xmm3 | 
 |  | 
 | 	sub	eax, byte 2*SIZEOF_XMMWORD | 
 | 	jz	short .nextrow | 
 |  | 
 | 	add	esi, byte 2*SIZEOF_XMMWORD	; inptr | 
 | 	add	edi, byte 4*SIZEOF_XMMWORD	; outptr | 
 | 	jmp	short .columnloop | 
 | 	alignx	16,7 | 
 |  | 
 | .nextrow: | 
 | 	pop	esi | 
 | 	pop	edi | 
 |  | 
 | 	add	esi, byte SIZEOF_JSAMPROW	; input_data | 
 | 	add	edi, byte SIZEOF_JSAMPROW	; output_data | 
 | 	dec	ecx				; rowctr | 
 | 	jg	short .rowloop | 
 |  | 
 | .return: | 
 | 	pop	edi | 
 | 	pop	esi | 
 | ;	pop	edx		; need not be preserved | 
 | ;	pop	ecx		; need not be preserved | 
 | ;	pop	ebx		; unused | 
 | 	pop	ebp | 
 | 	ret | 
 |  | 
 | ; -------------------------------------------------------------------------- | 
 | ; | 
 | ; Fast processing for the common case of 2:1 horizontal and 2:1 vertical. | 
 | ; It's still a box filter. | 
 | ; | 
 | ; GLOBAL(void) | 
 | ; jsimd_h2v2_upsample_sse2 (nt max_v_samp_factor, | 
 | ;                           JDIMENSION output_width, | 
 | ;                           JSAMPARRAY input_data, | 
 | ;                           JSAMPARRAY * output_data_ptr); | 
 | ; | 
 |  | 
 | %define max_v_samp(b)		(b)+8			; int max_v_samp_factor | 
 | %define output_width(b)	(b)+12		; JDIMENSION output_width | 
 | %define input_data(b)		(b)+16		; JSAMPARRAY input_data | 
 | %define output_data_ptr(b)	(b)+20		; JSAMPARRAY * output_data_ptr | 
 |  | 
 | 	align	16 | 
 | 	global	EXTN(jsimd_h2v2_upsample_sse2) | 
 |  | 
 | EXTN(jsimd_h2v2_upsample_sse2): | 
 | 	push	ebp | 
 | 	mov	ebp,esp | 
 | 	push	ebx | 
 | ;	push	ecx		; need not be preserved | 
 | ;	push	edx		; need not be preserved | 
 | 	push	esi | 
 | 	push	edi | 
 |  | 
 | 	mov	edx, JDIMENSION [output_width(ebp)] | 
 | 	add	edx, byte (2*SIZEOF_XMMWORD)-1 | 
 | 	and	edx, byte -(2*SIZEOF_XMMWORD) | 
 | 	jz	near .return | 
 |  | 
 | 	mov	ecx, INT [max_v_samp(ebp)]	; rowctr | 
 | 	test	ecx,ecx | 
 | 	jz	near .return | 
 |  | 
 | 	mov	esi, JSAMPARRAY [input_data(ebp)]	; input_data | 
 | 	mov	edi, POINTER [output_data_ptr(ebp)] | 
 | 	mov	edi, JSAMPARRAY [edi]			; output_data | 
 | 	alignx	16,7 | 
 | .rowloop: | 
 | 	push	edi | 
 | 	push	esi | 
 |  | 
 | 	mov	esi, JSAMPROW [esi]			; inptr | 
 | 	mov	ebx, JSAMPROW [edi+0*SIZEOF_JSAMPROW]	; outptr0 | 
 | 	mov	edi, JSAMPROW [edi+1*SIZEOF_JSAMPROW]	; outptr1 | 
 | 	mov	eax,edx					; colctr | 
 | 	alignx	16,7 | 
 | .columnloop: | 
 |  | 
 | 	movdqa	xmm0, XMMWORD [esi+0*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa    xmm1,xmm0 | 
 | 	punpcklbw xmm0,xmm0 | 
 | 	punpckhbw xmm1,xmm1 | 
 |  | 
 | 	movdqa	XMMWORD [ebx+0*SIZEOF_XMMWORD], xmm0 | 
 | 	movdqa	XMMWORD [ebx+1*SIZEOF_XMMWORD], xmm1 | 
 | 	movdqa	XMMWORD [edi+0*SIZEOF_XMMWORD], xmm0 | 
 | 	movdqa	XMMWORD [edi+1*SIZEOF_XMMWORD], xmm1 | 
 |  | 
 | 	sub	eax, byte 2*SIZEOF_XMMWORD | 
 | 	jz	short .nextrow | 
 |  | 
 | 	movdqa	xmm2, XMMWORD [esi+1*SIZEOF_XMMWORD] | 
 |  | 
 | 	movdqa    xmm3,xmm2 | 
 | 	punpcklbw xmm2,xmm2 | 
 | 	punpckhbw xmm3,xmm3 | 
 |  | 
 | 	movdqa	XMMWORD [ebx+2*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [ebx+3*SIZEOF_XMMWORD], xmm3 | 
 | 	movdqa	XMMWORD [edi+2*SIZEOF_XMMWORD], xmm2 | 
 | 	movdqa	XMMWORD [edi+3*SIZEOF_XMMWORD], xmm3 | 
 |  | 
 | 	sub	eax, byte 2*SIZEOF_XMMWORD | 
 | 	jz	short .nextrow | 
 |  | 
 | 	add	esi, byte 2*SIZEOF_XMMWORD	; inptr | 
 | 	add	ebx, byte 4*SIZEOF_XMMWORD	; outptr0 | 
 | 	add	edi, byte 4*SIZEOF_XMMWORD	; outptr1 | 
 | 	jmp	short .columnloop | 
 | 	alignx	16,7 | 
 |  | 
 | .nextrow: | 
 | 	pop	esi | 
 | 	pop	edi | 
 |  | 
 | 	add	esi, byte 1*SIZEOF_JSAMPROW	; input_data | 
 | 	add	edi, byte 2*SIZEOF_JSAMPROW	; output_data | 
 | 	sub	ecx, byte 2			; rowctr | 
 | 	jg	short .rowloop | 
 |  | 
 | .return: | 
 | 	pop	edi | 
 | 	pop	esi | 
 | ;	pop	edx		; need not be preserved | 
 | ;	pop	ecx		; need not be preserved | 
 | 	pop	ebx | 
 | 	pop	ebp | 
 | 	ret | 
 |  | 
 | ; For some reason, the OS X linker does not honor the request to align the | 
 | ; segment unless we do this. | 
 | 	align	16 |