1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "Operations" 18 19 #include "Cast.h" 20 #include "Tracing.h" 21 22 namespace android { 23 namespace nn { 24 namespace cast { 25 26 namespace { 27 28 template <typename FromT, typename ToT> 29 void copyCast(const FromT* in, ToT* out, int numElements) { 30 std::transform(in, in + numElements, out, [](FromT a) -> ToT { 31 if constexpr (std::is_same_v<ToT, uint8_t>) { 32 if (a < 0) return 0; 33 if (a > 255) return 255; 34 } 35 return static_cast<ToT>(a); 36 }); 37 } 38 39 template <typename FromT> 40 bool copyToTensor(const FromT* inputData, int numElements, uint8_t* outputData, 41 const Shape& outputShape) { 42 #define ANDROID_NN_COPY_CAST(operandType, dataType) \ 43 case operandType: { \ 44 NNTRACE_COMP("cast::copyCast::" #dataType); \ 45 copyCast(inputData, reinterpret_cast<dataType*>(outputData), numElements); \ 46 return true; \ 47 } 48 49 switch (outputShape.type) { 50 ANDROID_NN_COPY_CAST(OperandType::TENSOR_FLOAT16, _Float16); 51 ANDROID_NN_COPY_CAST(OperandType::TENSOR_FLOAT32, float); 52 ANDROID_NN_COPY_CAST(OperandType::TENSOR_INT32, int32_t); 53 ANDROID_NN_COPY_CAST(OperandType::TENSOR_QUANT8_ASYMM, uint8_t); 54 default: 55 LOG(ERROR) << "Unsupported CAST output type"; 56 return false; 57 } 58 #undef ANDROID_NN_COPY_CAST 59 } 60 61 } // namespace 62 63 bool prepare(const Shape& input, Shape* output) { 64 if (input.dimensions.size() != output->dimensions.size()) { 65 return false; 66 } 67 output->dimensions = input.dimensions; 68 return true; 69 } 70 71 bool eval(const uint8_t* inputData, const Shape& inputShape, uint8_t* outputData, 72 const Shape& outputShape) { 73 NNTRACE_TRANS("cast::eval"); 74 int numElements = getNumberOfElements(inputShape); 75 76 #define ANDROID_NN_COPY_TO_TENSOR(operandType, dataType) \ 77 case operandType: { \ 78 NNTRACE_TRANS("cast::copyToTensor::" #dataType); \ 79 copyToTensor(reinterpret_cast<const dataType*>(inputData), numElements, outputData, \ 80 outputShape); \ 81 return true; \ 82 } 83 84 switch (inputShape.type) { 85 ANDROID_NN_COPY_TO_TENSOR(OperandType::TENSOR_FLOAT16, _Float16); 86 ANDROID_NN_COPY_TO_TENSOR(OperandType::TENSOR_FLOAT32, float); 87 ANDROID_NN_COPY_TO_TENSOR(OperandType::TENSOR_INT32, int32_t); 88 ANDROID_NN_COPY_TO_TENSOR(OperandType::TENSOR_QUANT8_ASYMM, uint8_t); 89 default: 90 LOG(ERROR) << "Unsupported CAST input type"; 91 return false; 92 } 93 #undef ANDROID_NN_COPY_TO_TENSOR 94 } 95 96 } // namespace cast 97 } // namespace nn 98 } // namespace android 99