From 1ed19e89885a3b637c7797fc3312dade50039c90 Mon Sep 17 00:00:00 2001 From: unmeshna Date: Thu, 17 Sep 2026 01:57:44 -0700 Subject: [PATCH] Add HiFi int16 pooling support for Xtensa Adds int16 average/max pooling (avgpool_16/maxpool_16) via the new pooling_int16.cc helper and extends pooling_int8.cc dispatch and xtensa_pooling.h with the int16 HiFi entry points. Registers pooling_int16.cc in xtensa_makefile.inc. --- .../lite/micro/kernels/xtensa/pooling.cc | 37 ++++-- .../micro/kernels/xtensa/pooling_int16.cc | 125 ++++++++++++++++++ .../lite/micro/kernels/xtensa/pooling_int8.cc | 117 +++++++++------- .../micro/kernels/xtensa/xtensa_pooling.h | 26 +++- .../tools/make/targets/xtensa_makefile.inc | 1 + 5 files changed, 238 insertions(+), 68 deletions(-) create mode 100644 tensorflow/lite/micro/kernels/xtensa/pooling_int16.cc diff --git a/tensorflow/lite/micro/kernels/xtensa/pooling.cc b/tensorflow/lite/micro/kernels/xtensa/pooling.cc index 172d0587412..842afd40692 100644 --- a/tensorflow/lite/micro/kernels/xtensa/pooling.cc +++ b/tensorflow/lite/micro/kernels/xtensa/pooling.cc @@ -32,7 +32,7 @@ TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) { auto* params = reinterpret_cast(node->builtin_data); TFLITE_DCHECK(node->user_data != nullptr); -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) auto* op_data = static_cast(node->user_data); const OpDataPooling* reference_op_data = &(op_data->reference_op_data); #else @@ -53,8 +53,8 @@ TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) { break; } case kTfLiteInt8: { -#if defined(HIFI5) - AverageEvalQuantizedHifi(context, node, params, op_data, input, output); +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) + AverageEvalQuantizedInt8Hifi(context, node, params, op_data, input, output); #elif defined(VISION_P6) const auto& op_data = *(reinterpret_cast(node->user_data)); @@ -66,8 +66,12 @@ TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) { break; } case kTfLiteInt16: { +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) + AverageEvalQuantizedInt16Hifi(context, node, params, op_data, input, output); +#else AveragePoolingEvalQuantized(context, node, params, reference_op_data, input, output); +#endif break; } default: { @@ -84,19 +88,20 @@ TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { auto* params = reinterpret_cast(node->builtin_data); TFLITE_DCHECK(node->user_data != nullptr); -#if defined(HIFI5) + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kPoolingInputTensor); + TfLiteEvalTensor* output = + micro::GetEvalOutput(context, node, kPoolingOutputTensor); + +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) + const OpDataPooling* reference_op_data; auto* op_data = static_cast(node->user_data); - const OpDataPooling* reference_op_data = &(op_data->reference_op_data); + reference_op_data = &(op_data->reference_op_data); #else const OpDataPooling* reference_op_data = static_cast(node->user_data); #endif - const TfLiteEvalTensor* input = - micro::GetEvalInput(context, node, kPoolingInputTensor); - TfLiteEvalTensor* output = - micro::GetEvalOutput(context, node, kPoolingOutputTensor); - switch (input->type) { case kTfLiteFloat32: { MaxPoolingEvalFloat(context, node, params, reference_op_data, input, @@ -104,8 +109,8 @@ TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { break; } case kTfLiteInt8: { -#if defined(HIFI5) - MaxEvalQuantizedHifi(context, node, params, op_data, input, output); +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) + MaxEvalQuantizedInt8Hifi(context, node, params, op_data, input, output); #elif defined(VISION_P6) const auto& op_data = *(reinterpret_cast(node->user_data)); @@ -117,8 +122,12 @@ TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { break; } case kTfLiteInt16: { +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) + MaxEvalQuantizedInt16Hifi(context, node, params, op_data, input, output); +#else MaxPoolingEvalQuantized(context, node, params, reference_op_data, input, output); +#endif break; } default: { @@ -133,7 +142,7 @@ TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { } // namespace TFLMRegistration Register_AVERAGE_POOL_2D() { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) return tflite::micro::RegisterOp(XtensaPoolingInit, AveragePrepareHifi, AverageEval); #elif defined(VISION_P6) @@ -146,7 +155,7 @@ TFLMRegistration Register_AVERAGE_POOL_2D() { } TFLMRegistration Register_MAX_POOL_2D() { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) return tflite::micro::RegisterOp(XtensaPoolingInit, MaxPrepareHifi, MaxEval); #elif defined(VISION_P6) return tflite::micro::RegisterOp(XtensaPoolingInit, MaxPoolingPrepareVision, diff --git a/tensorflow/lite/micro/kernels/xtensa/pooling_int16.cc b/tensorflow/lite/micro/kernels/xtensa/pooling_int16.cc new file mode 100644 index 00000000000..325c5234780 --- /dev/null +++ b/tensorflow/lite/micro/kernels/xtensa/pooling_int16.cc @@ -0,0 +1,125 @@ +/* Copyright 2023 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/pooling.h" +#include "tensorflow/lite/micro/kernels/xtensa/xtensa.h" +#include "tensorflow/lite/micro/kernels/xtensa/xtensa_pooling.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +TfLiteStatus AverageEvalQuantizedInt16Hifi(TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const XtensaOpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + TFLITE_DCHECK(input->type == kTfLiteInt16); + + const RuntimeShape& input_shape = tflite::micro::GetTensorShape(input); + const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + void* p_scratch = static_cast( + context->GetScratchBuffer(context, data->scratch_tensor_index)); + + const int16_t* inp_data_ptr = tflite::micro::GetTensorData(input); + int16_t* out_data_ptr = tflite::micro::GetTensorData(output); + + for (int batch = 0; batch < batches; ++batch) { + TF_LITE_ENSURE_EQ( + context, + xa_nn_avgpool_16( + &out_data_ptr[output_height * output_width * depth * batch], + const_cast( + &inp_data_ptr[output_height * output_width * depth * batch]), + input_height, input_width, depth, params->filter_height, + params->filter_width, params->stride_width, params->stride_height, + data->reference_op_data.padding.width, + data->reference_op_data.padding.height, output_height, output_width, + 0, 0, p_scratch), + 0); + } + + const int out_length = batches * output_height * output_width * depth; + TF_LITE_ENSURE_EQ( + context, + xa_nn_vec_activation_min_max_16_16( + out_data_ptr, out_data_ptr, data->reference_op_data.activation_min, + data->reference_op_data.activation_max, out_length), + 0); + + return kTfLiteOk; +} + +TfLiteStatus MaxEvalQuantizedInt16Hifi(TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const XtensaOpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + TFLITE_DCHECK(input->type == kTfLiteInt16); + + const RuntimeShape& input_shape = tflite::micro::GetTensorShape(input); + const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + void* p_scratch = static_cast( + context->GetScratchBuffer(context, data->scratch_tensor_index)); + + const int16_t* inp_data_ptr = tflite::micro::GetTensorData(input); + int16_t* out_data_ptr = tflite::micro::GetTensorData(output); + + for (int batch = 0; batch < batches; ++batch) { + TF_LITE_ENSURE_EQ( + context, + xa_nn_maxpool_16( + &out_data_ptr[output_height * output_width * depth * batch], + const_cast( + &inp_data_ptr[output_height * output_width * depth * batch]), + input_height, input_width, depth, params->filter_height, + params->filter_width, params->stride_width, params->stride_height, + data->reference_op_data.padding.width, + data->reference_op_data.padding.height, output_height, output_width, + 0, 0, p_scratch), + 0); + } + + const int out_length = batches * output_height * output_width * depth; + TF_LITE_ENSURE_EQ( + context, + xa_nn_vec_activation_min_max_16_16( + out_data_ptr, out_data_ptr, data->reference_op_data.activation_min, + data->reference_op_data.activation_max, out_length), + 0); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc b/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc index 84246d64507..a660875968b 100644 --- a/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc +++ b/tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc @@ -40,9 +40,9 @@ TfLiteStatus AverageEvalInt8(TfLiteContext* context, TfLiteNode* node) { // Inputs and outputs share the same type, guaranteed by the converter. switch (input->type) { case kTfLiteInt8: { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) auto* op_data = static_cast(node->user_data); - AverageEvalQuantizedHifi(context, node, params, op_data, input, output); + AverageEvalQuantizedInt8Hifi(context, node, params, op_data, input, output); #elif defined(VISION_P6) const auto& op_data = *(reinterpret_cast(node->user_data)); @@ -77,9 +77,9 @@ TfLiteStatus MaxEvalInt8(TfLiteContext* context, TfLiteNode* node) { switch (input->type) { case kTfLiteInt8: { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) auto* op_data = static_cast(node->user_data); - MaxEvalQuantizedHifi(context, node, params, op_data, input, output); + MaxEvalQuantizedInt8Hifi(context, node, params, op_data, input, output); #elif defined(VISION_P6) const auto& op_data = *(reinterpret_cast(node->user_data)); @@ -103,7 +103,7 @@ TfLiteStatus MaxEvalInt8(TfLiteContext* context, TfLiteNode* node) { } // namespace -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) TfLiteStatus AveragePrepareHifi(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_STATUS(PoolingPrepare(context, node)); @@ -111,45 +111,57 @@ TfLiteStatus AveragePrepareHifi(TfLiteContext* context, TfLiteNode* node) { TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, kPoolingInputTensor); - if (input->type == kTfLiteInt8) { - const RuntimeShape& input_shape = GetTensorShape(input); - TfLiteTensor* output = - micro_context->AllocateTempInputTensor(node, kPoolingOutputTensor); - const RuntimeShape& output_shape = GetTensorShape(output); - micro_context->DeallocateTempTfLiteTensor(output); - - const int depth = MatchingDim(input_shape, 3, output_shape, 3); - const int input_height = input_shape.Dims(1); - const int input_width = input_shape.Dims(2); - const int output_height = output_shape.Dims(1); - const int output_width = output_shape.Dims(2); + const RuntimeShape& input_shape = GetTensorShape(input); + TfLiteTensor* output = + micro_context->AllocateTempInputTensor(node, kPoolingOutputTensor); + const RuntimeShape& output_shape = GetTensorShape(output); + micro_context->DeallocateTempTfLiteTensor(output); - auto* params = reinterpret_cast(node->builtin_data); - auto* data = static_cast(node->user_data); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); - int required_scratch = xa_nn_avgpool_getsize( - depth, PREC_8, PREC_8, input_height, input_width, params->filter_height, - params->filter_width, - params->stride_width, // x_stride, - params->stride_height, // y_stride, - data->reference_op_data.padding.width, // x_padding, - data->reference_op_data.padding.height, // y_padding, - output_height, output_width, 0 /*NHWC input */, 0 /* NHWC output */); + auto* params = reinterpret_cast(node->builtin_data); + auto* data = static_cast(node->user_data); + int required_scratch = 0; + if (input->type == kTfLiteInt8) { + required_scratch = xa_nn_avgpool_getsize( + depth, PREC_8, PREC_8, input_height, input_width, params->filter_height, + params->filter_width, + params->stride_width, // x_stride, + params->stride_height, // y_stride, + data->reference_op_data.padding.width, // x_padding, + data->reference_op_data.padding.height, // y_padding, + output_height, output_width, 0 /*NHWC input */, 0 /* NHWC output */); + } + if (input->type == kTfLiteInt16) { + required_scratch = xa_nn_avgpool_getsize( + depth, PREC_16, PREC_16, input_height, input_width, params->filter_height, + params->filter_width, + params->stride_width, // x_stride, + params->stride_height, // y_stride, + data->reference_op_data.padding.width, // x_padding, + data->reference_op_data.padding.height, // y_padding, + output_height, output_width, 0 /*NHWC input */, 0 /* NHWC output */); + } + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { if (required_scratch <= 0) { MicroPrintf("Averagepool: xa_nn_avgpool_getsize failed"); return kTfLiteError; } - TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( - context, required_scratch, &(data->scratch_tensor_index))); + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, required_scratch, &(data->scratch_tensor_index))); } micro_context->DeallocateTempTfLiteTensor(input); return kTfLiteOk; } -TfLiteStatus AverageEvalQuantizedHifi(TfLiteContext* context, +TfLiteStatus AverageEvalQuantizedInt8Hifi(TfLiteContext* context, const TfLiteNode* node, const TfLitePoolParams* params, const XtensaOpDataPooling* data, @@ -186,7 +198,6 @@ TfLiteStatus AverageEvalQuantizedHifi(TfLiteContext* context, 0, 0, p_scratch), 0); } - const int out_length = batches * output_height * output_width * depth; TF_LITE_ENSURE_EQ( context, @@ -194,7 +205,6 @@ TfLiteStatus AverageEvalQuantizedHifi(TfLiteContext* context, out_data_ptr, out_data_ptr, data->reference_op_data.activation_min, data->reference_op_data.activation_max, out_length), 0); - return kTfLiteOk; } @@ -206,7 +216,7 @@ TfLiteStatus MaxPrepareHifi(TfLiteContext* context, TfLiteNode* node) { TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, kPoolingInputTensor); - if (input->type == kTfLiteInt8) { + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { auto* params = reinterpret_cast(node->builtin_data); auto* data = static_cast(node->user_data); @@ -221,15 +231,27 @@ TfLiteStatus MaxPrepareHifi(TfLiteContext* context, TfLiteNode* node) { const int input_width = input_shape.Dims(2); const int output_height = output_shape.Dims(1); const int output_width = output_shape.Dims(2); - - int required_scratch = xa_nn_maxpool_getsize( - depth, PREC_8, PREC_8, input_height, input_width, params->filter_height, - params->filter_width, - params->stride_width, // x_stride, - params->stride_height, // y_stride, - data->reference_op_data.padding.width, // x_padding, - data->reference_op_data.padding.height, // y_padding, - output_height, output_width, 0 /* NHWC inpput */, 0 /* NHWC output */); + int required_scratch = 0; + if (input->type == kTfLiteInt8){ + required_scratch = xa_nn_maxpool_getsize( + depth, PREC_8, PREC_8, input_height, input_width, params->filter_height, + params->filter_width, + params->stride_width, // x_stride, + params->stride_height, // y_stride, + data->reference_op_data.padding.width, // x_padding, + data->reference_op_data.padding.height, // y_padding, + output_height, output_width, 0 /* NHWC inpput */, 0 /* NHWC output */); + } + if(input->type == kTfLiteInt16){ + required_scratch = xa_nn_maxpool_getsize( + depth, PREC_16, PREC_16, input_height, input_width, params->filter_height, + params->filter_width, + params->stride_width, // x_stride, + params->stride_height, // y_stride, + data->reference_op_data.padding.width, // x_padding, + data->reference_op_data.padding.height, // y_padding, + output_height, output_width, 0 /* NHWC inpput */, 0 /* NHWC output */); + } if (required_scratch <= 0) { MicroPrintf("Maxpool: xa_nn_maxpool_getsize failed"); @@ -244,7 +266,7 @@ TfLiteStatus MaxPrepareHifi(TfLiteContext* context, TfLiteNode* node) { return kTfLiteOk; } -TfLiteStatus MaxEvalQuantizedHifi(TfLiteContext* context, TfLiteNode* node, +TfLiteStatus MaxEvalQuantizedInt8Hifi(TfLiteContext* context, TfLiteNode* node, TfLitePoolParams* params, const XtensaOpDataPooling* data, const TfLiteEvalTensor* input, @@ -278,7 +300,6 @@ TfLiteStatus MaxEvalQuantizedHifi(TfLiteContext* context, TfLiteNode* node, 0, 0, p_scratch), 0); } - const int out_length = batches * output_height * output_width * depth; TF_LITE_ENSURE_EQ( context, @@ -290,12 +311,12 @@ TfLiteStatus MaxEvalQuantizedHifi(TfLiteContext* context, TfLiteNode* node, return kTfLiteOk; } -#endif // defined(HIFI5) +#endif // defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) void* XtensaPoolingInit(TfLiteContext* context, const char* buffer, size_t length) { TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) return context->AllocatePersistentBuffer(context, sizeof(XtensaOpDataPooling)); #elif defined(VISION_P6) @@ -310,7 +331,7 @@ void* XtensaPoolingInit(TfLiteContext* context, const char* buffer, } TFLMRegistration Register_AVERAGE_POOL_2D_INT8() { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) return tflite::micro::RegisterOp(XtensaPoolingInit, AveragePrepareHifi, AverageEvalInt8); #elif defined(VISION_P6) @@ -323,7 +344,7 @@ TFLMRegistration Register_AVERAGE_POOL_2D_INT8() { } TFLMRegistration Register_MAX_POOL_2D_INT8() { -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) return tflite::micro::RegisterOp(XtensaPoolingInit, MaxPrepareHifi, MaxEvalInt8); #elif defined(VISION_P6) diff --git a/tensorflow/lite/micro/kernels/xtensa/xtensa_pooling.h b/tensorflow/lite/micro/kernels/xtensa/xtensa_pooling.h index a2346e3a8c8..215c8e7439d 100644 --- a/tensorflow/lite/micro/kernels/xtensa/xtensa_pooling.h +++ b/tensorflow/lite/micro/kernels/xtensa/xtensa_pooling.h @@ -31,9 +31,9 @@ struct XtensaOpDataPooling { uint32_t context_size; #endif // defined(VISION_P6) -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) int scratch_tensor_index; -#endif // defined(HIFI5) +#endif // defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) }; #if defined(VISION_P6) @@ -49,10 +49,17 @@ TfLiteStatus PoolEvalVision(TfLiteContext* context, TfLiteNode* node, TfLiteEvalTensor* output); #endif -#if defined(HIFI5) +#if defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) TfLiteStatus AveragePrepareHifi(TfLiteContext* context, TfLiteNode* node); -TfLiteStatus AverageEvalQuantizedHifi(TfLiteContext* context, +TfLiteStatus AverageEvalQuantizedInt8Hifi(TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const XtensaOpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +TfLiteStatus AverageEvalQuantizedInt16Hifi(TfLiteContext* context, const TfLiteNode* node, const TfLitePoolParams* params, const XtensaOpDataPooling* data, @@ -60,13 +67,20 @@ TfLiteStatus AverageEvalQuantizedHifi(TfLiteContext* context, TfLiteEvalTensor* output); TfLiteStatus MaxPrepareHifi(TfLiteContext* context, TfLiteNode* node); -TfLiteStatus MaxEvalQuantizedHifi(TfLiteContext* context, TfLiteNode* node, +TfLiteStatus MaxEvalQuantizedInt8Hifi(TfLiteContext* context, TfLiteNode* node, TfLitePoolParams* params, const XtensaOpDataPooling* data, const TfLiteEvalTensor* input, TfLiteEvalTensor* output); -#endif // defined(HIFI5) +TfLiteStatus MaxEvalQuantizedInt16Hifi(TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const XtensaOpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +#endif // defined(HIFI4) || defined(HIFI5) || defined(HIFI_IQ) void* XtensaPoolingInit(TfLiteContext* context, const char* buffer, size_t length); diff --git a/tensorflow/lite/micro/tools/make/targets/xtensa_makefile.inc b/tensorflow/lite/micro/tools/make/targets/xtensa_makefile.inc index 78d3dce16dc..206092daaa3 100644 --- a/tensorflow/lite/micro/tools/make/targets/xtensa_makefile.inc +++ b/tensorflow/lite/micro/tools/make/targets/xtensa_makefile.inc @@ -127,6 +127,7 @@ ifeq ($(OPTIMIZED_KERNEL_DIR), xtensa) $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/lstm_eval_hifi.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/pad_vision.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/pooling_int8.cc \ + $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/pooling_int16.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/pooling_vision.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/reduce_vision.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/xtensa/reshape_vision.cc \