1// Copyright 2021 Google LLC 2// 3// This source code is licensed under the BSD-style license found in the 4// LICENSE file in the root directory of this source tree. 5 6$assert BATCH_TILE >= 1 7#include <assert.h> 8#include <math.h> 9 10#include <xnnpack/common.h> 11#include <xnnpack/math.h> 12#include <xnnpack/vcvt.h> 13 14 15$XINT8_T = {"QS8": "int8_t", "QU8": "uint8_t"}[DATATYPE] 16$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32" 17$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32" 18void xnn_f32_${DATATYPE.lower()}_vcvt_ukernel__${"wasm" if WASM else "scalar"}_lrintf_x${BATCH_TILE}( 19 size_t n, 20 const float* x, 21 ${XINT8_T}* y, 22 const union xnn_f32_${DATATYPE.lower()}_cvt_params params[restrict XNN_MIN_ELEMENTS(1)]) 23{ 24 assert(n != 0); 25 assert(n % sizeof(float) == 0); 26 assert(x != NULL); 27 assert(y != NULL); 28 29 const float vscale = params->scalar_lrintf.scale; 30 const float voutput_min_less_zero_point = params->scalar_lrintf.output_min_less_zero_point; 31 const float voutput_max_less_zero_point = params->scalar_lrintf.output_max_less_zero_point; 32 const int32_t voutput_zero_point = params->scalar_lrintf.output_zero_point; 33 34 $if BATCH_TILE > 1: 35 for (; n >= ${BATCH_TILE} * sizeof(float); n -= ${BATCH_TILE} * sizeof(float)) { 36 $for N in range(BATCH_TILE): 37 float vx${N} = x[${N}]; 38 x += ${BATCH_TILE}; 39 40 $for N in range(BATCH_TILE): 41 vx${N} *= vscale; 42 43 $for N in range(BATCH_TILE): 44 vx${N} = ${MAX_F32}(vx${N}, voutput_min_less_zero_point); 45 46 $for N in range(BATCH_TILE): 47 vx${N} = ${MIN_F32}(vx${N}, voutput_max_less_zero_point); 48 49 $for N in range(BATCH_TILE): 50 int32_t vy${N} = (int32_t) lrintf(vx${N}); 51 52 $for N in range(BATCH_TILE): 53 vy${N} += voutput_zero_point; 54 55 $for N in range(BATCH_TILE): 56 y[${N}] = (${XINT8_T}) vy${N}; 57 y += ${BATCH_TILE}; 58 } 59 $if BATCH_TILE == 1: 60 do { 61 float vx = *x++; 62 vx *= vscale; 63 vx = ${MAX_F32}(vx, voutput_min_less_zero_point); 64 vx = ${MIN_F32}(vx, voutput_max_less_zero_point); 65 66 int32_t vy = (int32_t) lrintf(vx); 67 vy += voutput_zero_point; 68 69 *y++ = (${XINT8_T}) vy; 70 71 n -= sizeof(float); 72 } while (n != 0); 73 $elif BATCH_TILE == 2: 74 if XNN_UNLIKELY(n != 0) { 75 float vx = *x; 76 vx *= vscale; 77 vx = ${MAX_F32}(vx, voutput_min_less_zero_point); 78 vx = ${MIN_F32}(vx, voutput_max_less_zero_point); 79 80 int32_t vy = (int32_t) lrintf(vx); 81 vy += voutput_zero_point; 82 83 *y = (${XINT8_T}) vy; 84 } 85 $else: 86 if XNN_UNLIKELY(n != 0) { 87 do { 88 float vx = *x++; 89 vx *= vscale; 90 vx = ${MAX_F32}(vx, voutput_min_less_zero_point); 91 vx = ${MIN_F32}(vx, voutput_max_less_zero_point); 92 93 int32_t vy = (int32_t) lrintf(vx); 94 vy += voutput_zero_point; 95 96 *y++ = (${XINT8_T}) vy; 97 98 n -= sizeof(float); 99 } while (n != 0); 100 } 101} 102