shithub: openh264

ref: b7a25df13f2641504d8a77e3ab0110ee25d75920
dir: /codec/common/deblocking_neon.S/

View raw version
/*!
 * \copy
 *     Copyright (c)  2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in
 *          the documentation and/or other materials provided with the
 *          distribution.
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *     POSSIBILITY OF SUCH DAMAGE.
 *
 */
 
#ifdef HAVE_NEON
.text

#include "arm_arch_common_macro.S"

#ifdef APPLE_IOS
.macro	JMP_IF_128BITS_IS_ZERO
//	{
		vorr.s16	$2, $0, $1
		vmov		r3, r2, $2
		orr			r3, r3, r2
		cmp			r3, #0
//	}
.endm

//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
.macro	MASK_MATRIX
//	{	input: p1, p0, q0, q1, alpha(be modified), beta; output: mask
		vabd.u8	$6, $1, $2		// abs( p0 - q0 )
		vcgt.u8	$6, $4, $6		//	mask = abs( p0 - q0 ) < alpha
	
		vabd.u8	$4, $0, $1		// abs( p1 - p0 )
		vclt.u8	$4, $4, $5		//	abs( p1 - p0 ) < beta
		vand.u8	$6, $6, $4		//	2nd mask &		
	
		vabd.u8	$4, $3, $2		// abs( q1 - q0 )		
		vclt.u8	$4, $4, $5		//	abs( q1 - q0 ) < beta
		vand.u8	$6, $6, $4		//	3rd mask &
//	}
.endm

//if( abs( p2 - p0 ) < beta )
//{
//	pix[-2*xstride] = p1 + x264_clip3( (( p2 + ((p0 + q0 + 1)>> 1)) >> 1) - p1, -tc0[i], tc0[i] );
//	tc++;
//}
.macro	DIFF_LUMA_LT4_P1_Q1
//	{	input: p2, p1, p0, q0, beta, -tc0[i], tc0[i], mask_matrx; output: _clip3(p1'), tc++;
		vabd.u8	$9, $0, $2				//	abs( p2 - p0 )
		vclt.u8	$9, $9, $4				//	abs( p2 - p0 ) < beta
		vrhadd.u8	$8, $2, $3				//	((p0 + q0 + 1)>> 1)	
		vhadd.u8	$8, $0, $8				//	(( p2 + ((p0 + q0 + 1)>> 1)) >> 1)
		vsub.s8	$8, $8, $1				//	(( p2 + ((p0 + q0 + 1)>> 1)) >> 1) - p1
		vmax.s8	$8, $8, $5				// >= -tc0[i]
		vmin.s8	$8, $8, $6				// <= tc0[i]
		vand.s8	$8, $8, $9				// mask, only [abs( p2 - p0 ) < beta] avail _clip3
		vand.s8	$8, $8, $7
		vadd.u8	$8, $1, $8
		vabs.s8	$9, $9					// if( abs( p2 - p0 ) < beta ) tc++;
//	}
.endm

//delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3,-tc, tc );
.macro	DIFF_LUMA_LT4_P0_Q0
//	{	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
		vsubl.u8	$5, $0, $3			// (p1 - q1)
		vsubl.u8	$6, $2, $1			// (q0 - p0)
		vshl.s16	$6, $6, #2
		vadd.s16	$5, $5, $6			// (p1 - q1) += ( q0 - p0 )	<<2
		vrshrn.s16		$4, $5, #3
//	}
.endm

//if( abs( p2 - p0 ) < beta ) /* p0', p1', p2' */
//{
//		const int p3 = pix[-4*xstride];
//		pix[-1*xstride] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3;
//		pix[-2*xstride] = ( p2 + p1 + p0 + q0 + 2 ) >> 2;
//		pix[-3*xstride] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3;
//}
//else /* p0' */
//		pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
.macro	DIFF_LUMA_EQ4_P2P1P0
//	{	input: p3(output p1'), p2, p1, p0, q0, q1, select_matrix(output p0'), output p2'; 
//		workin q4~q5; after filtered then p3/p2 useless!
		vaddl.u8	q4, $1, $2			// (p2 + p1)
		vaddl.u8	q5, $3, $4			// (p0 + q0)		
		vadd.u16	q5, q4, q5			// p1'=(p2 + p1)+(p0 + q0)
		
		vaddl.u8	q4, $0, $1			// (p3 + p2)		
		vshl.u16	q4, q4, #1
		vadd.u16	q4, q5, q4			// p2'=2*(p3 + p2)+(p2 + p1)+(p0 + q0)
		
		vrshrn.u16		$0, q5, #2		//	p1', prev p3 useless now
		vrshrn.u16		$7, q4, #3		//	p2'
						
		vshl.u16	q5, q5, #1			//	((p2 + p1)+(p0 + q0))*2
		vsubl.u8	q4, $5, $1			// (q1 - p2)			
		vadd.u16	q5, q4,q5			// 5tags p0'=(q1 - p2)+((p2 + p1)+(p0 + q0))*2
		
		vaddl.u8	q4, $2, $5			// (p1 + q1)		
		vaddw.u8	q4, q4, $2
		vaddw.u8	q4, q4, $3			// 3tags p0'=2*p1+(p0 + q1)
		
		vrshrn.u16		d10,q5, #3		//	5tags
		vrshrn.u16		d8, q4, #2		//	3tags
		vbsl.u8		$6, d10, d8		//	p0'			
//	}
.endm

.macro	DIFF_LUMA_EQ4_MASK
//	{	input: px', px, mask_matrix; working q4
		vmov	$3, $2
		vbsl.u8	$3, $0, $1
//	}
.endm

//	( (p1 << 1) + p0 + q1 + 2 ) >> 2
.macro	DIFF_CHROMA_EQ4_P0Q0	
//	{	input: p1, p0, q0, q1; working q4/q5/q6; output: p0'_d, q0'_d
		vaddl.u8	$4, $0, $3			// (p1 + q1)		
		vaddw.u8	$5, $4, $1
		vaddw.u8	$6, $4, $2		
		vaddw.u8	$5, $5, $0			// p0'=(p1 + q1)+(p0+p1)
//		vaddw.u8	$6, $4, $2
		vaddw.u8	$6, $6, $3			// q0'=(p1 + q1)+(q0+q1)		
		vrshrn.u16		$7, $5, #2		
		vrshrn.u16		$8, $6, #2
//	}
.endm

.macro	LORD_CHROMA_DATA_4
//	{	input: 4xCb_addr, 4xCr_addr, working r0~r2	
		vld4.u8	{$0[$8],$1[$8],$2[$8],$3[$8]}, [r0], r2	// Cb
		vld4.u8	{$4[$8],$5[$8],$6[$8],$7[$8]}, [r1], r2	// Cr
//	}
.endm

.macro	STORE_CHROMA_DATA_4
//	{	input: 4xCb_addr, 4xCr_addr, working r0~r2	
		vst4.u8	{$0[$8],$1[$8],$2[$8],$3[$8]}, [r0], r2	// Cb
		vst4.u8	{$4[$8],$5[$8],$6[$8],$7[$8]}, [r1], r2	// Cr
//	}
.endm

.macro	LORD_LUMA_DATA_3
//	{	input: 3xluma_addr, working r0~r2	
		vld3.u8	{$0[$6],$1[$6],$2[$6]}, [r2], r1	//	0::pix[-3];1::pix[-2];2::pix[-1];
		vld3.u8	{$3[$6],$4[$6],$5[$6]}, [r0], r1	//	3::pix[0]; 4::pix[1]; 5::pix[2];
//	}
.endm

.macro	STORE_LUMA_DATA_4
//	{	input: 4xluma, working r0~r2	
		vst4.u8	{$0[$4],$1[$4],$2[$4],$3[$4]}, [r0], r1	//	0::pix[-2];1::pix[-1];2::pix[0]; 3::pix[1]
		vst4.u8	{$0[$5],$1[$5],$2[$5],$3[$5]}, [r2], r1
//	}
.endm

.macro	LORD_LUMA_DATA_4
//	{	input: 4xluma_addr, working r0r1r3	
		vld4.u8	{$0[$8],$1[$8],$2[$8],$3[$8]}, [r3], r1	//	0::pix[-4];1::pix[-3];2::pix[-2];3::pix[-1]
		vld4.u8	{$4[$8],$5[$8],$6[$8],$7[$8]}, [r0], r1	//	4::pix[0]; 5::pix[1]; 6::pix[2]; 7::pix[3];
//	}
.endm

.macro	STORE_LUMA_DATA_3
//	{	input: 3xluma_addr, working r0~r2	
		vst3.u8	{$0[$6],$1[$6],$2[$6]}, [r3], r1	//	0::pix[-3];1::pix[-2];2::pix[-1];
		vst3.u8	{$3[$6],$4[$6],$5[$6]}, [r0], r1	//	3::pix[0]; 4::pix[1]; 5::pix[2];
//	}
.endm

.macro	EXTRACT_DELTA_INTO_TWO_PART
//	{	input: delta (output abs minus part), working (output plus part)	
		vcge.s8	$1, $0, #0
		vand	$1, $0, $1				// select original (+part)
		vsub.s8	$0, $1, $0				// select original -(-part)
//	}
.endm
#else
.macro	JMP_IF_128BITS_IS_ZERO arg0, arg1, arg2
//	{
		vorr.s16	\arg2, \arg0, \arg1
		vmov		r3, r2, \arg2
		orr			r3, r3, r2
		cmp			r3, #0
//	}
.endm

//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
.macro	MASK_MATRIX arg0, arg1, arg2, arg3, arg4, arg5, arg6
//	{	input: p1, p0, q0, q1, alpha(be modified), beta; output: mask
		vabd.u8	\arg6, \arg1, \arg2		// abs( p0 - q0 )
		vcgt.u8	\arg6, \arg4, \arg6		//	mask = abs( p0 - q0 ) < alpha
	
		vabd.u8	\arg4, \arg0, \arg1		// abs( p1 - p0 )
		vclt.u8	\arg4, \arg4, \arg5		//	abs( p1 - p0 ) < beta
		vand.u8	\arg6, \arg6, \arg4		//	2nd mask &		
	
		vabd.u8	\arg4, \arg3, \arg2		// abs( q1 - q0 )		
		vclt.u8	\arg4, \arg4, \arg5		//	abs( q1 - q0 ) < beta
		vand.u8	\arg6, \arg6, \arg4		//	3rd mask &
//	}
.endm

//if( abs( p2 - p0 ) < beta )
//{
//	pix[-2*xstride] = p1 + x264_clip3( (( p2 + ((p0 + q0 + 1)>> 1)) >> 1) - p1, -tc0[i], tc0[i] );
//	tc++;
//}
.macro	DIFF_LUMA_LT4_P1_Q1 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
//	{	input: p2, p1, p0, q0, beta, -tc0[i], tc0[i], mask_matrx; output: _clip3(p1'), tc++;
		vabd.u8	\arg9, \arg0, \arg2				//	abs( p2 - p0 )
		vclt.u8	\arg9, \arg9, \arg4				//	abs( p2 - p0 ) < beta
		vrhadd.u8	\arg8, \arg2, \arg3				//	((p0 + q0 + 1)>> 1)	
		vhadd.u8	\arg8, \arg0, \arg8				//	(( p2 + ((p0 + q0 + 1)>> 1)) >> 1)
		vsub.s8	\arg8, \arg8, \arg1				//	(( p2 + ((p0 + q0 + 1)>> 1)) >> 1) - p1
		vmax.s8	\arg8, \arg8, \arg5				// >= -tc0[i]
		vmin.s8	\arg8, \arg8, \arg6				// <= tc0[i]
		vand.s8	\arg8, \arg8, \arg9				// mask, only [abs( p2 - p0 ) < beta] avail _clip3
		vand.s8	\arg8, \arg8, \arg7
		vadd.u8	\arg8, \arg1, \arg8
		vabs.s8	\arg9, \arg9					// if( abs( p2 - p0 ) < beta ) tc++;
//	}
.endm

//delta = x264_clip3( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3,-tc, tc );
.macro	DIFF_LUMA_LT4_P0_Q0 arg0, arg1, arg2, arg3, arg4, arg5, arg6
//	{	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
		vsubl.u8	\arg5, \arg0, \arg3			// (p1 - q1)
		vsubl.u8	\arg6, \arg2, \arg1			// (q0 - p0)
		vshl.s16	\arg6, \arg6, #2
		vadd.s16	\arg5, \arg5, \arg6			// (p1 - q1) += ( q0 - p0 )	<<2
		vrshrn.s16		\arg4, \arg5, #3
//	}
.endm

//if( abs( p2 - p0 ) < beta ) /* p0', p1', p2' */
//{
//		const int p3 = pix[-4*xstride];
//		pix[-1*xstride] = ( p2 + 2*p1 + 2*p0 + 2*q0 + q1 + 4 ) >> 3;
//		pix[-2*xstride] = ( p2 + p1 + p0 + q0 + 2 ) >> 2;
//		pix[-3*xstride] = ( 2*p3 + 3*p2 + p1 + p0 + q0 + 4 ) >> 3;
//}
//else /* p0' */
//		pix[-1*xstride] = ( 2*p1 + p0 + q1 + 2 ) >> 2;
.macro	DIFF_LUMA_EQ4_P2P1P0 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 
//	{	input: p3(output p1'), p2, p1, p0, q0, q1, select_matrix(output p0'), output p2'; 
//		workin q4~q5; after filtered then p3/p2 useless!
		vaddl.u8	q4, \arg1, \arg2			// (p2 + p1)
		vaddl.u8	q5, \arg3, \arg4			// (p0 + q0)		
		vadd.u16	q5, q4, q5			// p1'=(p2 + p1)+(p0 + q0)
		
		vaddl.u8	q4, \arg0, \arg1			// (p3 + p2)		
		vshl.u16	q4, q4, #1
		vadd.u16	q4, q5, q4			// p2'=2*(p3 + p2)+(p2 + p1)+(p0 + q0)
		
		vrshrn.u16		\arg0, q5, #2		//	p1', prev p3 useless now
		vrshrn.u16		\arg7, q4, #3		//	p2'
						
		vshl.u16	q5, q5, #1			//	((p2 + p1)+(p0 + q0))*2
		vsubl.u8	q4, \arg5, \arg1			// (q1 - p2)			
		vadd.u16	q5, q4,q5			// 5tags p0'=(q1 - p2)+((p2 + p1)+(p0 + q0))*2
		
		vaddl.u8	q4, \arg2, \arg5			// (p1 + q1)		
		vaddw.u8	q4, q4, \arg2
		vaddw.u8	q4, q4, \arg3			// 3tags p0'=2*p1+(p0 + q1)
		
		vrshrn.u16		d10,q5, #3		//	5tags
		vrshrn.u16		d8, q4, #2		//	3tags
		vbsl.u8		\arg6, d10, d8		//	p0'			
//	}
.endm

.macro	DIFF_LUMA_EQ4_MASK arg0, arg1, arg2, arg3
//	{	input: px', px, mask_matrix; working q4
		vmov	\arg3, \arg2
		vbsl.u8	\arg3, \arg0, \arg1
//	}
.endm

//	( (p1 << 1) + p0 + q1 + 2 ) >> 2
.macro	DIFF_CHROMA_EQ4_P0Q0 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8	
//	{	input: p1, p0, q0, q1; working q4/q5/q6; output: p0'_d, q0'_d
		vaddl.u8	\arg4, \arg0, \arg3			// (p1 + q1)		
		vaddw.u8	\arg5, \arg4, \arg1
		vaddw.u8	\arg6, \arg4, \arg2		
		vaddw.u8	\arg5, \arg5, \arg0			// p0'=(p1 + q1)+(p0+p1)
//		vaddw.u8	\arg6, \arg4, \arg2
		vaddw.u8	\arg6, \arg6, \arg3			// q0'=(p1 + q1)+(q0+q1)		
		vrshrn.u16		\arg7, \arg5, #2		
		vrshrn.u16		\arg8, \arg6, #2
//	}
.endm		

.macro	LORD_CHROMA_DATA_4 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8	
//	{	input: 4xCb_addr, 4xCr_addr, working r0~r2	
		vld4.u8	{\arg0[\arg8],\arg1[\arg8],\arg2[\arg8],\arg3[\arg8]}, [r0], r2	// Cb
		vld4.u8	{\arg4[\arg8],\arg5[\arg8],\arg6[\arg8],\arg7[\arg8]}, [r1], r2	// Cr
//	}
.endm	

.macro	STORE_CHROMA_DATA_4 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
//	{	input: 4xCb_addr, 4xCr_addr, working r0~r2	
		vst4.u8	{\arg0[\arg8],\arg1[\arg8],\arg2[\arg8],\arg3[\arg8]}, [r0], r2	// Cb
		vst4.u8	{\arg4[\arg8],\arg5[\arg8],\arg6[\arg8],\arg7[\arg8]}, [r1], r2	// Cr
//	}
.endm

.macro	LORD_LUMA_DATA_3 arg0, arg1, arg2, arg3, arg4, arg5, arg6
//	{	input: 3xluma_addr, working r0~r2	
		vld3.u8	{\arg0[\arg6],\arg1[\arg6],\arg2[\arg6]}, [r2], r1	//	0::pix[-3];1::pix[-2];2::pix[-1];
		vld3.u8	{\arg3[\arg6],\arg4[\arg6],\arg5[\arg6]}, [r0], r1	//	3::pix[0]; 4::pix[1]; 5::pix[2];
//	}
.endm

.macro	STORE_LUMA_DATA_4 arg0, arg1, arg2, arg3, arg4, arg5
//	{	input: 4xluma, working r0~r2	
		vst4.u8	{\arg0[\arg4],\arg1[\arg4],\arg2[\arg4],\arg3[\arg4]}, [r0], r1	//	0::pix[-2];1::pix[-1];2::pix[0]; 3::pix[1]
		vst4.u8	{\arg0[\arg5],\arg1[\arg5],\arg2[\arg5],\arg3[\arg5]}, [r2], r1
//	}
.endm

.macro	LORD_LUMA_DATA_4 arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
//	{	input: 4xluma_addr, working r0r1r3	
		vld4.u8	{\arg0[\arg8],\arg1[\arg8],\arg2[\arg8],\arg3[\arg8]}, [r3], r1	//	0::pix[-4];1::pix[-3];2::pix[-2];3::pix[-1]
		vld4.u8	{\arg4[\arg8],\arg5[\arg8],\arg6[\arg8],\arg7[\arg8]}, [r0], r1	//	4::pix[0]; 5::pix[1]; 6::pix[2]; 7::pix[3];
//	}
.endm

.macro	STORE_LUMA_DATA_3 arg0, arg1, arg2, arg3, arg4, arg5, arg6
//	{	input: 3xluma_addr, working r0~r2	
		vst3.u8	{\arg0[\arg6],\arg1[\arg6],\arg2[\arg6]}, [r3], r1	//	0::pix[-3];1::pix[-2];2::pix[-1];
		vst3.u8	{\arg3[\arg6],\arg4[\arg6],\arg5[\arg6]}, [r0], r1	//	3::pix[0]; 4::pix[1]; 5::pix[2];
//	}
.endm

.macro	EXTRACT_DELTA_INTO_TWO_PART arg0, arg1
//	{	input: delta (output abs minus part), working (output plus part)	
		vcge.s8	\arg1, \arg0, #0
		vand	\arg1, \arg0, \arg1				// select original (+part)
		vsub.s8	\arg0, \arg1, \arg0				// select original -(-part)
//	}
.endm

#endif
//uint8_t *pix, int32_t stride, int32_t alpha, int32_t beta, uint8_t *tc
  WELS_ASM_FUNC_BEGIN DeblockLumaLt4V_neon

	vdup.u8	q11, r2				// alpha [0~255]
	vdup.u8	q9, r3					// q9:: beta [0~18]
		
	add			r2, r1, r1, lsl #1
	sub			r2, r0, r2				//	pix -= 3*src_stride]	
	vld1.u8	{q0}, [r2], r1		//	q0::p2 = pix[-3*xstride];
	vld1.u8	{q3}, [r0], r1		//	q3::q0 = pix[ 0*xstride];
	vld1.u8	{q1}, [r2], r1		//	q1::p1 = pix[-2*xstride];
	vld1.u8	{q4}, [r0], r1		//	q4::q1 = pix[ 1*xstride];
	vld1.u8	{q2}, [r2]				//	q2::p0 = pix[-1*xstride];
	vld1.u8	{q5}, [r0]				//	q5::q2 = pix[ 2*xstride];
	sub			r2, r2, r1				//	r2 = pix-2*xstride

//	if( tc0[i] < 0 )	 continue; else filter					
	ldr			r3, [sp, #0]
	vld1.s8	{d31}, [r3]			//	load 4 tc0[i]
	vdup.s8	d28, d31[0]    
	vdup.s8	d30, d31[1]
	vdup.s8	d29, d31[2] 
	vdup.s8	d31, d31[3]
	vtrn.32	d28, d30
	vtrn.32	d29, d31				//	q14::each 32 bits is 4x tc0[i]
	vcge.s8	q10, q14, #0			//	q10::tc0[i] >= 0

//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	MASK_MATRIX	q1, q2, q3, q4, q11, q9, q15	// q15::mask matrix
	vand.u8	q10, q10, q15			//	two mask
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		lt4_end

	veor		q15, q15
	vsub.i8	q15,q15,q14			// q15::4x -tc0[i], min	

//	input: p2, p1, p0, q0, beta, -tc0[i], tc0[i]; mask_matrx, output: _clip3(p1'), tc++;	
	DIFF_LUMA_LT4_P1_Q1	q0, q1, q2, q3, q9, q15, q14, q10, q6, q12	//	q6 = _clip3(p1')
	vst1.u8	{q6}, [r2], r1
	
	DIFF_LUMA_LT4_P1_Q1	q5, q4, q3, q2, q9, q15, q14, q10, q7, q13	//	q7 = _clip3(q1')
		
	vabs.s8	q12, q12
	vabs.s8	q13, q13					// if( abs( p2 - p0 ) < beta ) tc++;					
	vadd.u8	q14,q14,q12
	vadd.u8	q14,q14,q13			// updated  tc
	veor		q15, q15
	vsub.i8	q15,q15,q14			// updated -tc
	
//	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
	DIFF_LUMA_LT4_P0_Q0	d2, d4, d6, d8, d16, q12, q13
	DIFF_LUMA_LT4_P0_Q0	d3, d5, d7, d9, d17, q12, q13	//q8::delta		
	vmax.s8	q8, q8, q15			// >= -tc0[i]
	vmin.s8	q8, q8, q14			// <= tc0[i]
	vand.s8	q8, q8, q10
	EXTRACT_DELTA_INTO_TWO_PART	q8, q9
	vqadd.u8	q2, q2, q9		// clip_uint8( p0 + [+delta] ); p0'
	vqsub.u8	q2, q2, q8		// clip_uint8( p0 - [-delta] ); p0'
	vst1.u8	{q2}, [r2], r1
	vqsub.u8	q3, q3, q9		// clip_uint8( q0 - [+delta] ); q0'	
	vqadd.u8	q3, q3, q8		// clip_uint8( q0 + [-delta] ); q0'
	vst1.u8	{q3}, [r2]	, r1
	vst1.u8	{q7}, [r2]

//lt4_end:
  WELS_ASM_FUNC_END
	
//uint8_t *pix, int32_t stride, int32_t alpha, int32_t beta
  WELS_ASM_FUNC_BEGIN DeblockLumaEq4V_neon

	vdup.u8	q5, r2				// alpha [0~255]
	vdup.u8	q4, r3				// beta [0~18]
	
	sub			r3, r0, r1, lsl #2	//	pix -= 4*src_stride
	vld1.u8	{q8},  [r3], r1		//	q8::p3 = pix[-4*xstride];
	vld1.u8	{q12}, [r0], r1		//	q12::q0 = pix[ 0*xstride];	
	vld1.u8	{q9},  [r3], r1		//	q9::p2 = pix[-3*xstride];
	vld1.u8	{q13}, [r0], r1		//	q13::q1 = pix[ 1*xstride];
	vld1.u8	{q10}, [r3], r1		//	q10::p1 = pix[-2*xstride];
	vld1.u8	{q14}, [r0], r1		//	q14::q2 = pix[ 2*xstride];
	vld1.u8	{q11}, [r3]			//	q11::p0 = pix[-1*xstride];
	vld1.u8	{q15}, [r0]			//	q15::q3 = pix[ 3*xstride];
	sub			r3, r3, r1	, lsl #1	//	r3 = pix-3*xstride
		
//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )		
	MASK_MATRIX	q10, q11, q12, q13, q5, q4, q6	// q6::mask matrix
//	JMP_IF_128BITS_IS_ZERO	d12, d13, d0
//	beq		eq4_end

//	if(abs( p0 - q0 ) < ((alpha >> 2) + 2) )
	mov			r2, r2, lsr #2
	add			r2, r2, #2
	vdup.u8	q5, r2
	vabd.u8	q0, q11, q12	
	vclt.u8	q7, q0, q5				// q7::indicate
//	if( abs( p2 - p0 ) < beta )
	vabd.u8	q1, q9, q11	
	vclt.u8	q1, q1, q4
	vand.s8	q1, q1, q7				//	q1::indicate [p0', p1', p2'] or [p0']
//	if( abs( q2 - q0 ) < beta )
	vabd.u8	q2, q14,q12	
	vclt.u8	q2, q2, q4
	vand.s8	q2, q2, q7				//	q2::indicate [q0', q1', q2'] or [q0']
	vand.u8	q7, q7, q6
	
	vmov		q3, q1
//	input: p3(output p1'), p2, p1, p0, q0, q1, select_matrix(output p0'), output p2'; 
//	workin q4~q5; after filtered then p3/p2 useless!
	DIFF_LUMA_EQ4_P2P1P0		d16, d18, d20, d22, d24, d26, d2, d0
	DIFF_LUMA_EQ4_P2P1P0		d17, d19, d21, d23, d25, d27, d3, d1
	
//	q1(p0') q2(q0') only need ::if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
//	q0(p2') q8(p1') q15(q1') q3(q2'); need more &&if(abs( p0 - q0 ) < ((alpha >> 2) + 2) )&&if( abs( p2 - p0 ) < beta )
	vand.u8	q3, q7, q3
	DIFF_LUMA_EQ4_MASK	q0, q9, q3, q4
	vst1.u8	{q4}, [r3], r1
	DIFF_LUMA_EQ4_MASK	q8,q10, q3, q4
	vst1.u8	{q4}, [r3], r1
	DIFF_LUMA_EQ4_MASK	q1,q11, q6, q4
	vst1.u8	{q4}, [r3], r1
	
	vmov		q0, q2			
	DIFF_LUMA_EQ4_P2P1P0		d30, d28, d26, d24, d22, d20, d4, d6
	DIFF_LUMA_EQ4_P2P1P0		d31, d29, d27, d25, d23, d21, d5, d7

	vand.u8	q0, q7, q0
	DIFF_LUMA_EQ4_MASK	q2,  q12, q6, q4
	vst1.u8	{q4}, [r3], r1	
	DIFF_LUMA_EQ4_MASK	q15, q13, q0, q4
	vst1.u8	{q4}, [r3], r1
	DIFF_LUMA_EQ4_MASK	q3,  q14, q0, q4
	vst1.u8	{q4}, [r3], r1
			
//eq4_end:
  WELS_ASM_FUNC_END	



//uint8_t *pix, int32_t stride, int32_t alpha, int32_t beta, uint8_t *tc
  WELS_ASM_FUNC_BEGIN DeblockLumaLt4H_neon

	vdup.u8	q11, r2				// alpha [0~255]
	vdup.u8	q9, r3					// q9:: beta [0~18]

	sub			r2, r0, #3				//	pix -= 3	
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 0
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 1
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 2
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 3
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 4
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 5
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 6
	LORD_LUMA_DATA_3		d0, d1, d2, d6, d7, d8, 7

	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 0
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 1
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 2
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 3
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 4
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 5
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 6
	LORD_LUMA_DATA_3		d3, d4, d5, d9, d10, d11, 7		
//	d0d1d2d6d7d8+d3d4d5d9d10d11
	vswp		d1, d2
	vswp		d3, d4
	vswp		d1, d4	
	vswp		d7, d8
	vswp		d9, d10
	vswp		d7, d10	
//	q0::p2 = pix[-3*xstride];
//	q1::p1 = pix[-2*xstride];
//	q2::p0 = pix[-1*xstride];
//	q3::q0 = pix[ 0*xstride];
//	q4::q1 = pix[ 1*xstride];
//	q5::q2 = pix[ 2*xstride];
	sub			r0, r0, r1, lsl #4	//	pix -= 16*src_stride

//	if( tc0[i] < 0 )	 continue; else filter					
	ldr			r3, [sp, #0]
	vld1.s8	{d31}, [r3]			//	load 4 tc0[i]
	vdup.s8	d28, d31[0]    
	vdup.s8	d30, d31[1]
	vdup.s8	d29, d31[2] 
	vdup.s8	d31, d31[3]
	vtrn.32	d28, d30
	vtrn.32	d29, d31				//	q14::each 32 bits is 4x tc0[i]
	vcge.s8	q10, q14, #0			//	q10::tc0[i] >= 0

//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	MASK_MATRIX	q1, q2, q3, q4, q11, q9, q15	// q15::mask matrix
	vand.u8	q10, q10, q15			//	two mask
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		lt4_end

	veor		q15, q15
	vsub.i8	q15,q15,q14			// q15::4x -tc0[i], min	

//	input: p2, p1, p0, q0, beta, -tc0[i], tc0[i]; mask_matrx, output: _clip3(p1'), tc++;	
	DIFF_LUMA_LT4_P1_Q1	q0, q1, q2, q3, q9, q15, q14, q10, q6, q12	//	q6 = _clip3(p1')
	
	DIFF_LUMA_LT4_P1_Q1	q5, q4, q3, q2, q9, q15, q14, q10, q7, q13	//	q7 = _clip3(q1')
		
	vabs.s8	q12, q12
	vabs.s8	q13, q13					// if( abs( p2 - p0 ) < beta ) tc++;					
	vadd.u8	q14,q14,q12
	vadd.u8	q14,q14,q13			// updated  tc
	veor		q15, q15
	vsub.i8	q15,q15,q14			// updated -tc
	
//	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
	DIFF_LUMA_LT4_P0_Q0	d2, d4, d6, d8, d16, q12, q13
	DIFF_LUMA_LT4_P0_Q0	d3, d5, d7, d9, d17, q12, q13	//q8::delta		
	vmax.s8	q8, q8, q15			// >= -tc0[i]
	vmin.s8	q8, q8, q14			// <= tc0[i]
	vand.s8	q8, q8, q10
	EXTRACT_DELTA_INTO_TWO_PART	q8, q9
	vqadd.u8	q2, q2, q9		// clip_uint8( p0 + [+delta] ); p0'
	vqsub.u8	q2, q2, q8		// clip_uint8( p0 - [-delta] ); p0'

	vqsub.u8	q3, q3, q9		// clip_uint8( q0 - [+delta] ); q0'	
	vqadd.u8	q3, q3, q8		// clip_uint8( q0 + [-delta] ); q0'

	sub		r0, #2
	add		r2, r0, r1
	lsl		r1, #1
	
	vmov		q1, q6
	vmov		q4, q7
//	q1,q2,q3,q4
	vswp		q2, q3
	vswp		d3, d6
	vswp		d5, d8
//	d2~d5, d6~d7
	STORE_LUMA_DATA_4		d2, d3, d4, d5, 0, 1
	STORE_LUMA_DATA_4		d2, d3, d4, d5, 2, 3
	STORE_LUMA_DATA_4		d2, d3, d4, d5, 4, 5
	STORE_LUMA_DATA_4		d2, d3, d4, d5, 6, 7	
	
	STORE_LUMA_DATA_4		d6, d7, d8, d9, 0, 1
	STORE_LUMA_DATA_4		d6, d7, d8, d9, 2, 3
	STORE_LUMA_DATA_4		d6, d7, d8, d9, 4, 5
	STORE_LUMA_DATA_4		d6, d7, d8, d9, 6, 7		
//lt4_end:
  WELS_ASM_FUNC_END


//uint8_t *pix, int32_t stride, int32_t alpha, int32_t beta
  WELS_ASM_FUNC_BEGIN DeblockLumaEq4H_neon

	vdup.u8	q5, r2				// alpha [0~255]
	vdup.u8	q4, r3				// beta [0~18]
	
	sub			r3, r0, #4				//	pix -= 4
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,0
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,1
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,2
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,3		
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,4
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,5
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,6
	LORD_LUMA_DATA_4		d16,d17,d18,d19,d24,d25,d26,d27,7
	
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,0
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,1
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,2
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,3		
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,4
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,5
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,6
	LORD_LUMA_DATA_4		d20,d21,d22,d23,d28,d29,d30,d31,7
	
	vswp		q9, q10
	vswp		d17,d18
	vswp		d21,d22
	vswp		q13,q14
	vswp		d25,d26
	vswp		d29,d30	
	sub			r0, r0, r1	, lsl #4	//	r0 -= 16*xstride	
//	q8::p3 = pix[-4*xstride];
//	q9::p2 = pix[-3*xstride];
//	q10::p1 = pix[-2*xstride];
//	q11::p0 = pix[-1*xstride];
//	q12::q0 = pix[ 0*xstride];
//	q13::q1 = pix[ 1*xstride];
//	q14::q2 = pix[ 2*xstride];
//	q15::q3 = pix[ 3*xstride];
		
//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )		
	MASK_MATRIX	q10, q11, q12, q13, q5, q4, q6	// q6::mask matrix
//	JMP_IF_128BITS_IS_ZERO	d12, d13, d0
//	beq		eq4_end

//	if(abs( p0 - q0 ) < ((alpha >> 2) + 2) )
	mov			r2, r2, lsr #2
	add			r2, r2, #2
	vdup.u8	q5, r2
	vabd.u8	q0, q11, q12	
	vclt.u8	q7, q0, q5				// q7::indicate
//	if( abs( p2 - p0 ) < beta )
	vabd.u8	q1, q9, q11	
	vclt.u8	q1, q1, q4
	vand.s8	q1, q1, q7				//	q1::indicate [p0', p1', p2'] or [p0']
//	if( abs( q2 - q0 ) < beta )
	vabd.u8	q2, q14,q12	
	vclt.u8	q2, q2, q4
	vand.s8	q2, q2, q7				//	q2::indicate [q0', q1', q2'] or [q0']
	vand.u8	q7, q7, q6
	
	vmov		q3, q1
//	input: p3(output p1'), p2, p1, p0, q0, q1, select_matrix(output p0'), output p2'; 
//	workin q4~q5; after filtered then p3/p2 useless!
	DIFF_LUMA_EQ4_P2P1P0		d16, d18, d20, d22, d24, d26, d2, d0
	DIFF_LUMA_EQ4_P2P1P0		d17, d19, d21, d23, d25, d27, d3, d1
	
//	q1(p0') q2(q0') only need ::if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )
//	q0(p2') q8(p1') q15(q1') q3(q2'); need more &&if(abs( p0 - q0 ) < ((alpha >> 2) + 2) )&&if( abs( p2 - p0 ) < beta )
	vand.u8	q3, q7, q3
	DIFF_LUMA_EQ4_MASK	q0, q9, q3, q4	//	p2'
	vmov		q9, q4

//	DIFF_LUMA_EQ4_MASK	q8,q10, q3, q4	//	p1'
	vbsl.u8	q3, q8, q10	
		
	DIFF_LUMA_EQ4_MASK	q1,q11, q6, q8	//	p0'
	
	vand.u8	q7, q7, q2			
//	input: q3(output q1'), q2, q1, q0, p0, p1, select_matrix(output q0'), output q2'; 
//	workin q4~q5; after filtered then q3/q2 useless!		
	DIFF_LUMA_EQ4_P2P1P0		d30, d28, d26, d24, d22, d20, d4, d0
	DIFF_LUMA_EQ4_P2P1P0		d31, d29, d27, d25, d23, d21, d5, d1

//	DIFF_LUMA_EQ4_MASK	q2,  q12, q6, q4
	vbsl.u8	q6, q2, q12	
		
	DIFF_LUMA_EQ4_MASK	q15, q13, q7, q4

//	DIFF_LUMA_EQ4_MASK	q0,  q14, q7, q4
	vbsl.u8	q7, q0, q14
	
//	q9,q3,q8,q6,q4,q7
	vmov		q5, q6
	vmov		q2, q9
	vmov		q6, q4	
	vmov		q4, q8
//	q2,q3,q4,q5,q6,q7
	
	vswp	d8, d6
	vswp	d5, d7
	vswp	d5, d8
	vswp	d14, d12
	vswp	d11, d13
	vswp	d11, d14
		
	sub		r3, r0, #3
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,0
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,1
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,2
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,3
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,4
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,5
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,6
	STORE_LUMA_DATA_3		d4,d5,d6,d10,d11,d12,7
	
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,0
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,1
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,2
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,3
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,4
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,5
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,6
	STORE_LUMA_DATA_3		d7,d8,d9,d13,d14,d15,7							
	
//eq4_end:
  WELS_ASM_FUNC_END	

//uint8_t *pix_cb, uint8_t *pix_cr, int32_t stride, int32_t alpha, int32_t beta, uint8_t *tc
  WELS_ASM_FUNC_BEGIN DeblockChromaLt4V_neon

	vdup.u8	q11, r3				// alpha [0~255]
	ldr			r3, [sp, #0]

	sub			r0, r0, r2	, lsl #1	//	pix -= 2*src_stride	
	sub			r1, r1, r2, lsl #1
	vdup.u8	q9, r3					// q9:: beta [0~18]
	ldr			r3, [sp, #4]
			
	vld1.u8	{d0}, [r0], r2		//	q0::p1
	vld1.u8	{d1}, [r1], r2
	vld1.u8	{d2}, [r0], r2		//	q1::p0
	vld1.u8	{d3}, [r1], r2
	vld1.u8	{d4}, [r0], r2		//	q2::q0
	vld1.u8	{d5}, [r1], r2
	vld1.u8	{d6}, [r0]				//	q3::q1
	vld1.u8	{d7}, [r1]	

	sub			r0, r0, r2, lsl #1	//	pix = [-1*src_stride]	
	sub			r1, r1, r2, lsl #1
//	if( tc0[i] < 0 )	 continue; else filter
	vld1.s8	{d15}, [r3]		//	load 4 tc0[i], each tc0[i] 2 bytes; d[x] Cb && d[x+1] Cr
	vmovl.u8	q6, d15
	vshl.u64	d13,d12,#8
	vorr		d12,d13
	vmov		d13, d12			//	q6::each 64 bits is 2x tc0[i]
	veor		q7, q7
	vsub.i8	q7,q7,q6			//	q7::4x -tc0[i], min
	
//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	MASK_MATRIX	q0, q1, q2, q3, q11, q9, q5	// q5::mask matrix
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		lt4_end

	
//	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
	DIFF_LUMA_LT4_P0_Q0	d0, d2, d4, d6, d8, q12, q13
	DIFF_LUMA_LT4_P0_Q0	d1, d3, d5, d7, d9, q12, q13	//q4::delta		
	vmax.s8	q4, q4, q7				// >= -tc0[i]
	vmin.s8	q4, q4, q6				// <= tc0[i]
	
	vand.s8	q4, q4, q5	
	vcge.s8	q6, q6, #0				//	q6::tc0[i] >= 0
	vand.s8	q4, q4, q6
	EXTRACT_DELTA_INTO_TWO_PART	q4, q5
	vqadd.u8	q1, q1, q5			// clip_uint8( p0 + [+delta] ); p0'
	vqsub.u8	q1, q1, q4			// clip_uint8( p0 - [-delta] ); p0'
	vst1.u8	{d2}, [r0], r2
	vst1.u8	{d3}, [r1], r2	
	vqsub.u8	q2, q2, q5			// clip_uint8( q0 - [+delta] ); q0'	
	vqadd.u8	q2, q2, q4			// clip_uint8( q0 + [-delta] ); q0'
	vst1.u8	{d4}, [r0]
	vst1.u8	{d5}, [r1]

//lt4_end:
  WELS_ASM_FUNC_END

//	uint8_t *pix_cb, uint8_t *pix_cr, int32_t stride, int32_t alpha, int32_t beta
  WELS_ASM_FUNC_BEGIN DeblockChromaEq4V_neon

	vdup.u8	q11, r3				// alpha [0~255]
	ldr			r3, [sp, #0]

	sub			r0, r0, r2	, lsl #1	//	pix -= 2*src_stride	
	sub			r1, r1, r2, lsl #1
	vdup.u8	q9, r3					// q9:: beta [0~18]
			
	vld1.u8	{d0}, [r0], r2		//	q0::p1
	vld1.u8	{d1}, [r1], r2
	vld1.u8	{d2}, [r0], r2		//	q1::p0
	vld1.u8	{d3}, [r1], r2
	vld1.u8	{d4}, [r0], r2		//	q2::q0
	vld1.u8	{d5}, [r1], r2
	vld1.u8	{d6}, [r0]				//	q3::q1
	vld1.u8	{d7}, [r1]	

	sub			r0, r0, r2, lsl #1	//	pix = [-1*src_stride]	
	sub			r1, r1, r2, lsl #1
	
//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	MASK_MATRIX	q0, q1, q2, q3, q11, q9, q10	// q10::mask matrix, d20:Cb d21:Cr
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		eq4_end
	vmov			q11, q10

//	( (p1 << 1) + p0 + q1 + 2 ) >> 2
//	( (q1 << 1) + q0 + p1 + 2 ) >> 2
	DIFF_CHROMA_EQ4_P0Q0		d0, d2, d4, d6, q4, q5, q6, d14, d0		// Cb::p0' q0'
	DIFF_CHROMA_EQ4_P0Q0		d1, d3, d5, d7, q12, q13, q14, d15, d1	// Cr::p0' q0'

	vbsl.u8	q10, q7, q1		//	p0'	
	vst1.u8	{d20}, [r0], r2
	vst1.u8	{d21}, [r1], r2
		
	vbsl.u8	q11, q0, q2		//	q0'	
	vst1.u8	{d22}, [r0]
	vst1.u8	{d23}, [r1]

//eq4_end:
  WELS_ASM_FUNC_END
	
//uint8_t *pix_cb, uint8_t *pix_cr, int32_t stride, int32_t alpha, int32_t beta, uint8_t *tc
  WELS_ASM_FUNC_BEGIN DeblockChromaLt4H_neon

	vdup.u8	q11, r3				// alpha [0~255]
	ldr			r3, [sp, #0]	
	
	sub			r0, r0, #2				//	pix [-2]
	vdup.u8	q9, r3					// q9:: beta [0~18]
	ldr			r3, [sp, #4]		
	sub			r1, r1, #2
	vld1.s8	{d15}, [r3]			//	load 4 tc0[i], each tc0[i] 2 bytes; d[x] Cb && d[x+1] Cr	

	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 0
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 1
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 2
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 3
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 4
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 5
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 6
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 7
//	Cb:d0d1d2d3, Cr:d4d5d6d7
	vswp		q1, q2
	vswp		d1, d2		
	vswp		d6, d5
//	Cb:d0d2d4d6, Cr:d1d3d5d7
	

//	if( tc0[i] < 0 )	 continue; else filter

	vmovl.u8	q6, d15
	vshl.u64	d13,d12,#8
	vorr		d12,d13
	vmov		d13, d12			//	q6::each 64 bits is 2x tc0[i]
	veor		q7, q7
	vsub.i8	q7,q7,q6			//	q7::4x -tc0[i], min
	
//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	MASK_MATRIX	q0, q1, q2, q3, q11, q9, q5	// q5::mask matrix
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		lt4_end

//	input: p1, p0, q0, q1; output: _clip3(p0'); working q12,q13
	DIFF_LUMA_LT4_P0_Q0	d0, d2, d4, d6, d8, q12, q13
	DIFF_LUMA_LT4_P0_Q0	d1, d3, d5, d7, d9, q12, q13	//q4::delta		
	vmax.s8	q4, q4, q7				// >= -tc0[i]
	vmin.s8	q4, q4, q6				// <= tc0[i]
	
	vand.s8	q4, q4, q5	
	vcge.s8	q6, q6, #0				//	q6::tc0[i] >= 0
	vand.s8	q4, q4, q6
	EXTRACT_DELTA_INTO_TWO_PART	q4, q5
	vqadd.u8	q1, q1, q5			// clip_uint8( p0 + [+delta] ); p0'
	vqsub.u8	q1, q1, q4			// clip_uint8( p0 - [-delta] ); p0'
	vqsub.u8	q2, q2, q5			// clip_uint8( q0 - [+delta] ); q0'	
	vqadd.u8	q2, q2, q4			// clip_uint8( q0 + [-delta] ); q0'

	sub			r0, r0, r2, lsl #3	//	pix: 0th row	[-2]
	sub			r1, r1, r2, lsl #3
	vswp		d1, d2		
	vswp		d6, d5
	vswp		q1, q2
//	Cb:d0d1d2d3, Cr:d4d5d6d7
		
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 0
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 1
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 2
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 3
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 4
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 5
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 6
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 7
				
//lt4_end:
  WELS_ASM_FUNC_END

//	uint8_t *pix_cb, uint8_t *pix_cr, int32_t stride, int32_t alpha, int32_t beta
  WELS_ASM_FUNC_BEGIN DeblockChromaEq4H_neon

	vdup.u8	q11, r3				// alpha [0~255]
	ldr			r3, [sp, #0]
	
	sub			r0, r0, #2				//	pix [-2]
	sub			r1, r1, #2
	
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 0
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 1
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 2
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 3
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 4
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 5
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 6
	LORD_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 7
//	Cb:d0d1d2d3, Cr:d4d5d6d7
	vswp		q1, q2
	vswp		d1, d2		
	vswp		d6, d5
//	Cb:d0d2d4d6, Cr:d1d3d5d7


//	if( abs( p0 - q0 ) < alpha && abs( p1 - p0 ) < beta && abs( q1 - q0 ) < beta )	
	vdup.u8	q9, r3					// q9:: beta [0~18]
	MASK_MATRIX	q0, q1, q2, q3, q11, q9, q10	// q10::mask matrix, d20:Cb d21:Cr
//	JMP_IF_128BITS_IS_ZERO	d20, d21, d31
//	beq		eq4_end
	vmov			q11, q10

//	( (p1 << 1) + p0 + q1 + 2 ) >> 2
//	( (q1 << 1) + q0 + p1 + 2 ) >> 2
	DIFF_CHROMA_EQ4_P0Q0		d0, d2, d4, d6, q8, q9, q12, d8, d10		// Cb::p0' q0'
	DIFF_CHROMA_EQ4_P0Q0		d1, d3, d5, d7, q13, q14, q15, d9, d11	// Cr::p0' q0'

	vbsl.u8	q10, q4, q1		//	p0'			
	vbsl.u8	q11, q5, q2		//	q0'	
//	q0 q10 q11 q3

	sub			r0, r0, r2, lsl #3	//	pix: 0th row	[-2]
	sub			r1, r1, r2, lsl #3

	vmov		q1, q10
	vmov		q2, q11
	vswp		d1, d2		
	vswp		d6, d5
	vswp		q1, q2
//	Cb:d0d1d2d3, Cr:d4d5d6d7
		
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 0
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 1
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 2
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 3
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 4
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 5
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 6
	STORE_CHROMA_DATA_4	d0, d1, d2, d3, d4, d5, d6, d7, 7

//eq4_end:
  WELS_ASM_FUNC_END


// r0    int8_t* non_zero_count,
  WELS_ASM_FUNC_BEGIN enc_avc_non_zero_count_neon
	
	vld1.64	{d0-d2}, [r0]
		
	vceq.s8	q0, q0, #0
	vceq.s8	d2, d2, #0
	vmvn	q0, q0
	vmvn	d2, d2
	vabs.s8	q0, q0
	vabs.s8	d2, d2
	
	vst1.64	{d0-d2}, [r0]
  WELS_ASM_FUNC_END

#endif