Loading...
Searching...
No Matches
factor.h
/*
* Copyright 2011-15 ARM Limited and Contributors.
* 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.
* * Neither the name of ARM Limited nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ARM LIMITED 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 ARM LIMITED AND 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.
*/
/*
* NE10 Library : common/factor.h
*/
// Typebuilding MACROs
// - Slight difference between toolchain versions on intrinsics
#define FLOAT32_2x3(x1,y1,x2,y2,x3,y3) \
{{ \
{x1, y1}, {x2,y2}, {x3,y3} \
}}
// Unit test use this macro to index into their function table
// "opc" stands for operation's code (which function),
// and "imp" stands for implementation (which implementation of the function)
#define FTBL_IDX(opc, imp) ((opc-1)*IMPL_COUNT+(imp-1))
// This macro helps measure the performance of the code passed to it through the "code" argument
// It is used in the unit tests
#define MEASURE(res, code) \
{ \
gettimeofday (&before, &zone); \
code \
gettimeofday (&after, &zone); \
if (before.tv_usec > after.tv_usec) \
{ \
after.tv_usec += 1000000; \
after.tv_sec--; \
} \
lapsed.tv_usec = after.tv_usec - before.tv_usec; \
lapsed.tv_sec = after.tv_sec - before.tv_sec; \
res = lapsed.tv_sec + ((double)lapsed.tv_usec / 1000000.0); \
}
// There are several categories of functions that share common code:
// Different groups of functions take different number of inputs
//
// Group 1 = Functions that take a dst, a src, and a cst ("DstSrcCst" for short)
// Group 2 = Those that take a dst, an acc, a src, and a cst ("DstAccSrcCst" for short)
// Group 3 = The ones that take a dst, and a cst only ("DstCst" for short)
//
// Group 4 = These take a dst, and two src inputs, src2 and scr2 ("DstSrc1Src2")
// Group 5 = These take a dst, an acc, and two src inputs ("DstAccSrc1Src2")
// Group 6 = These take a dst, and a src ("DstSrc")
//
// The naming convention used in the following macros is as follows:
// SNAPP_<A>_OPERATION_<T>_<I>
// where
// <A> Stands for the title of the operation (add, mul, etc) followed by its type (C = const as in addc).
// The letter X - if used - means any such operation.
// <T> Indicates the type of the operation (float, vec2, etc.)
// The letter X - is used - means any type.
// <I> This indicates the implementation (it can be C, ASM, or NEON).
// A few macros to check pointers and their address range to make sure there's
// no unwanted overlap between any two of them
#define NE10_CHECKPOINTER_DstSrcCst_OPERATION \
if ( (void *)dst < (void *)src ) \
{ assert ( (void *)dst + count <= (void *)src ); } \
else if ( (void *)dst > (void *)src ) \
{ assert ( (void *)src + count <= (void *)dst ); }
#define NE10_CHECKPOINTER_DstSrc_OPERATION NE10_CHECKPOINTER_DstSrcCst_OPERATION
#define NE10_CHECKPOINTER_3POINTER_OPERATION(arg1, arg2, arg3) \
if ( (void *)arg1 < (void *)arg2 ) \
{ assert ( (void *)arg1 + count <= (void *)arg2 ); } \
else if ( (void *)arg1 > (void *)arg2 ) \
{ assert ( (void *)arg2 + count <= (void *)arg1 ); } \
if ( (void *)arg1 < (void *)arg3 ) \
{ assert ( (void *)arg1 + count <= (void *)arg3 ); } \
else if ( (void *)arg1 > (void *)arg3 ) \
{ assert ( (void *)arg3 + count <= (void *)arg1 ); } \
if ( (void *)arg3 < (void *)arg2 ) \
{ assert ( (void *)arg3 + count <= (void *)arg2 ); } \
else if ( (void *)arg3 > (void *)arg2 ) \
{ assert ( (void *)arg2 + count <= (void *)arg3 ); }
#define NE10_CHECKPOINTER_4POINTER_OPERATION(arg1, arg2, arg3, arg4) \
NE10_CHECKPOINTER_3POINTER_OPERATION(arg1, arg2, arg3) \
if ( (void *)arg1 < (void *)arg4 ) \
{ assert ( (void *)arg1 + count <= (void *)arg4 ); } \
else if ( (void *)arg1 > (void *)arg4 ) \
{ assert ( (void *)arg4 + count <= (void *)arg1 ); } \
if ( (void *)arg2 < (void *)arg4 ) \
{ assert ( (void *)arg2 + count <= (void *)arg4 ); } \
else if ( (void *)arg2 > (void *)arg4 ) \
{ assert ( (void *)arg4 + count <= (void *)arg2 ); } \
if ( (void *)arg4 < (void *)arg3 ) \
{ assert ( (void *)arg4 + count <= (void *)arg3 ); } \
else if ( (void *)arg4 > (void *)arg3 ) \
{ assert ( (void *)arg3 + count <= (void *)arg4 ); }
#define NE10_CHECKPOINTER_DstAccSrcCst_OPERATION { \
NE10_CHECKPOINTER_3POINTER_OPERATION(dst, acc, src); }
#define NE10_CHECKPOINTER_DstCst_OPERATION {}
#define NE10_CHECKPOINTER_DstSrc1Src2_OPERATION { \
NE10_CHECKPOINTER_3POINTER_OPERATION(dst, src1, src2); }
#define NE10_CHECKPOINTER_DstAccSrc1Src2_OPERATION { \
NE10_CHECKPOINTER_4POINTER_OPERATION(dst, acc, src1, src2); }
// These macros generalise implementation of the functions.
// Macros used in C implementations
#define NE10_TEMPLATE_XC_OPERATION_X_C(checkPointer, loopCode) { \
ne10_result_t res = NE10_OK; \
unsigned int itr = 0; \
checkPointer; \
for ( itr = 0; itr < count; itr++ ) \
{ loopCode ; /* this loop iterates through each and every float item one at a time */ \
} \
return res; \
}
// macros used in the NEON implementations
// Main Loop = The loop where the number of items to be processed is exactly the
// number that we can process in a single iteration.
//
// Secondary Loop = The loop that follows a Main Loop to fill in the entries that
// did not fit into the Main Loop. This is needed when the number of
// input items is not a multiple of the number of items that we
// process in every iteration of the Main Loop.
/****************************************************
* *
* The "DstSrcCst" group of functions *
* *
****************************************************/
#define NE10_DstSrcCst_MAINLOOP_FLOAT_NEON(loopCode) { \
/* load 4 values */ \
n_src = vld1q_f32( (float32_t*)src ); \
src += 4; /* move to the next 4 float items; 4*float */ \
loopCode; /* the actual operation is placed here... */ /* The main loop iterates through four float values each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store the results back */ \
dst += 4; /* move to the next items; 4*float */ \
}
#define NE10_DstSrcCst_SECONDLOOP_FLOAT_NEON(loopCode) { \
float32x2_t n_tmp_src = { 0.0f , 0.0f }; /* temporary storage to be used with NEON load/store intrinsics */ \
float32x2_t n_tmp_cst = { cst, cst }; /* temporary constant value for use in the main NEON operation */ \
n_tmp_src = vld1_lane_f32 ( (float32_t*)src, n_tmp_src, 0); /* load into the first lane of d0 */ \
loopCode; /* the actual operation is placed here ... */ /* exceptional cases where the count is not a multiple of 4 */ \
vst1_lane_f32( (float32_t*)dst, n_tmp_src, 0); /* store the lane back into the memory */ \
/* move to the next item in the stream */ \
src++; \
dst++; \
}
#define NE10_DstSrcCst_OPERATION_FLOAT_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_src; \
float32x4_t n_dst; \
checkPointer; \
int dif = 0; \
dif = count % 4; /* either 0 or one of 1,2,3; in the latter cases the second path is taken */ \
for (; count > dif; count -= 4) { \
loopCode1; \
} \
if ( 0 != dif ) { \
unsigned int idx; \
for ( idx = 0 ; idx < dif; idx++ ) { \
loopCode2; \
} \
} \
return res; \
}
#define NE10_DstSrcCst_MAINLOOP_VEC2F_NEON(loopCode) { \
n_src = vld1q_f32( (float32_t*)src ); /* load two vectors */ \
src += 2; /* move to the next two vectors */ \
loopCode; /* actual operation */ /* The main loop iterates through two 2D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store back */ \
dst += 2; /* move to the next 2 vectors */ \
}
#define NE10_DstSrcCst_SECONDLOOP_VEC2F_NEON(loopCode) { \
float32x2_t n_tmp_src; \
float32x2_t n_tmp_cst = { cst->x, cst->y }; \
n_tmp_src = vld1_f32( (float32_t*)src ); \
loopCode; /* exceptional cases where the count isn't a multiple of 2 */ \
vst1_f32( (float32_t*)dst, n_tmp_src); \
}
#define NE10_DstSrcCst_OPERATION_VEC2F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst = { cst->x, cst->y, cst->x, cst->y }; \
float32x4_t n_src; \
float32x4_t n_dst; \
checkPointer; \
int dif = count % 2; \
for (; count > dif; count -= 2) { \
loopCode1; \
} \
if ( 0 != dif ) { \
loopCode2; \
} \
return res; \
}
#define NE10_DstSrcCst_MAINLOOP_VEC3F_NEON(loopCode) { \
n_src1 = vld1q_f32( (float32_t*)src ); \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
n_src2 = vld1q_f32( (float32_t*)src ); \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
n_src3 = vld1q_f32( (float32_t*)src ); \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
loopCode; /* The main loop iterates through three 3D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst1 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_dst2 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_dst3 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
}
#define NE10_DstSrcCst_SECONDLOOP_VEC3F_NEON(loopCode) { \
float32x2x3_t n_tmp_src = FLOAT32_2x3( \
0.0f, 0.0f, 0.0f , 0.0f, 0.0f , 0.0f); \
float32x2x3_t n_tmp_cst = { (const float32x2_t){cst->x, 0}, \
(const float32x2_t){cst->y, 0}, (const float32x2_t){cst->z, 0} }; \
n_tmp_src = vld3_lane_f32 ( (float32_t*)src, n_tmp_src, 0); \
loopCode; /* exceptional cases where the count isn't a multiple of 3 */ \
vst3_lane_f32( (float32_t*)dst, n_tmp_src, 0); \
src++; \
dst++; \
}
#define NE10_DstSrcCst_OPERATION_VEC3F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst1 = { cst->x, cst->y, cst->z, cst->x }; \
float32x4_t n_cst2 = { cst->y, cst->z, cst->x, cst->y }; \
float32x4_t n_cst3 = { cst->z, cst->x, cst->y, cst->z }; \
float32x4_t n_src1, n_src2, n_src3; \
float32x4_t n_dst1, n_dst2, n_dst3; \
checkPointer; \
int dif = count % 4; \
for (; count > dif; count -= 4) { \
loopCode1; \
} \
if ( 0 != dif ) { \
unsigned int idx; \
for ( idx = 0 ; idx < dif; idx++ ) { \
loopCode2; \
} \
} \
return res; \
}
/* Note that for the VEC4* types, we do not need a second loop as the number
of input items is always a multiple of four. */
#define NE10_DstSrcCst_MAINLOOP_VEC4F_NEON(loopCode) { \
n_src = vld1q_f32( (float32_t*)src ); \
src ++; \
loopCode; \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* The main loop iterates through one 4D vector each time */ \
dst ++; \
}
#define NE10_DstSrcCst_OPERATION_VEC4F_NEON(checkPointer, loopCode) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst = { cst->x, cst->y, cst->z, cst->w }; \
float32x4_t n_src; \
float32x4_t n_dst; \
checkPointer; \
for (; count != 0; count --) { \
loopCode; \
} \
return res; \
}
/****************************************************
* *
* The "DstAccSrcCst" group of functions *
* *
****************************************************/
#define NE10_DstAccSrcCst_MAINLOOP_FLOAT_NEON(loopCode) { \
/* load 4 values */ \
n_acc = vld1q_f32( (float32_t*)acc ); \
n_src = vld1q_f32( (float32_t*)src ); \
acc += 4; /* move to the next 4 float items; 4*float */ \
src += 4; \
loopCode; /* the actual operation is placed here... */ /* The main loop iterates through four float values each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store theresults back */ \
dst += 4; /* move to the next items; 4*float */ \
}
#define NE10_DstAccSrcCst_SECONDLOOP_FLOAT_NEON(loopCode) { \
float32x2_t n_tmp_acc = { 0.0f , 0.0f }; /* temporary storage to be used with NEON load/store intrinsics */ \
float32x2_t n_tmp_src = { 0.0f , 0.0f }; /* temporary storage to be used with NEON load/store intrinsics */ \
float32x2_t n_tmp_cst = { cst, cst }; /* temporary constant value for use in the main NEON operation */ \
n_tmp_acc = vld1_lane_f32 ( (float32_t*)acc, n_tmp_acc, 0); /* load into the first lane of d0 */ \
n_tmp_src = vld1_lane_f32 ( (float32_t*)src, n_tmp_src, 0); /* load into the first lane of d1 */ \
loopCode; /* the actual operation is palced here ... */ /* exceptional cases where the count is not a multiple of 4 */ \
vst1_lane_f32( (float32_t*)dst, n_tmp_src, 0); /* store the lane back into the memory */ \
/* move to the next item in the stream */ \
acc++; \
src++; \
dst++; \
}
#define NE10_DstAccSrcCst_OPERATION_FLOAT_NEON NE10_DstSrcCst_OPERATION_FLOAT_NEON
#define NE10_DstAccSrcCst_MAINLOOP_VEC2F_NEON(loopCode) { \
n_acc = vld1q_f32( (float32_t*)acc ); /* load two vectors */ \
n_src = vld1q_f32( (float32_t*)src ); /* load two vectors */ \
acc += 2; /* move to the next two vectors */ \
src += 2; \
loopCode; /* actual operation */ /* The main loop iterates through two 2D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store back */ \
dst += 2; /* move to the next 2 vectors */ \
}
#define NE10_DstAccSrcCst_SECONDLOOP_VEC2F_NEON(loopCode) { \
float32x2_t n_tmp_acc; \
float32x2_t n_tmp_src; \
float32x2_t n_tmp_cst = { cst->x, cst->y }; \
n_tmp_acc = vld1_f32( (float32_t*)acc ); \
n_tmp_src = vld1_f32( (float32_t*)src ); \
loopCode; /* exceptional cases where the count isn't a multiple of 2 */ \
vst1_f32( (float32_t*)dst, n_tmp_src); \
}
#define NE10_DstAccSrcCst_OPERATION_VEC2F_NEON NE10_DstSrcCst_OPERATION_VEC2F_NEON
#define NE10_DstAccSrcCst_MAINLOOP_VEC3F_NEON(loopCode) { \
n_acc1 = vld1q_f32( (float32_t*)acc ); /* Load accumulator values */ \
acc = ((void*)acc)+(4*sizeof(ne10_float32_t)); \
n_acc2 = vld1q_f32( (float32_t*)acc ); \
acc = ((void*)acc)+(4*sizeof(ne10_float32_t)); \
n_acc3 = vld1q_f32( (float32_t*)acc ); \
acc = ((void*)acc)+(4*sizeof(ne10_float32_t)); \
n_src1 = vld1q_f32( (float32_t*)src ); /* Load source values */ \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
n_src2 = vld1q_f32( (float32_t*)src ); \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
n_src3 = vld1q_f32( (float32_t*)src ); \
src = ((void*)src)+(4*sizeof(ne10_float32_t)); \
loopCode; /* The main loop iterates through three 3D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst1 ); /* Store the results back into the memory */ \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_dst2 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_dst3 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
}
#define NE10_DstAccSrcCst_SECONDLOOP_VEC3F_NEON(loopCode) { \
float32x2x3_t n_tmp_acc = FLOAT32_2x3( \
0.0f, 0.0f, \
0.0f, 0.0f, \
0.0f, 0.0f \
); \
float32x2x3_t n_tmp_src = FLOAT32_2x3( \
0.0f, 0.0f, \
0.0f, 0.0f, \
0.0f, 0.0f \
); \
float32x2x3_t n_tmp_cst = { (const float32x2_t){cst->x, 0}, \
(const float32x2_t){cst->y, 0}, \
(const float32x2_t){cst->z, 0} }; \
n_tmp_acc = vld3_lane_f32 ( (float32_t*)acc, n_tmp_acc, 0); \
n_tmp_src = vld3_lane_f32 ( (float32_t*)src, n_tmp_src, 0); \
loopCode; /* exceptional cases where the count isn't a multiple of 3 */ \
vst3_lane_f32( (float32_t*)dst, n_tmp_src, 0); \
acc++; \
src++; \
dst++; \
}
#define NE10_DstAccSrcCst_OPERATION_VEC3F_NEON NE10_DstSrcCst_OPERATION_VEC3F_NEON
#define NE10_DstAccSrcCst_MAINLOOP_VEC4F_NEON(loopCode) { \
n_acc = vld1q_f32( (float32_t*)acc ); \
n_src = vld1q_f32( (float32_t*)src ); \
acc ++; \
src ++; \
loopCode; \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* The main loop iterates through one 4D vector each time */ \
dst ++; \
}
#define NE10_DstAccSrcCst_OPERATION_VEC4F_NEON NE10_DstSrcCst_OPERATION_VEC4F_NEON
/****************************************************
* *
* The "DstCst" group of functions *
* *
****************************************************/
#define NE10_DstCst_MAINLOOP_FLOAT_NEON(loopCode) { \
/* load 4 values */ \
loopCode; /* the actual operation is placed here... */ /* The main loop iterates through four float values each time */ \
vst1q_f32 ( (float32_t*)dst , n_cst ); /* store theresults back */ \
dst += 4; /* move to the next items; 4*float */ \
}
#define NE10_DstCst_SECONDLOOP_FLOAT_NEON(loopCode) { \
float32x2_t n_tmp_cst = { cst, cst }; /* temporary constant value for use in the main NEON operation */ \
loopCode; /* the actual operation is palced here ... */ /* exceptional cases where the count is not a multiple of 4 */ \
vst1_lane_f32( (float32_t*)dst, n_tmp_cst, 0); /* store the lane back into the memory */ \
/* move to the next item in the stream */ \
dst++; \
}
#define NE10_DstCst_OPERATION_FLOAT_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
checkPointer; \
int dif = 0; \
dif = count % 4; /* either 0 or one of 1,2,3; in the latter cases the second path is taken */ \
for (; count > dif; count -= 4) { \
loopCode1; \
} \
if ( 0 != dif ) { \
unsigned int idx; \
for ( idx = 0 ; idx < dif; idx++ ) { \
loopCode2; \
} \
} \
return res; \
}
#define NE10_DstCst_MAINLOOP_VEC2F_NEON(loopCode) { \
loopCode; /* actual operation */ /* The main loop iterates through two 2D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_cst ); /* store back */ \
dst += 2; /* move to the next 2 vectors */ \
}
#define NE10_DstCst_SECONDLOOP_VEC2F_NEON(loopCode) { \
float32x2_t n_tmp_cst = { cst->x, cst->y }; \
loopCode; /* exceptional cases where the count isn't a multiple of 2 */ \
vst1_f32( (float32_t*)dst, n_tmp_cst); \
}
#define NE10_DstCst_OPERATION_VEC2F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst = { cst->x, cst->y, cst->x, cst->y }; \
checkPointer; \
int dif = count % 2; \
for (; count > dif; count -= 2) { \
loopCode1; \
} \
if ( 0 != dif ) { \
loopCode2; \
} \
return res; \
}
#define NE10_DstCst_MAINLOOP_VEC3F_NEON(loopCode) { \
loopCode; /* The main loop iterates through three 3D vectors each time */ \
vst1q_f32 ( (float32_t*)dst , n_cst1 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_cst2 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
vst1q_f32 ( (float32_t*)dst , n_cst3 ); \
dst = ((void*)dst)+(4*sizeof(ne10_float32_t)); \
}
#define NE10_DstCst_SECONDLOOP_VEC3F_NEON(loopCode) { \
float32x2x3_t n_tmp_cst = { (const float32x2_t){cst->x, 0}, \
(const float32x2_t){cst->y, 0}, (const float32x2_t){cst->z, 0} }; \
loopCode; /* exceptional cases where the count isn't a multiple of 3 */ \
vst3_lane_f32( (float32_t*)dst, n_tmp_cst, 0); \
dst++; \
}
#define NE10_DstCst_OPERATION_VEC3F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst1 = { cst->x, cst->y, cst->z, cst->x }; \
float32x4_t n_cst2 = { cst->y, cst->z, cst->x, cst->y }; \
float32x4_t n_cst3 = { cst->z, cst->x, cst->y, cst->z }; \
checkPointer; \
int dif = count % 4; \
for (; count > dif; count -= 4) { \
loopCode1; \
} \
if ( 0 != dif ) { \
unsigned int idx; \
for ( idx = 0 ; idx < dif; idx++ ) { \
loopCode2; \
} \
} \
return res; \
}
#define NE10_DstCst_MAINLOOP_VEC4F_NEON(loopCode) { \
loopCode; \
vst1q_f32 ( (float32_t*)dst , n_cst ); /* The main loop iterates through one 4D vector each time */ \
dst ++; \
}
#define NE10_DstCst_OPERATION_VEC4F_NEON(checkPointer, loopCode) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_cst = { cst->x, cst->y, cst->z, cst->w }; \
checkPointer; \
for (; count != 0; count --) { \
loopCode; \
} \
return res; \
}
/****************************************************
* *
* The "DstSrc1Src2" group of functions *
* *
****************************************************/
#define NE10_DstSrc1Src2_MAINLOOP_FLOAT_NEON(loopCode) { \
/* load 4 values */ \
n_src = vld1q_f32( (float32_t*)src1 ); \
src1 += 4; /* move to the next 4 float items; 4*float */ \
n_src2 = vld1q_f32( (float32_t*)src2 ); \
src2 += 4; /* move to the next 4 float items; 4*float */ \
loopCode; /* the actual operation is placed here... */ /* The main loop iterates through four float values each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store the results back */ \
dst += 4; /* move to the next items; 4*float */ \
}
#define NE10_DstSrc1Src2_SECONDLOOP_FLOAT_NEON(loopCode) { \
float32x2_t n_tmp_src = { 0.0f , 0.0f }; /* temporary storage to be used with NEON load/store intrinsics */ \
float32x2_t n_tmp_src2 = { 0.0f , 0.0f }; \
n_tmp_src = vld1_lane_f32 ( (float32_t*)src1, n_tmp_src, 0); /* load into the first lane of d0 */ \
n_tmp_src2 = vld1_lane_f32 ( (float32_t*)src2, n_tmp_src, 0); \
loopCode; /* the actual operation is placed here ... */ /* exceptional cases where the count is not a multiple of 4 */ \
vst1_lane_f32( (float32_t*)dst, n_tmp_src, 0); /* store the lane back into the memory */ \
/* move to the next item in the stream */ \
src1++; \
src2++; \
dst++; \
}
#define NE10_DstSrc1Src2_OPERATION_FLOAT_NEON NE10_DstSrcCst_OPERATION_FLOAT_NEON
/****************************************************
* *
* The "DstAccSrc1Src2" group of functions *
* *
****************************************************/
#define NE10_DstAccSrc1Src2_MAINLOOP_FLOAT_NEON(loopCode) { \
/* load 4 values */ \
n_acc = vld1q_f32( (float32_t*)acc ); \
n_src = vld1q_f32( (float32_t*)src1 ); \
n_src2 = vld1q_f32( (float32_t*)src2 ); \
acc += 4; /* move to the next 4 float items; 4*float */ \
src1 += 4; \
src2 += 4; \
loopCode; /* the actual operation is placed here... */ /* The main loop iterates through four float values each time */ \
vst1q_f32 ( (float32_t*)dst , n_dst ); /* store theresults back */ \
dst += 4; /* move to the next items; 4*float */ \
}
#define NE10_DstAccSrc1Src2_SECONDLOOP_FLOAT_NEON(loopCode) { \
float32x2_t n_tmp_acc = { 0.0f , 0.0f }; /* temporary storage to be used with NEON load/store intrinsics */ \
float32x2_t n_tmp_src = { 0.0f , 0.0f }; \
float32x2_t n_tmp_src2 = { 0.0f, 0.0f }; \
n_tmp_acc = vld1_lane_f32 ( (float32_t*)acc, n_tmp_acc, 0); /* load into the first lane of d0 */ \
n_tmp_src = vld1_lane_f32 ( (float32_t*)src1, n_tmp_src, 0); /* load into the first lane of d1 */ \
n_tmp_src2 = vld1_lane_f32 ( (float32_t*)src2, n_tmp_src2, 0); /* load into the first lane of d2 */ \
loopCode; /* the actual operation is palced here ... */ /* exceptional cases where the count is not a multiple of 4 */ \
vst1_lane_f32( (float32_t*)dst, n_tmp_src, 0); /* store the lane back into the memory */ \
/* move to the next item in the stream */ \
acc++; \
src1++; \
src2++; \
dst++; \
}
#define NE10_DstAccSrc1Src2_OPERATION_FLOAT_NEON NE10_DstAccSrcCst_OPERATION_FLOAT_NEON
/****************************************************
* *
* The "DstSrc" group of functions *
* *
****************************************************/
#define NE10_DstSrc_MAINLOOP_FLOAT_NEON NE10_DstSrcCst_MAINLOOP_FLOAT_NEON
#define NE10_DstSrc_SECONDLOOP_FLOAT_NEON NE10_DstSrcCst_SECONDLOOP_FLOAT_NEON
#define NE10_DstSrc_OPERATION_FLOAT_NEON NE10_DstSrcCst_OPERATION_FLOAT_NEON
#define NE10_DstSrc_MAINLOOP_VEC2F_NEON(loopCode) { \
n_src = vld2_f32( (float32_t*)src ); /* load two vectors */ \
src += 2; /* move to the next two vectors */ \
loopCode; /* actual operation */ /* The main loop iterates through two 2D vectors each time */ \
/* store the results and increment the destination pointer within the loopCode */ \
}
#define NE10_DstSrc_SECONDLOOP_VEC2F_NEON(loopCode) { \
loopCode; /* exceptional cases where the count isn't a multiple of 2 */ \
/* store the results within the loopCode */ \
}
#define NE10_DstSrc_OPERATION_VEC2F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x2x2_t n_src; \
float32x2_t n_dst; \
checkPointer; \
int dif = count % 2; \
for (; count > dif; count -= 2) { \
loopCode1; \
} \
if ( 0 != dif ) { \
loopCode2; \
} \
return res; \
}
#define NE10_DstSrc_MAINLOOP_VEC3F_NEON(loopCode) { \
n_src = vld3q_f32( (float32_t*)src ); \
src = ((void*)src)+(12*sizeof(ne10_float32_t)); \
loopCode; /* The main loop iterates through four 3D vectors each time */ \
/* store the results and increment the destination pointer within the loopCode */ \
}
#define NE10_DstSrc_SECONDLOOP_VEC3F_NEON(loopCode) { \
loopCode; /* exceptional cases where the count isn't a multiple of 4 */ \
/* store the results within the loopCode */ \
}
#define NE10_DstSrc_OPERATION_VEC3F_NEON(checkPointer, loopCode1, loopCode2) { \
ne10_result_t res = NE10_OK; \
float32x4x3_t n_src; \
float32x4_t n_dst; \
checkPointer; \
int dif = count % 4; \
for (; count > dif; count -= 4) { \
loopCode1; \
} \
if ( 0 != dif ) { \
unsigned int idx; \
for ( idx = 0 ; idx < dif; idx++ ) { \
loopCode2; \
} \
} \
return res; \
}
/* Note that for the VEC4* types, we do not need a second loop as the number
of input items is always a multiple of four. */
#define NE10_DstSrc_MAINLOOP_VEC4F_NEON(loopCode) { \
n_src = vld1q_f32( (float32_t*)src ); \
src ++; \
loopCode; \
/* store the results and increment the destination pointer within the loopCode */ \
}
#define NE10_DstSrc_OPERATION_VEC4F_NEON(checkPointer, loopCode) { \
ne10_result_t res = NE10_OK; \
float32x4_t n_src; \
checkPointer; \
for (; count != 0; count --) { \
loopCode; \
} \
return res; \
}