Add QUANT8_ASYMM_SIGNED support to SELECT op

Bug: 143935354
Test: NNTest_static and VTS_1_3  with --gtest_filter="*select*"
Change-Id: Ifc8ae06d412d4b50421a4e2dce39b223723a137a
Merged-In: Ifc8ae06d412d4b50421a4e2dce39b223723a137a
(cherry picked from commit 29c9adde6ec7ea99c98b6d796c5a79c19dea8701)
diff --git a/common/OperationsUtils.cpp b/common/OperationsUtils.cpp
index 5c50e3d..5c251a2 100644
--- a/common/OperationsUtils.cpp
+++ b/common/OperationsUtils.cpp
@@ -17,12 +17,16 @@
 #define LOG_TAG "OperationsUtils"
 
 #include "OperationsUtils.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <sstream>
+#include <vector>
+
 #include "Operations.h"
 #include "Utils.h"
 
-#include <cmath>
-#include <sstream>
-
 namespace android {
 namespace nn {
 
@@ -355,6 +359,14 @@
     return static_cast<uint8_t>(std::round(doubleRet));
 }
 
+int8_t requantize(int8_t value, const Shape& oldShape, const Shape& newShape) {
+    double doubleValue = (value - oldShape.offset) * oldShape.scale;
+    double doubleRet = doubleValue / newShape.scale + newShape.offset;
+    if (doubleRet < -128) return -128;
+    if (doubleRet > 127) return 127;
+    return static_cast<int8_t>(std::round(doubleRet));
+}
+
 bool floorPrepare(const Shape& input, Shape* output) {
     return SetShape(input, output);
 }
diff --git a/common/operations/Select.cpp b/common/operations/Select.cpp
index e9b6645..b46e6af 100644
--- a/common/operations/Select.cpp
+++ b/common/operations/Select.cpp
@@ -47,7 +47,8 @@
     for (uint32_t i = 0; i < size; ++i) {
         T a = aData[i];
         T b = bData[i];
-        if (aShape.type == OperandType::TENSOR_QUANT8_ASYMM) {
+        if (aShape.type == OperandType::TENSOR_QUANT8_ASYMM ||
+            aShape.type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) {
             a = requantize(a, aShape, outputShape);
             b = requantize(b, bShape, outputShape);
         }
@@ -72,9 +73,11 @@
     NN_RET_CHECK_EQ(context->getNumInputs(), kNumInputs);
     NN_RET_CHECK_EQ(context->getNumOutputs(), kNumOutputs);
     OperandType inputType = context->getInputType(kInputTensor1);
-    NN_RET_CHECK(
-            inputType == OperandType::TENSOR_FLOAT16 || inputType == OperandType::TENSOR_FLOAT32 ||
-            inputType == OperandType::TENSOR_INT32 || inputType == OperandType::TENSOR_QUANT8_ASYMM)
+    NN_RET_CHECK(inputType == OperandType::TENSOR_FLOAT16 ||
+                 inputType == OperandType::TENSOR_FLOAT32 ||
+                 inputType == OperandType::TENSOR_INT32 ||
+                 inputType == OperandType::TENSOR_QUANT8_ASYMM ||
+                 inputType == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)
             << "Unsupported input operand type for select op: " << toString(inputType);
     NN_RET_CHECK(validateInputTypes(context, {OperandType::TENSOR_BOOL8, inputType, inputType}));
     NN_RET_CHECK(validateOutputTypes(context, {inputType}));
@@ -113,6 +116,8 @@
             return executeTyped<int32_t>(context);
         case OperandType::TENSOR_QUANT8_ASYMM:
             return executeTyped<uint8_t>(context);
+        case OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
+            return executeTyped<int8_t>(context);
         default:
             NN_RET_CHECK_FAIL() << "Unsupported tensor type for SELECT op.";
     }