1 /*
2 * Copyright (C) 2017 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 "Utils"
18
19 #include "LegacyHalUtils.h"
20
21 #include <nnapi/TypeUtils.h>
22 #include <nnapi/hal/1.0/Conversions.h>
23 #include <nnapi/hal/1.1/Conversions.h>
24 #include <nnapi/hal/1.2/Conversions.h>
25 #include <nnapi/hal/1.3/Conversions.h>
26
27 #include <algorithm>
28 #include <limits>
29 #include <set>
30 #include <string>
31 #include <tuple>
32 #include <type_traits>
33 #include <utility>
34 #include <vector>
35
36 #include "CpuExecutor.h"
37 #include "NeuralNetworks.h"
38 #include "ValidateHal.h"
39
40 namespace android {
41 namespace nn {
42
43 constexpr V1_0::PerformanceInfo kNoPerformanceInfo = {
44 .execTime = std::numeric_limits<float>::max(),
45 .powerUsage = std::numeric_limits<float>::max()};
46
47 template <typename Type>
handleError(GeneralResult<Type> result)48 static Type handleError(GeneralResult<Type> result) {
49 CHECK(result.has_value()) << "Unhandled error (" << result.error().code
50 << "): " << result.error().message;
51 return std::move(result).value();
52 }
53
makeDeadline(const V1_3::OptionalTimePoint & timePoint)54 LegacyOptionalTimePoint makeDeadline(const V1_3::OptionalTimePoint& timePoint) {
55 using Disc = V1_3::OptionalTimePoint::hidl_discriminator;
56 if (timePoint.getDiscriminator() == Disc::none) {
57 return LegacyOptionalTimePoint{};
58 }
59 const uint64_t count = timePoint.nanosecondsSinceEpoch();
60 return LegacyTimePoint{LegacyDuration{count}};
61 }
62
makeDeadline(const V1_3::OptionalTimeoutDuration & optionalDuration)63 LegacyOptionalTimePoint makeDeadline(const V1_3::OptionalTimeoutDuration& optionalDuration) {
64 if (optionalDuration.getDiscriminator() ==
65 V1_3::OptionalTimeoutDuration::hidl_discriminator::none) {
66 return LegacyOptionalTimePoint{};
67 }
68
69 const auto duration = LegacyDuration{optionalDuration.nanoseconds()};
70 constexpr auto kMaxTime = LegacyTimePoint::max();
71 const auto currentTime = LegacyClock::now();
72
73 // If there would be an overflow, use the max value.
74 if (duration > kMaxTime - currentTime) {
75 return kMaxTime;
76 }
77 return currentTime + duration;
78 }
79
hasDeadlinePassed(const LegacyOptionalTimePoint & deadline)80 bool hasDeadlinePassed(const LegacyOptionalTimePoint& deadline) {
81 if (!deadline.has_value()) {
82 return false;
83 }
84 return LegacyClock::now() >= *deadline;
85 }
86
isExtensionOperandType(V1_3::OperandType type)87 bool isExtensionOperandType(V1_3::OperandType type) {
88 return isExtensionOperandType(static_cast<OperandType>(type));
89 }
90
isExtensionOperationType(V1_3::OperationType type)91 bool isExtensionOperationType(V1_3::OperationType type) {
92 return isExtensionOperationType(static_cast<OperationType>(type));
93 }
94
getOperandTypeName(V1_3::OperandType type)95 std::string getOperandTypeName(V1_3::OperandType type) {
96 return toString(type);
97 }
98
getOperationName(V1_3::OperationType type)99 std::string getOperationName(V1_3::OperationType type) {
100 return toString(type);
101 }
102
nonExtensionOperandSizeOfData(V1_3::OperandType type,const std::vector<uint32_t> & dimensions)103 uint32_t nonExtensionOperandSizeOfData(V1_3::OperandType type,
104 const std::vector<uint32_t>& dimensions) {
105 return nonExtensionOperandSizeOfData(uncheckedConvert(type), dimensions);
106 }
107
nonExtensionOperandSizeOfDataOverflowsUInt32(V1_3::OperandType type,const std::vector<uint32_t> & dimensions)108 bool nonExtensionOperandSizeOfDataOverflowsUInt32(V1_3::OperandType type,
109 const std::vector<uint32_t>& dimensions) {
110 return nonExtensionOperandSizeOfDataOverflowsUInt32(uncheckedConvert(type), dimensions);
111 }
112
tensorHasUnspecifiedDimensions(V1_3::OperandType type,const std::vector<uint32_t> & dimensions)113 bool tensorHasUnspecifiedDimensions(V1_3::OperandType type,
114 const std::vector<uint32_t>& dimensions) {
115 return tensorHasUnspecifiedDimensions(static_cast<int>(type), dimensions.data(),
116 dimensions.size());
117 }
118
tensorHasUnspecifiedDimensions(const V1_3::Operand & operand)119 bool tensorHasUnspecifiedDimensions(const V1_3::Operand& operand) {
120 return tensorHasUnspecifiedDimensions(static_cast<int>(operand.type), operand.dimensions.data(),
121 operand.dimensions.size());
122 }
123
logModelToInfo(const V1_0::Model & model)124 void logModelToInfo(const V1_0::Model& model) {
125 LOG(INFO) << "V1_0::Model start";
126 LOG(INFO) << "operands" << toString(model.operands);
127 LOG(INFO) << "operations" << toString(model.operations);
128 LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
129 LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
130 LOG(INFO) << "operandValues size" << model.operandValues.size();
131 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
132 }
133
logModelToInfo(const V1_1::Model & model)134 void logModelToInfo(const V1_1::Model& model) {
135 LOG(INFO) << "V1_1::Model start";
136 LOG(INFO) << "operands" << toString(model.operands);
137 LOG(INFO) << "operations" << toString(model.operations);
138 LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
139 LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
140 LOG(INFO) << "operandValues size " << model.operandValues.size();
141 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
142 }
143
logModelToInfo(const V1_2::Model & model)144 void logModelToInfo(const V1_2::Model& model) {
145 LOG(INFO) << "V1_2::Model start";
146 LOG(INFO) << "operands" << toString(model.operands);
147 LOG(INFO) << "operations" << toString(model.operations);
148 LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
149 LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
150 LOG(INFO) << "operandValues size" << model.operandValues.size();
151 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
152 LOG(INFO) << "relaxComputationFloat32toFloat16" << model.relaxComputationFloat32toFloat16;
153 LOG(INFO) << "extensionNameToPrefix" << toString(model.extensionNameToPrefix);
154 }
155
logSubgraphToInfo(std::string label,const V1_3::Subgraph & subgraph)156 static void logSubgraphToInfo(std::string label, const V1_3::Subgraph& subgraph) {
157 LOG(INFO) << label << ".operands" << toString(subgraph.operands);
158 LOG(INFO) << label << ".operations" << toString(subgraph.operations);
159 LOG(INFO) << label << ".inputIndexes" << toString(subgraph.inputIndexes);
160 LOG(INFO) << label << ".outputIndexes" << toString(subgraph.outputIndexes);
161 }
162
logModelToInfo(const V1_3::Model & model)163 void logModelToInfo(const V1_3::Model& model) {
164 LOG(INFO) << "V1_3::Model start";
165 logSubgraphToInfo("main", model.main);
166 for (uint32_t i = 0, n = model.referenced.size(); i < n; ++i) {
167 logSubgraphToInfo("referenced[" + std::to_string(i) + "]", model.referenced[i]);
168 }
169 LOG(INFO) << "operandValues size " << model.operandValues.size();
170 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
171 LOG(INFO) << "relaxComputationFloat32toFloat16 " << model.relaxComputationFloat32toFloat16;
172 LOG(INFO) << "extensionNameToPrefix" << toString(model.extensionNameToPrefix);
173 }
174
validateOperandSymmPerChannelQuantParams(const V1_3::Operand & halOperand,const ANeuralNetworksSymmPerChannelQuantParams & channelQuant,const char * tag)175 bool validateOperandSymmPerChannelQuantParams(
176 const V1_3::Operand& halOperand,
177 const ANeuralNetworksSymmPerChannelQuantParams& channelQuant, const char* tag) {
178 if (halOperand.type != V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
179 return false;
180 }
181
182 NN_RET_CHECK_LT(channelQuant.channelDim, halOperand.dimensions.size()) << tag;
183 NN_RET_CHECK(channelQuant.scales != nullptr) << tag;
184 NN_RET_CHECK_EQ(channelQuant.scaleCount, halOperand.dimensions[channelQuant.channelDim]) << tag;
185 NN_RET_CHECK_NE(halOperand.dimensions[channelQuant.channelDim], 0u)
186 << tag << " channel dimension " << channelQuant.channelDim << " is underspecified";
187 for (uint32_t i = 0; i < halOperand.dimensions[channelQuant.channelDim]; i++) {
188 NN_RET_CHECK_GT(channelQuant.scales[i], 0.0f) << tag << " invalid scaleArray[" << i << "]";
189 }
190 return true;
191 }
192
validateHalVersion(ANeuralNetworksOperationType opType,HalVersion halVersion,HalVersion minSupportedHalVersion)193 static int validateHalVersion(ANeuralNetworksOperationType opType, HalVersion halVersion,
194 HalVersion minSupportedHalVersion) {
195 if (halVersion < minSupportedHalVersion) {
196 LOG(ERROR) << "The given inputs and outputs for operation " << opType
197 << " are only supported in " << minSupportedHalVersion
198 << " and later (validating using " << halVersion << ")";
199 return ANEURALNETWORKS_BAD_DATA;
200 }
201 return ANEURALNETWORKS_NO_ERROR;
202 }
203
validateOperation(ANeuralNetworksOperationType opType,uint32_t inputCount,const uint32_t * inputIndexes,uint32_t outputCount,const uint32_t * outputIndexes,const std::vector<Operand> & operands,HalVersion halVersion)204 static inline int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount,
205 const uint32_t* inputIndexes, uint32_t outputCount,
206 const uint32_t* outputIndexes,
207 const std::vector<Operand>& operands, HalVersion halVersion) {
208 if (opType == ANEURALNETWORKS_IF || opType == ANEURALNETWORKS_WHILE) {
209 NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_3));
210 LOG(ERROR) << "This validateOperation() overload does not support control flow";
211 return ANEURALNETWORKS_BAD_DATA;
212 }
213 return validateOperation(opType, inputCount, inputIndexes, outputCount, outputIndexes, operands,
214 halVersion, {});
215 }
216
convertResultCodeToHalErrorStatus(int resultCode)217 V1_3::ErrorStatus convertResultCodeToHalErrorStatus(int resultCode) {
218 return convertToV1_3(convertResultCodeToErrorStatus(resultCode));
219 }
220
convertErrorStatusToResultCode(V1_3::ErrorStatus status)221 int convertErrorStatusToResultCode(V1_3::ErrorStatus status) {
222 return convertErrorStatusToResultCode(uncheckedConvert(status));
223 }
224
getExecutionResult(V1_3::ErrorStatus status,const hardware::hidl_vec<V1_2::OutputShape> & outputShapes,const V1_2::Timing & timing)225 std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult(
226 V1_3::ErrorStatus status, const hardware::hidl_vec<V1_2::OutputShape>& outputShapes,
227 const V1_2::Timing& timing) {
228 return getExecutionResult(uncheckedConvert(status), uncheckedConvert(outputShapes),
229 uncheckedConvert(timing));
230 }
231
232 // Capabilities::operandPerformance utilities.
233 // The field Capabilities::operandPerformance is a vector sorted by the field
234 // Capabilities::OperandPerformance::type.
235
236 template <HalVersion version>
nonExtensionOperandPerformance(V1_0::PerformanceInfo perf)237 hardware::hidl_vec<VersionedOperandPerformance<version>> nonExtensionOperandPerformance(
238 V1_0::PerformanceInfo perf) {
239 using OpPerf = VersionedOperandPerformance<version>;
240
241 // Note: range presents enumerators in declaration order, not in numerical order.
242 static constexpr hardware::hidl_enum_range<VersionedOperandType<version>> kOperandTypeRange;
243
244 std::vector<OpPerf> ret;
245 ret.reserve(kOperandTypeRange.end() - kOperandTypeRange.begin());
246 for (VersionedOperandType<version> type : kOperandTypeRange) {
247 if (static_cast<V1_3::OperandType>(type) != V1_3::OperandType::SUBGRAPH) {
248 ret.push_back(OpPerf{type, perf});
249 }
250 }
251 std::sort(ret.begin(), ret.end(),
252 [](const OpPerf& a, const OpPerf& b) { return a.type < b.type; });
253
254 return ret;
255 }
256
257 template hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>
258 nonExtensionOperandPerformance<HalVersion::V1_2>(V1_0::PerformanceInfo perf);
259 template hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>
260 nonExtensionOperandPerformance<HalVersion::V1_3>(V1_0::PerformanceInfo perf);
261
262 template <HalVersion version>
update(hardware::hidl_vec<VersionedOperandPerformance<version>> * operandPerformance,VersionedOperandType<version> type,V1_0::PerformanceInfo perf)263 void update(hardware::hidl_vec<VersionedOperandPerformance<version>>* operandPerformance,
264 VersionedOperandType<version> type, V1_0::PerformanceInfo perf) {
265 CHECK(operandPerformance != nullptr);
266 const auto it =
267 std::lower_bound(operandPerformance->begin(), operandPerformance->end(), type,
268 [](const VersionedOperandPerformance<version>& perf,
269 VersionedOperandType<version> type) { return perf.type < type; });
270 CHECK(it != operandPerformance->end())
271 << toString(type) << " not in " << toString(*operandPerformance);
272 it->info = perf;
273 }
274
update(hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> * operandPerformance,V1_2::OperandType type,V1_0::PerformanceInfo perf)275 void update(hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>* operandPerformance,
276 V1_2::OperandType type, V1_0::PerformanceInfo perf) {
277 update<HalVersion::V1_2>(operandPerformance, type, perf);
278 }
update(hardware::hidl_vec<V1_3::Capabilities::OperandPerformance> * operandPerformance,V1_3::OperandType type,V1_0::PerformanceInfo perf)279 void update(hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>* operandPerformance,
280 V1_3::OperandType type, V1_0::PerformanceInfo perf) {
281 update<HalVersion::V1_3>(operandPerformance, type, perf);
282 }
283
284 template <HalVersion version>
lookup(const hardware::hidl_vec<VersionedOperandPerformance<version>> & operandPerformance,VersionedOperandType<version> type)285 V1_0::PerformanceInfo lookup(
286 const hardware::hidl_vec<VersionedOperandPerformance<version>>& operandPerformance,
287 VersionedOperandType<version> type) {
288 const auto it = std::lower_bound(operandPerformance.begin(), operandPerformance.end(), type,
289 [](const VersionedOperandPerformance<version>& perf,
290 VersionedOperandType<version> type) {
291 return static_cast<V1_3::OperandType>(perf.type) <
292 static_cast<V1_3::OperandType>(type);
293 });
294 if (it == operandPerformance.end()) {
295 LOG(WARNING) << "No PerformanceInfo for " << toString(type);
296 return kNoPerformanceInfo;
297 } else {
298 return it->info;
299 }
300 }
301
lookup(const hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> & operandPerformance,V1_2::OperandType type)302 V1_0::PerformanceInfo lookup(
303 const hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>& operandPerformance,
304 V1_2::OperandType type) {
305 return lookup<HalVersion::V1_2>(operandPerformance, type);
306 }
lookup(const hardware::hidl_vec<V1_3::Capabilities::OperandPerformance> & operandPerformance,V1_3::OperandType type)307 V1_0::PerformanceInfo lookup(
308 const hardware::hidl_vec<V1_3::Capabilities::OperandPerformance>& operandPerformance,
309 V1_3::OperandType type) {
310 CHECK(type != V1_3::OperandType::SUBGRAPH)
311 << "Use Capabilities::ifPerformance or Capabilities::whilePerformance";
312 return lookup<HalVersion::V1_3>(operandPerformance, type);
313 }
314
setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo> * poolInfos,const hardware::hidl_vec<hardware::hidl_memory> & pools)315 bool setRunTimePoolInfosFromHidlMemories(std::vector<RunTimePoolInfo>* poolInfos,
316 const hardware::hidl_vec<hardware::hidl_memory>& pools) {
317 return setRunTimePoolInfosFromCanonicalMemories(poolInfos, uncheckedConvert(pools));
318 }
319
320 // Versioning
321
322 // In Android P, most data types are treated as having the same performance as TENSOR_QUANT8_ASYMM.
323 // This array must be in sorted order.
324 static const V1_3::OperandType kQuantized8PerformanceConsistentWithP[] = {
325 V1_3::OperandType::INT32, V1_3::OperandType::UINT32, V1_3::OperandType::TENSOR_INT32,
326 V1_3::OperandType::OEM, V1_3::OperandType::TENSOR_OEM_BYTE};
327
isQuantized8PerformanceConsistentWithP(const V1_2::Capabilities & capabilities)328 static bool isQuantized8PerformanceConsistentWithP(const V1_2::Capabilities& capabilities) {
329 const V1_0::PerformanceInfo quantized8Performance =
330 lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_ASYMM);
331 return std::all_of(std::begin(kQuantized8PerformanceConsistentWithP),
332 std::end(kQuantized8PerformanceConsistentWithP),
333 [quantized8Performance, &capabilities](V1_3::OperandType type) {
334 return quantized8Performance ==
335 lookup(capabilities.operandPerformance,
336 static_cast<V1_2::OperandType>(type));
337 });
338 }
339
isQuantized8PerformanceConsistentWithP(const V1_3::Capabilities & capabilities)340 static bool isQuantized8PerformanceConsistentWithP(const V1_3::Capabilities& capabilities) {
341 const V1_0::PerformanceInfo quantized8Performance =
342 lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM);
343 return std::all_of(std::begin(kQuantized8PerformanceConsistentWithP),
344 std::end(kQuantized8PerformanceConsistentWithP),
345 [quantized8Performance, &capabilities](V1_3::OperandType type) {
346 return quantized8Performance ==
347 lookup(capabilities.operandPerformance, type);
348 });
349 }
350
351 static hardware::hidl_vec<V1_2::Capabilities::OperandPerformance>
makeQuantized8PerformanceConsistentWithP(V1_0::PerformanceInfo quantized8Performance)352 makeQuantized8PerformanceConsistentWithP(V1_0::PerformanceInfo quantized8Performance) {
353 hardware::hidl_vec<V1_2::Capabilities::OperandPerformance> ret(
354 std::size(kQuantized8PerformanceConsistentWithP));
355 std::transform(std::begin(kQuantized8PerformanceConsistentWithP),
356 std::end(kQuantized8PerformanceConsistentWithP), ret.begin(),
357 [quantized8Performance](
358 V1_3::OperandType type) -> V1_2::Capabilities::OperandPerformance {
359 return {static_cast<V1_2::OperandType>(type), quantized8Performance};
360 });
361 return ret;
362 }
363
compliantWithV1_0(const V1_0::Capabilities &)364 bool compliantWithV1_0(const V1_0::Capabilities&) {
365 return true;
366 }
367
compliantWithV1_0(const V1_1::Capabilities & capabilities)368 bool compliantWithV1_0(const V1_1::Capabilities& capabilities) {
369 return capabilities.relaxedFloat32toFloat16Performance == capabilities.float32Performance;
370 }
371
compliantWithV1_0(const V1_2::Capabilities & capabilities)372 bool compliantWithV1_0(const V1_2::Capabilities& capabilities) {
373 const V1_0::PerformanceInfo perfTensorFloat32 =
374 lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32);
375 const V1_0::PerformanceInfo perfFloat32 =
376 lookup(capabilities.operandPerformance, V1_2::OperandType::FLOAT32);
377 if (perfTensorFloat32 != perfFloat32 ||
378 perfTensorFloat32 != capabilities.relaxedFloat32toFloat16PerformanceTensor ||
379 perfFloat32 != capabilities.relaxedFloat32toFloat16PerformanceScalar) {
380 return false;
381 }
382
383 return isQuantized8PerformanceConsistentWithP(capabilities);
384 }
385
compliantWithV1_0(const V1_3::Capabilities & capabilities)386 bool compliantWithV1_0(const V1_3::Capabilities& capabilities) {
387 const V1_0::PerformanceInfo perfTensorFloat32 =
388 lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32);
389 const V1_0::PerformanceInfo perfFloat32 =
390 lookup(capabilities.operandPerformance, V1_3::OperandType::FLOAT32);
391 if (perfTensorFloat32 != perfFloat32 ||
392 perfTensorFloat32 != capabilities.relaxedFloat32toFloat16PerformanceTensor ||
393 perfFloat32 != capabilities.relaxedFloat32toFloat16PerformanceScalar) {
394 return false;
395 }
396
397 return isQuantized8PerformanceConsistentWithP(capabilities);
398 }
399
compliantWithV1_1(const V1_0::Capabilities &)400 bool compliantWithV1_1(const V1_0::Capabilities&) {
401 return true;
402 }
403
compliantWithV1_1(const V1_1::Capabilities &)404 bool compliantWithV1_1(const V1_1::Capabilities&) {
405 return true;
406 }
407
compliantWithV1_1(const V1_2::Capabilities & capabilities)408 bool compliantWithV1_1(const V1_2::Capabilities& capabilities) {
409 if ((capabilities.relaxedFloat32toFloat16PerformanceTensor !=
410 capabilities.relaxedFloat32toFloat16PerformanceScalar) ||
411 (lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32) !=
412 lookup(capabilities.operandPerformance, V1_2::OperandType::FLOAT32))) {
413 return false;
414 }
415
416 return isQuantized8PerformanceConsistentWithP(capabilities);
417 }
418
compliantWithV1_1(const V1_3::Capabilities & capabilities)419 bool compliantWithV1_1(const V1_3::Capabilities& capabilities) {
420 if ((capabilities.relaxedFloat32toFloat16PerformanceTensor !=
421 capabilities.relaxedFloat32toFloat16PerformanceScalar) ||
422 (lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32) !=
423 lookup(capabilities.operandPerformance, V1_3::OperandType::FLOAT32))) {
424 return false;
425 }
426
427 return isQuantized8PerformanceConsistentWithP(capabilities);
428 }
429
compliantWithV1_2(const V1_0::Capabilities &)430 bool compliantWithV1_2(const V1_0::Capabilities&) {
431 return true;
432 }
433
compliantWithV1_2(const V1_1::Capabilities &)434 bool compliantWithV1_2(const V1_1::Capabilities&) {
435 return true;
436 }
437
compliantWithV1_2(const V1_2::Capabilities &)438 bool compliantWithV1_2(const V1_2::Capabilities&) {
439 return true;
440 }
441
compliantWithV1_2(const V1_3::Capabilities &)442 bool compliantWithV1_2(const V1_3::Capabilities&) {
443 return true;
444 }
445
compliantWithV1_3(const V1_0::Capabilities &)446 bool compliantWithV1_3(const V1_0::Capabilities&) {
447 return true;
448 }
449
compliantWithV1_3(const V1_1::Capabilities &)450 bool compliantWithV1_3(const V1_1::Capabilities&) {
451 return true;
452 }
453
compliantWithV1_3(const V1_2::Capabilities &)454 bool compliantWithV1_3(const V1_2::Capabilities&) {
455 return true;
456 }
457
compliantWithV1_3(const V1_3::Capabilities &)458 bool compliantWithV1_3(const V1_3::Capabilities&) {
459 return true;
460 }
461
convertToV1_0(V1_0::ErrorStatus status)462 V1_0::ErrorStatus convertToV1_0(V1_0::ErrorStatus status) {
463 return status;
464 }
465
convertToV1_0(V1_3::ErrorStatus status)466 V1_0::ErrorStatus convertToV1_0(V1_3::ErrorStatus status) {
467 switch (status) {
468 case V1_3::ErrorStatus::NONE:
469 return V1_0::ErrorStatus::NONE;
470 case V1_3::ErrorStatus::DEVICE_UNAVAILABLE:
471 return V1_0::ErrorStatus::DEVICE_UNAVAILABLE;
472 case V1_3::ErrorStatus::GENERAL_FAILURE:
473 return V1_0::ErrorStatus::GENERAL_FAILURE;
474 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
475 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
476 case V1_3::ErrorStatus::INVALID_ARGUMENT:
477 return V1_0::ErrorStatus::INVALID_ARGUMENT;
478 case V1_3::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
479 return V1_0::ErrorStatus::GENERAL_FAILURE;
480 case V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
481 return V1_0::ErrorStatus::GENERAL_FAILURE;
482 case V1_3::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
483 return V1_0::ErrorStatus::GENERAL_FAILURE;
484 case V1_3::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
485 return V1_0::ErrorStatus::GENERAL_FAILURE;
486 }
487 LOG(ERROR) << "Unknown ErrorStatus: " << toString(status) << " mapped to GENERAL_FAILURE";
488 return V1_0::ErrorStatus::GENERAL_FAILURE;
489 }
490
convertToV1_3(V1_0::ErrorStatus status)491 V1_3::ErrorStatus convertToV1_3(V1_0::ErrorStatus status) {
492 return static_cast<V1_3::ErrorStatus>(status);
493 }
494
convertToV1_3(V1_3::ErrorStatus status)495 V1_3::ErrorStatus convertToV1_3(V1_3::ErrorStatus status) {
496 return status;
497 }
498
uncheckedConvertToV1_0(V1_1::OperationType type)499 static V1_0::OperationType uncheckedConvertToV1_0(V1_1::OperationType type) {
500 return static_cast<V1_0::OperationType>(type);
501 }
502
uncheckedConvertToV1_0(V1_2::OperationType type)503 static V1_0::OperationType uncheckedConvertToV1_0(V1_2::OperationType type) {
504 return static_cast<V1_0::OperationType>(type);
505 }
506
uncheckedConvertToV1_0(V1_3::OperationType type)507 V1_0::OperationType uncheckedConvertToV1_0(V1_3::OperationType type) {
508 return static_cast<V1_0::OperationType>(type);
509 }
510
convertToV1_1(V1_0::OperationType type)511 static V1_1::OperationType convertToV1_1(V1_0::OperationType type) {
512 return static_cast<V1_1::OperationType>(type);
513 }
514
uncheckedConvertToV1_1(V1_2::OperationType type)515 static V1_1::OperationType uncheckedConvertToV1_1(V1_2::OperationType type) {
516 return static_cast<V1_1::OperationType>(type);
517 }
518
uncheckedConvertToV1_1(V1_3::OperationType type)519 V1_1::OperationType uncheckedConvertToV1_1(V1_3::OperationType type) {
520 return static_cast<V1_1::OperationType>(type);
521 }
522
convertToV1_2(V1_0::OperationType type)523 static V1_2::OperationType convertToV1_2(V1_0::OperationType type) {
524 return static_cast<V1_2::OperationType>(type);
525 }
526
convertToV1_2(V1_1::OperationType type)527 static V1_2::OperationType convertToV1_2(V1_1::OperationType type) {
528 return static_cast<V1_2::OperationType>(type);
529 }
530
uncheckedConvertToV1_2(V1_3::OperationType type)531 V1_2::OperationType uncheckedConvertToV1_2(V1_3::OperationType type) {
532 return static_cast<V1_2::OperationType>(type);
533 }
534
convertToV1_3(V1_0::OperationType type)535 static V1_3::OperationType convertToV1_3(V1_0::OperationType type) {
536 return static_cast<V1_3::OperationType>(type);
537 }
538
convertToV1_3(V1_1::OperationType type)539 static V1_3::OperationType convertToV1_3(V1_1::OperationType type) {
540 return static_cast<V1_3::OperationType>(type);
541 }
542
convertToV1_3(V1_2::OperationType type)543 static V1_3::OperationType convertToV1_3(V1_2::OperationType type) {
544 return static_cast<V1_3::OperationType>(type);
545 }
546
convertToV1_0(const V1_0::Capabilities & capabilities)547 V1_0::Capabilities convertToV1_0(const V1_0::Capabilities& capabilities) {
548 return capabilities;
549 }
550
convertToV1_0(const V1_1::Capabilities & capabilities)551 V1_0::Capabilities convertToV1_0(const V1_1::Capabilities& capabilities) {
552 if (!compliantWithV1_0(capabilities)) {
553 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
554 << " from V1_1::Capabilities to V1_0::Capabilities";
555 }
556 return {.float32Performance = capabilities.float32Performance,
557 .quantized8Performance = capabilities.quantized8Performance};
558 }
559
convertToV1_0(const V1_2::Capabilities & capabilities)560 V1_0::Capabilities convertToV1_0(const V1_2::Capabilities& capabilities) {
561 if (!compliantWithV1_0(capabilities)) {
562 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
563 << " from V1_2::Capabilities to V1_0::Capabilities";
564 }
565 return {.float32Performance =
566 lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32),
567 .quantized8Performance = lookup(capabilities.operandPerformance,
568 V1_2::OperandType::TENSOR_QUANT8_ASYMM)};
569 }
570
convertToV1_0(const V1_3::Capabilities & capabilities)571 V1_0::Capabilities convertToV1_0(const V1_3::Capabilities& capabilities) {
572 if (!compliantWithV1_0(capabilities)) {
573 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
574 << " from V1_3::Capabilities to V1_0::Capabilities";
575 }
576 return {.float32Performance =
577 lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32),
578 .quantized8Performance = lookup(capabilities.operandPerformance,
579 V1_3::OperandType::TENSOR_QUANT8_ASYMM)};
580 }
581
convertToV1_1(const V1_0::Capabilities & capabilities)582 V1_1::Capabilities convertToV1_1(const V1_0::Capabilities& capabilities) {
583 return {.float32Performance = capabilities.float32Performance,
584 .quantized8Performance = capabilities.quantized8Performance,
585 .relaxedFloat32toFloat16Performance = capabilities.float32Performance};
586 }
587
convertToV1_1(const V1_1::Capabilities & capabilities)588 V1_1::Capabilities convertToV1_1(const V1_1::Capabilities& capabilities) {
589 return capabilities;
590 }
591
convertToV1_1(const V1_2::Capabilities & capabilities)592 V1_1::Capabilities convertToV1_1(const V1_2::Capabilities& capabilities) {
593 if (!compliantWithV1_1(capabilities)) {
594 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
595 << " from V1_2::Capabilities to V1_1::Capabilities";
596 }
597 return {.float32Performance =
598 lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_FLOAT32),
599 .quantized8Performance =
600 lookup(capabilities.operandPerformance, V1_2::OperandType::TENSOR_QUANT8_ASYMM),
601 .relaxedFloat32toFloat16Performance =
602 capabilities.relaxedFloat32toFloat16PerformanceTensor};
603 }
604
convertToV1_1(const V1_3::Capabilities & capabilities)605 V1_1::Capabilities convertToV1_1(const V1_3::Capabilities& capabilities) {
606 if (!compliantWithV1_1(capabilities)) {
607 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
608 << " from V1_3::Capabilities to V1_1::Capabilities";
609 }
610 return {.float32Performance =
611 lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_FLOAT32),
612 .quantized8Performance =
613 lookup(capabilities.operandPerformance, V1_3::OperandType::TENSOR_QUANT8_ASYMM),
614 .relaxedFloat32toFloat16Performance =
615 capabilities.relaxedFloat32toFloat16PerformanceTensor};
616 }
617
convertToV1_2(const V1_0::Capabilities & capabilities)618 V1_2::Capabilities convertToV1_2(const V1_0::Capabilities& capabilities) {
619 V1_2::Capabilities ret = {
620 .relaxedFloat32toFloat16PerformanceScalar = capabilities.float32Performance,
621 .relaxedFloat32toFloat16PerformanceTensor = capabilities.float32Performance,
622 .operandPerformance =
623 makeQuantized8PerformanceConsistentWithP(capabilities.quantized8Performance)};
624 auto& opPerf = ret.operandPerformance;
625 opPerf.resize(opPerf.size() + 2);
626 opPerf[opPerf.size() - 2] = {V1_2::OperandType::TENSOR_FLOAT32,
627 capabilities.float32Performance};
628 opPerf[opPerf.size() - 1] = {V1_2::OperandType::FLOAT32, capabilities.float32Performance};
629 using OperandPerformance = V1_2::Capabilities::OperandPerformance;
630 std::sort(opPerf.begin(), opPerf.end(),
631 [](const OperandPerformance& a, const OperandPerformance& b) {
632 return a.type < b.type;
633 });
634 return ret;
635 }
636
convertToV1_2(const V1_1::Capabilities & capabilities)637 V1_2::Capabilities convertToV1_2(const V1_1::Capabilities& capabilities) {
638 V1_2::Capabilities ret = {.relaxedFloat32toFloat16PerformanceScalar =
639 capabilities.relaxedFloat32toFloat16Performance,
640 .relaxedFloat32toFloat16PerformanceTensor =
641 capabilities.relaxedFloat32toFloat16Performance,
642 .operandPerformance = makeQuantized8PerformanceConsistentWithP(
643 capabilities.quantized8Performance)};
644 auto& opPerf = ret.operandPerformance;
645 opPerf.resize(opPerf.size() + 2);
646 opPerf[opPerf.size() - 2] = {V1_2::OperandType::TENSOR_FLOAT32,
647 capabilities.float32Performance};
648 opPerf[opPerf.size() - 1] = {V1_2::OperandType::FLOAT32, capabilities.float32Performance};
649 using OperandPerformance = V1_2::Capabilities::OperandPerformance;
650 std::sort(opPerf.begin(), opPerf.end(),
651 [](const OperandPerformance& a, const OperandPerformance& b) {
652 return a.type < b.type;
653 });
654 return ret;
655 }
656
convertToV1_2(const V1_2::Capabilities & capabilities)657 V1_2::Capabilities convertToV1_2(const V1_2::Capabilities& capabilities) {
658 return capabilities;
659 }
660
convertToV1_2(const V1_3::Capabilities & capabilities)661 V1_2::Capabilities convertToV1_2(const V1_3::Capabilities& capabilities) {
662 V1_2::Capabilities ret = {
663 .relaxedFloat32toFloat16PerformanceScalar =
664 capabilities.relaxedFloat32toFloat16PerformanceScalar,
665 .relaxedFloat32toFloat16PerformanceTensor =
666 capabilities.relaxedFloat32toFloat16PerformanceTensor,
667 };
668 const auto& inputOpPerf = capabilities.operandPerformance;
669 hardware::hidl_vec<V1_3::Capabilities::OperandPerformance> opPerfSupported;
670 opPerfSupported.resize(inputOpPerf.size());
671 auto last =
672 std::copy_if(inputOpPerf.begin(), inputOpPerf.end(), opPerfSupported.begin(),
673 [](V1_3::Capabilities::OperandPerformance opPerf) {
674 return validOperandType(static_cast<V1_2::OperandType>(opPerf.type));
675 });
676 opPerfSupported.resize(std::distance(opPerfSupported.begin(), last));
677
678 auto& convertedOpPerf = ret.operandPerformance;
679 convertedOpPerf.resize(opPerfSupported.size());
680 std::transform(opPerfSupported.begin(), opPerfSupported.end(), convertedOpPerf.begin(),
681 [](V1_3::Capabilities::OperandPerformance opPerf) {
682 return V1_2::Capabilities::OperandPerformance{
683 static_cast<V1_2::OperandType>(opPerf.type), opPerf.info};
684 });
685 return ret;
686 }
687
convertToV1_3(const V1_0::Capabilities & capabilities)688 V1_3::Capabilities convertToV1_3(const V1_0::Capabilities& capabilities) {
689 return convertToV1_3(convertToV1_2(capabilities));
690 }
691
convertToV1_3(const V1_1::Capabilities & capabilities)692 V1_3::Capabilities convertToV1_3(const V1_1::Capabilities& capabilities) {
693 return convertToV1_3(convertToV1_2(capabilities));
694 }
695
convertToV1_3(const V1_2::Capabilities & capabilities)696 V1_3::Capabilities convertToV1_3(const V1_2::Capabilities& capabilities) {
697 V1_3::Capabilities ret = {
698 .relaxedFloat32toFloat16PerformanceScalar =
699 capabilities.relaxedFloat32toFloat16PerformanceScalar,
700 .relaxedFloat32toFloat16PerformanceTensor =
701 capabilities.relaxedFloat32toFloat16PerformanceTensor,
702 .ifPerformance = kNoPerformanceInfo,
703 .whilePerformance = kNoPerformanceInfo,
704 };
705 auto& opPerf = ret.operandPerformance;
706 opPerf.resize(capabilities.operandPerformance.size());
707 std::transform(capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
708 opPerf.begin(), [](V1_2::Capabilities::OperandPerformance opPerf) {
709 return V1_3::Capabilities::OperandPerformance{
710 static_cast<V1_3::OperandType>(opPerf.type), opPerf.info};
711 });
712 return ret;
713 }
714
convertToV1_3(const V1_3::Capabilities & capabilities)715 V1_3::Capabilities convertToV1_3(const V1_3::Capabilities& capabilities) {
716 return capabilities;
717 }
718
uncheckedConvertToV1_0(const V1_1::Operation & operation)719 static V1_0::Operation uncheckedConvertToV1_0(const V1_1::Operation& operation) {
720 return {.type = uncheckedConvertToV1_0(operation.type),
721 .inputs = operation.inputs,
722 .outputs = operation.outputs};
723 }
724
convertToV1_1(const V1_0::Operation & operation)725 static V1_1::Operation convertToV1_1(const V1_0::Operation& operation) {
726 return {.type = convertToV1_1(operation.type),
727 .inputs = operation.inputs,
728 .outputs = operation.outputs};
729 }
730
uncheckedConvertToV1_0(const hardware::hidl_vec<V1_1::Operation> & operations)731 static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0(
732 const hardware::hidl_vec<V1_1::Operation>& operations) {
733 hardware::hidl_vec<V1_0::Operation> result(operations.size());
734 std::transform(
735 operations.begin(), operations.end(), result.begin(),
736 [](const V1_1::Operation& operation) { return uncheckedConvertToV1_0(operation); });
737 return result;
738 }
739
convertToV1_1(const hardware::hidl_vec<V1_0::Operation> & operations)740 static hardware::hidl_vec<V1_1::Operation> convertToV1_1(
741 const hardware::hidl_vec<V1_0::Operation>& operations) {
742 hardware::hidl_vec<V1_1::Operation> result(operations.size());
743 std::transform(operations.begin(), operations.end(), result.begin(),
744 [](const V1_0::Operation& operation) { return convertToV1_1(operation); });
745 return result;
746 }
747
compliantWithV1_0(const V1_3::Operand & operand)748 bool compliantWithV1_0(const V1_3::Operand& operand) {
749 return validOperandType(static_cast<V1_0::OperandType>(operand.type)) &&
750 (nonExtensionOperandTypeIsScalar(static_cast<int>(operand.type)) ||
751 operand.dimensions.size() != 0) &&
752 compliantWithV1_0(operand.lifetime);
753 }
754
compliantWithV1_2(const V1_3::Operand & operand)755 bool compliantWithV1_2(const V1_3::Operand& operand) {
756 return validOperandType(static_cast<V1_2::OperandType>(operand.type)) &&
757 compliantWithV1_0(operand.lifetime);
758 }
759
compliantWithV1_3(const V1_3::Operand &)760 bool compliantWithV1_3(const V1_3::Operand& /*operand*/) {
761 return true;
762 }
763
compliantWithAidl(const V1_3::Operand & operand)764 bool compliantWithAidl(const V1_3::Operand& operand) {
765 if (static_cast<std::underlying_type_t<V1_3::OperandType>>(operand.type) >
766 std::numeric_limits<int32_t>::max()) {
767 return false;
768 }
769 if (operand.location.poolIndex > std::numeric_limits<int32_t>::max()) {
770 return false;
771 }
772 if (operand.extraParams.getDiscriminator() ==
773 V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant &&
774 operand.extraParams.channelQuant().channelDim > std::numeric_limits<int32_t>::max()) {
775 return false;
776 }
777 for (auto dim : operand.dimensions) {
778 if (dim > std::numeric_limits<int32_t>::max()) {
779 return false;
780 }
781 }
782 return true;
783 }
784
compliantWith(HalVersion version,const V1_3::Model & model,std::set<uint32_t> * noncompliantOperations)785 static bool compliantWith(HalVersion version, const V1_3::Model& model,
786 std::set<uint32_t>* noncompliantOperations) {
787 // A boolean vector indicating whether each pool is compliant with the target HAL version.
788 std::vector<bool> isPoolCompliant(model.pools.size(), false);
789 std::transform(
790 model.pools.begin(), model.pools.end(), isPoolCompliant.begin(),
791 [version](const hardware::hidl_memory& pool) { return validatePool(pool, version); });
792
793 // A boolean vector indicating whether each operand is compliant with the target HAL version.
794 std::vector<bool> isOperandCompliant(model.main.operands.size(), false);
795 std::transform(model.main.operands.begin(), model.main.operands.end(),
796 isOperandCompliant.begin(),
797 [&isPoolCompliant, version](const V1_3::Operand& op) {
798 bool is_operand_compliant = false;
799 switch (version) {
800 case HalVersion::UNKNOWN:
801 is_operand_compliant = false;
802 break;
803 case HalVersion::V1_0:
804 is_operand_compliant = compliantWithV1_0(op);
805 break;
806 case HalVersion::V1_1:
807 // There is no V1_1::Operand -- both V1_0::Model
808 // and V1_1::Model use V1_0::Operand.
809 is_operand_compliant = compliantWithV1_0(op);
810 break;
811 case HalVersion::V1_2:
812 is_operand_compliant = compliantWithV1_2(op);
813 break;
814 case HalVersion::V1_3:
815 is_operand_compliant = compliantWithV1_3(op);
816 break;
817 case HalVersion::AIDL_V1:
818 case HalVersion::AIDL_V2:
819 case HalVersion::AIDL_UNSTABLE:
820 is_operand_compliant = compliantWithAidl(op);
821 break;
822 }
823 return is_operand_compliant &&
824 !(op.lifetime == V1_3::OperandLifeTime::CONSTANT_REFERENCE &&
825 !isPoolCompliant[op.location.poolIndex]);
826 });
827
828 auto allOperandsCompliant = [&isOperandCompliant](const hardware::hidl_vec<uint32_t>& indices) {
829 return std::all_of(
830 indices.begin(), indices.end(),
831 [&isOperandCompliant](const uint32_t ind) { return isOperandCompliant[ind]; });
832 };
833
834 auto localValidateOperation = [&model, version,
835 &allOperandsCompliant](const V1_3::Operation& op) {
836 if (!allOperandsCompliant(op.inputs) || !allOperandsCompliant(op.outputs)) return false;
837 int error = validateOperation(static_cast<int32_t>(op.type), op.inputs.size(),
838 op.inputs.size() > 0 ? op.inputs.data() : nullptr,
839 op.outputs.size(),
840 op.outputs.size() > 0 ? op.outputs.data() : nullptr,
841 uncheckedConvert(model.main.operands), version);
842 return error == ANEURALNETWORKS_NO_ERROR;
843 };
844
845 if (noncompliantOperations) {
846 CHECK(noncompliantOperations->empty());
847 for (uint32_t idx = 0; idx < model.main.operations.size(); ++idx) {
848 if (!localValidateOperation(model.main.operations[idx])) {
849 noncompliantOperations->insert(idx);
850 }
851 }
852 return noncompliantOperations->empty();
853 } else {
854 return std::all_of(model.main.operations.begin(), model.main.operations.end(),
855 localValidateOperation);
856 }
857 }
858
compliantWithV1_0(const V1_0::Model &)859 bool compliantWithV1_0(const V1_0::Model& /*model*/) {
860 return true;
861 }
862
compliantWithV1_0(const V1_1::Model & model)863 bool compliantWithV1_0(const V1_1::Model& model) {
864 // In addition to new enumeration values being introduced in V1_1::Model, a
865 // new flag was introduced to indicate whether or not float32 data can be
866 // calculated using float16 units. This 'relaxComputationFloat32toFloat16'
867 // flag is not relevant in whether a V1_1::Model is compliant with a
868 // V1_0::Model because all 1.0 drivers require strict calculation by default
869 // in the P NN runtime. Even if fp16 calculations are allowed, they can
870 // still be computed by a strict fp32 driver.
871 auto operands = uncheckedConvert(convertToV1_3(model.operands));
872 return std::all_of(model.operations.begin(), model.operations.end(),
873 [&operands](const V1_1::Operation& op) {
874 int error = validateOperation(
875 static_cast<int32_t>(op.type), op.inputs.size(),
876 op.inputs.size() > 0 ? op.inputs.data() : nullptr,
877 op.outputs.size(),
878 op.outputs.size() > 0 ? op.outputs.data() : nullptr, operands,
879 HalVersion::V1_0);
880 return error == ANEURALNETWORKS_NO_ERROR;
881 });
882 }
883
compliantWithV1_0(const V1_2::Model & model,std::set<uint32_t> * noncompliantOperations)884 bool compliantWithV1_0(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations) {
885 return compliantWith(HalVersion::V1_0, convertToV1_3(model), noncompliantOperations);
886 }
887
compliantWithV1_0(const V1_3::Model & model,std::set<uint32_t> * noncompliantOperations)888 bool compliantWithV1_0(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations) {
889 return compliantWith(HalVersion::V1_0, model, noncompliantOperations);
890 }
891
compliantWithV1_1(const V1_0::Model &)892 bool compliantWithV1_1(const V1_0::Model&) {
893 return true;
894 }
895
compliantWithV1_1(const V1_1::Model &)896 bool compliantWithV1_1(const V1_1::Model&) {
897 return true;
898 }
899
compliantWithV1_1(const V1_2::Model & model,std::set<uint32_t> * noncompliantOperations)900 bool compliantWithV1_1(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations) {
901 return compliantWith(HalVersion::V1_1, convertToV1_3(model), noncompliantOperations);
902 }
903
compliantWithV1_1(const V1_3::Model & model,std::set<uint32_t> * noncompliantOperations)904 bool compliantWithV1_1(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations) {
905 return compliantWith(HalVersion::V1_1, model, noncompliantOperations);
906 }
907
compliantWithV1_2(const V1_0::Model &)908 bool compliantWithV1_2(const V1_0::Model&) {
909 return true;
910 }
911
compliantWithV1_2(const V1_1::Model &)912 bool compliantWithV1_2(const V1_1::Model&) {
913 return true;
914 }
915
compliantWithV1_2(const V1_2::Model &,std::set<uint32_t> *)916 bool compliantWithV1_2(const V1_2::Model&, std::set<uint32_t>* /*noncompliantOperations*/) {
917 return true;
918 }
919
compliantWithV1_2(const V1_3::Model & model,std::set<uint32_t> * noncompliantOperations)920 bool compliantWithV1_2(const V1_3::Model& model, std::set<uint32_t>* noncompliantOperations) {
921 return compliantWith(HalVersion::V1_2, model, noncompliantOperations);
922 }
923
uncheckedConvertToV1_0(const V1_2::Operation & operation)924 static V1_0::Operation uncheckedConvertToV1_0(const V1_2::Operation& operation) {
925 return {.type = uncheckedConvertToV1_0(operation.type),
926 .inputs = operation.inputs,
927 .outputs = operation.outputs};
928 }
929
uncheckedConvertToV1_0(const V1_3::Operation & operation)930 static V1_0::Operation uncheckedConvertToV1_0(const V1_3::Operation& operation) {
931 return {.type = uncheckedConvertToV1_0(operation.type),
932 .inputs = operation.inputs,
933 .outputs = operation.outputs};
934 }
935
uncheckedConvertToV1_1(const V1_2::Operation & operation)936 static V1_1::Operation uncheckedConvertToV1_1(const V1_2::Operation& operation) {
937 return {.type = uncheckedConvertToV1_1(operation.type),
938 .inputs = operation.inputs,
939 .outputs = operation.outputs};
940 }
941
uncheckedConvertToV1_1(const V1_3::Operation & operation)942 static V1_1::Operation uncheckedConvertToV1_1(const V1_3::Operation& operation) {
943 return {.type = uncheckedConvertToV1_1(operation.type),
944 .inputs = operation.inputs,
945 .outputs = operation.outputs};
946 }
947
convertToV1_2(const V1_0::Operation & operation)948 static V1_2::Operation convertToV1_2(const V1_0::Operation& operation) {
949 return {.type = convertToV1_2(operation.type),
950 .inputs = operation.inputs,
951 .outputs = operation.outputs};
952 }
953
convertToV1_2(const V1_1::Operation & operation)954 static V1_2::Operation convertToV1_2(const V1_1::Operation& operation) {
955 return {.type = convertToV1_2(operation.type),
956 .inputs = operation.inputs,
957 .outputs = operation.outputs};
958 }
959
uncheckedConvertToV1_2(const V1_3::Operation & operation)960 static V1_2::Operation uncheckedConvertToV1_2(const V1_3::Operation& operation) {
961 return {.type = uncheckedConvertToV1_2(operation.type),
962 .inputs = operation.inputs,
963 .outputs = operation.outputs};
964 }
965
convertToV1_3(const V1_0::Operation & operation)966 static V1_3::Operation convertToV1_3(const V1_0::Operation& operation) {
967 return {.type = convertToV1_3(operation.type),
968 .inputs = operation.inputs,
969 .outputs = operation.outputs};
970 }
971
convertToV1_3(const V1_1::Operation & operation)972 static V1_3::Operation convertToV1_3(const V1_1::Operation& operation) {
973 return {.type = convertToV1_3(operation.type),
974 .inputs = operation.inputs,
975 .outputs = operation.outputs};
976 }
977
convertToV1_3(const V1_2::Operation & operation)978 static V1_3::Operation convertToV1_3(const V1_2::Operation& operation) {
979 return {.type = convertToV1_3(operation.type),
980 .inputs = operation.inputs,
981 .outputs = operation.outputs};
982 }
983
uncheckedConvertToV1_0(const hardware::hidl_vec<V1_3::Operation> & operations)984 static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0(
985 const hardware::hidl_vec<V1_3::Operation>& operations) {
986 hardware::hidl_vec<V1_0::Operation> result(operations.size());
987 std::transform(
988 operations.begin(), operations.end(), result.begin(),
989 [](const V1_3::Operation& operation) { return uncheckedConvertToV1_0(operation); });
990 return result;
991 }
992
uncheckedConvertToV1_0(const hardware::hidl_vec<V1_2::Operation> & operations)993 static hardware::hidl_vec<V1_0::Operation> uncheckedConvertToV1_0(
994 const hardware::hidl_vec<V1_2::Operation>& operations) {
995 hardware::hidl_vec<V1_0::Operation> result(operations.size());
996 std::transform(
997 operations.begin(), operations.end(), result.begin(),
998 [](const V1_2::Operation& operation) { return uncheckedConvertToV1_0(operation); });
999 return result;
1000 }
1001
uncheckedConvertToV1_2(const hardware::hidl_vec<V1_3::Operation> & operations)1002 static hardware::hidl_vec<V1_2::Operation> uncheckedConvertToV1_2(
1003 const hardware::hidl_vec<V1_3::Operation>& operations) {
1004 hardware::hidl_vec<V1_2::Operation> result(operations.size());
1005 std::transform(
1006 operations.begin(), operations.end(), result.begin(),
1007 [](const V1_3::Operation& operation) { return uncheckedConvertToV1_2(operation); });
1008 return result;
1009 }
1010
uncheckedConvertToV1_1(const hardware::hidl_vec<V1_2::Operation> & operations)1011 static hardware::hidl_vec<V1_1::Operation> uncheckedConvertToV1_1(
1012 const hardware::hidl_vec<V1_2::Operation>& operations) {
1013 hardware::hidl_vec<V1_1::Operation> result(operations.size());
1014 std::transform(
1015 operations.begin(), operations.end(), result.begin(),
1016 [](const V1_2::Operation& operation) { return uncheckedConvertToV1_1(operation); });
1017 return result;
1018 }
1019
uncheckedConvertToV1_1(const hardware::hidl_vec<V1_3::Operation> & operations)1020 static hardware::hidl_vec<V1_1::Operation> uncheckedConvertToV1_1(
1021 const hardware::hidl_vec<V1_3::Operation>& operations) {
1022 hardware::hidl_vec<V1_1::Operation> result(operations.size());
1023 std::transform(
1024 operations.begin(), operations.end(), result.begin(),
1025 [](const V1_3::Operation& operation) { return uncheckedConvertToV1_1(operation); });
1026 return result;
1027 }
1028
convertToV1_2(const hardware::hidl_vec<V1_0::Operation> & operations)1029 static hardware::hidl_vec<V1_2::Operation> convertToV1_2(
1030 const hardware::hidl_vec<V1_0::Operation>& operations) {
1031 hardware::hidl_vec<V1_2::Operation> result(operations.size());
1032 std::transform(operations.begin(), operations.end(), result.begin(),
1033 [](const V1_0::Operation& operation) { return convertToV1_2(operation); });
1034 return result;
1035 }
1036
convertToV1_2(const hardware::hidl_vec<V1_1::Operation> & operations)1037 static hardware::hidl_vec<V1_2::Operation> convertToV1_2(
1038 const hardware::hidl_vec<V1_1::Operation>& operations) {
1039 hardware::hidl_vec<V1_2::Operation> result(operations.size());
1040 std::transform(operations.begin(), operations.end(), result.begin(),
1041 [](const V1_1::Operation& operation) { return convertToV1_2(operation); });
1042 return result;
1043 }
1044
convertToV1_3(const hardware::hidl_vec<V1_0::Operation> & operations)1045 static hardware::hidl_vec<V1_3::Operation> convertToV1_3(
1046 const hardware::hidl_vec<V1_0::Operation>& operations) {
1047 hardware::hidl_vec<V1_3::Operation> result(operations.size());
1048 std::transform(operations.begin(), operations.end(), result.begin(),
1049 [](const V1_0::Operation& operation) { return convertToV1_3(operation); });
1050 return result;
1051 }
1052
convertToV1_3(const hardware::hidl_vec<V1_1::Operation> & operations)1053 static hardware::hidl_vec<V1_3::Operation> convertToV1_3(
1054 const hardware::hidl_vec<V1_1::Operation>& operations) {
1055 hardware::hidl_vec<V1_3::Operation> result(operations.size());
1056 std::transform(operations.begin(), operations.end(), result.begin(),
1057 [](const V1_1::Operation& operation) { return convertToV1_3(operation); });
1058 return result;
1059 }
1060
convertToV1_3(const hardware::hidl_vec<V1_2::Operation> & operations)1061 static hardware::hidl_vec<V1_3::Operation> convertToV1_3(
1062 const hardware::hidl_vec<V1_2::Operation>& operations) {
1063 hardware::hidl_vec<V1_3::Operation> result(operations.size());
1064 std::transform(operations.begin(), operations.end(), result.begin(),
1065 [](const V1_2::Operation& operation) { return convertToV1_3(operation); });
1066 return result;
1067 }
1068
compliantWithV1_0(const V1_2::OperandType & operandType)1069 static bool compliantWithV1_0(const V1_2::OperandType& operandType) {
1070 return validOperandType(static_cast<V1_0::OperandType>(operandType));
1071 }
1072
compliantWithV1_0(const V1_3::OperandType & operandType)1073 static bool compliantWithV1_0(const V1_3::OperandType& operandType) {
1074 return validOperandType(static_cast<V1_0::OperandType>(operandType));
1075 }
1076
compliantWithV1_2(const V1_3::OperandType & operandType)1077 static bool compliantWithV1_2(const V1_3::OperandType& operandType) {
1078 return validOperandType(static_cast<V1_2::OperandType>(operandType));
1079 }
1080
convertToV1_0(const V1_2::OperandType & operandType)1081 V1_0::OperandType convertToV1_0(const V1_2::OperandType& operandType) {
1082 if (!compliantWithV1_0(operandType)) {
1083 LOG(ERROR) << "Upcasting non-compliant operand type " << toString(operandType)
1084 << " from V1_2::OperandType to V1_0::OperandType";
1085 }
1086 return static_cast<V1_0::OperandType>(operandType);
1087 }
1088
convertToV1_2(const V1_0::OperandType & operandType)1089 V1_2::OperandType convertToV1_2(const V1_0::OperandType& operandType) {
1090 return static_cast<V1_2::OperandType>(operandType);
1091 }
1092
convertToV1_2(const V1_3::OperandType & operandType)1093 V1_2::OperandType convertToV1_2(const V1_3::OperandType& operandType) {
1094 if (!compliantWithV1_2(operandType)) {
1095 LOG(ERROR) << "Upcasting non-compliant operand type " << toString(operandType)
1096 << " from V1_3::OperandType to V1_2::OperandType";
1097 }
1098 return static_cast<V1_2::OperandType>(operandType);
1099 }
1100
convertToV1_0(const V1_3::OperandType & operandType)1101 V1_0::OperandType convertToV1_0(const V1_3::OperandType& operandType) {
1102 if (!compliantWithV1_0(operandType)) {
1103 LOG(ERROR) << "Upcasting non-compliant operand type " << toString(operandType)
1104 << " from V1_3::Operand to V1_0::Operand";
1105 }
1106 return static_cast<V1_0::OperandType>(operandType);
1107 }
1108
compliantWithV1_0(V1_0::OperandLifeTime)1109 bool compliantWithV1_0(V1_0::OperandLifeTime /*lifetime*/) {
1110 return true;
1111 }
1112
compliantWithV1_0(V1_3::OperandLifeTime lifetime)1113 bool compliantWithV1_0(V1_3::OperandLifeTime lifetime) {
1114 return lifetime != V1_3::OperandLifeTime::SUBGRAPH;
1115 }
1116
compliantWithV1_3(V1_0::OperandLifeTime)1117 bool compliantWithV1_3(V1_0::OperandLifeTime /*lifetime*/) {
1118 return true;
1119 }
1120
compliantWithV1_3(V1_3::OperandLifeTime)1121 bool compliantWithV1_3(V1_3::OperandLifeTime /*lifetime*/) {
1122 return true;
1123 }
1124
convertToV1_0(V1_0::OperandLifeTime lifetime)1125 V1_0::OperandLifeTime convertToV1_0(V1_0::OperandLifeTime lifetime) {
1126 return lifetime;
1127 }
1128
convertToV1_0(V1_3::OperandLifeTime lifetime)1129 V1_0::OperandLifeTime convertToV1_0(V1_3::OperandLifeTime lifetime) {
1130 if (!compliantWithV1_0(lifetime)) {
1131 LOG(ERROR) << "Upcasting non-compliant lifetime " << toString(lifetime)
1132 << " from V1_3 to V1_0";
1133 }
1134 return static_cast<V1_0::OperandLifeTime>(lifetime);
1135 }
1136
convertToV1_3(V1_0::OperandLifeTime lifetime)1137 V1_3::OperandLifeTime convertToV1_3(V1_0::OperandLifeTime lifetime) {
1138 return static_cast<V1_3::OperandLifeTime>(lifetime);
1139 }
1140
convertToV1_3(V1_3::OperandLifeTime lifetime)1141 V1_3::OperandLifeTime convertToV1_3(V1_3::OperandLifeTime lifetime) {
1142 return lifetime;
1143 }
1144
convertToV1_0(const V1_2::Operand & operand)1145 V1_0::Operand convertToV1_0(const V1_2::Operand& operand) {
1146 return {.type = convertToV1_0(operand.type),
1147 .dimensions = operand.dimensions,
1148 .numberOfConsumers = operand.numberOfConsumers,
1149 .scale = operand.scale,
1150 .zeroPoint = operand.zeroPoint,
1151 .lifetime = convertToV1_0(operand.lifetime),
1152 .location = operand.location};
1153 }
1154
convertToV1_0(const V1_3::Operand & operand)1155 V1_0::Operand convertToV1_0(const V1_3::Operand& operand) {
1156 return {.type = convertToV1_0(operand.type),
1157 .dimensions = operand.dimensions,
1158 .numberOfConsumers = operand.numberOfConsumers,
1159 .scale = operand.scale,
1160 .zeroPoint = operand.zeroPoint,
1161 .lifetime = convertToV1_0(operand.lifetime),
1162 .location = operand.location};
1163 }
1164
convertToV1_2(const V1_0::Operand & operand)1165 V1_2::Operand convertToV1_2(const V1_0::Operand& operand) {
1166 return {.type = convertToV1_2(operand.type),
1167 .dimensions = operand.dimensions,
1168 .numberOfConsumers = operand.numberOfConsumers,
1169 .scale = operand.scale,
1170 .zeroPoint = operand.zeroPoint,
1171 .lifetime = operand.lifetime,
1172 .location = operand.location};
1173 }
1174
convertToV1_2(const V1_3::Operand & operand)1175 V1_2::Operand convertToV1_2(const V1_3::Operand& operand) {
1176 return {.type = convertToV1_2(operand.type),
1177 .dimensions = operand.dimensions,
1178 .numberOfConsumers = operand.numberOfConsumers,
1179 .scale = operand.scale,
1180 .zeroPoint = operand.zeroPoint,
1181 .lifetime = static_cast<V1_0::OperandLifeTime>(operand.lifetime),
1182 .location = operand.location,
1183 .extraParams = operand.extraParams};
1184 }
1185
convertToV1_3(const V1_0::Operand & operand)1186 V1_3::Operand convertToV1_3(const V1_0::Operand& operand) {
1187 return {.type = static_cast<V1_3::OperandType>(operand.type),
1188 .dimensions = operand.dimensions,
1189 .numberOfConsumers = operand.numberOfConsumers,
1190 .scale = operand.scale,
1191 .zeroPoint = operand.zeroPoint,
1192 .lifetime = convertToV1_3(operand.lifetime),
1193 .location = operand.location};
1194 }
1195
convertToV1_3(const V1_2::Operand & operand)1196 V1_3::Operand convertToV1_3(const V1_2::Operand& operand) {
1197 return {.type = static_cast<V1_3::OperandType>(operand.type),
1198 .dimensions = operand.dimensions,
1199 .numberOfConsumers = operand.numberOfConsumers,
1200 .scale = operand.scale,
1201 .zeroPoint = operand.zeroPoint,
1202 .lifetime = convertToV1_3(operand.lifetime),
1203 .location = operand.location,
1204 .extraParams = operand.extraParams};
1205 }
1206
convertToV1_3(const V1_3::Operand & operand)1207 V1_3::Operand convertToV1_3(const V1_3::Operand& operand) {
1208 return operand;
1209 }
1210
convertToV1_0(const hardware::hidl_vec<V1_0::Operand> & operands)1211 hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_0::Operand>& operands) {
1212 return operands;
1213 }
1214
convertToV1_0(const hardware::hidl_vec<V1_2::Operand> & operands)1215 hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_2::Operand>& operands) {
1216 hardware::hidl_vec<V1_0::Operand> result(operands.size());
1217 std::transform(operands.begin(), operands.end(), result.begin(),
1218 [](const V1_2::Operand& operand) { return convertToV1_0(operand); });
1219 return result;
1220 }
1221
convertToV1_0(const hardware::hidl_vec<V1_3::Operand> & operands)1222 hardware::hidl_vec<V1_0::Operand> convertToV1_0(const hardware::hidl_vec<V1_3::Operand>& operands) {
1223 hardware::hidl_vec<V1_0::Operand> result(operands.size());
1224 std::transform(operands.begin(), operands.end(), result.begin(),
1225 [](const V1_3::Operand& operand) { return convertToV1_0(operand); });
1226 return result;
1227 }
1228
convertToV1_2(const hardware::hidl_vec<V1_0::Operand> & operands)1229 hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_0::Operand>& operands) {
1230 hardware::hidl_vec<V1_2::Operand> result(operands.size());
1231 std::transform(operands.begin(), operands.end(), result.begin(),
1232 [](const V1_0::Operand& operand) { return convertToV1_2(operand); });
1233 return result;
1234 }
1235
convertToV1_2(const hardware::hidl_vec<V1_2::Operand> & operands)1236 hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_2::Operand>& operands) {
1237 return operands;
1238 }
1239
convertToV1_2(const hardware::hidl_vec<V1_3::Operand> & operands)1240 hardware::hidl_vec<V1_2::Operand> convertToV1_2(const hardware::hidl_vec<V1_3::Operand>& operands) {
1241 hardware::hidl_vec<V1_2::Operand> result(operands.size());
1242 std::transform(operands.begin(), operands.end(), result.begin(),
1243 [](const V1_3::Operand& operand) { return convertToV1_2(operand); });
1244 return result;
1245 }
1246
convertToV1_3(const hardware::hidl_vec<V1_0::Operand> & operands)1247 hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_0::Operand>& operands) {
1248 hardware::hidl_vec<V1_3::Operand> result(operands.size());
1249 std::transform(operands.begin(), operands.end(), result.begin(),
1250 [](const V1_0::Operand& operand) { return convertToV1_3(operand); });
1251 return result;
1252 }
1253
convertToV1_3(const hardware::hidl_vec<V1_2::Operand> & operands)1254 hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_2::Operand>& operands) {
1255 hardware::hidl_vec<V1_3::Operand> result(operands.size());
1256 std::transform(operands.begin(), operands.end(), result.begin(),
1257 [](const V1_2::Operand& operand) { return convertToV1_3(operand); });
1258 return result;
1259 }
1260
convertToV1_3(const hardware::hidl_vec<V1_3::Operand> & operands)1261 hardware::hidl_vec<V1_3::Operand> convertToV1_3(const hardware::hidl_vec<V1_3::Operand>& operands) {
1262 return operands;
1263 }
1264
convertToV1_0(const V1_0::Model & model)1265 V1_0::Model convertToV1_0(const V1_0::Model& model) {
1266 return model;
1267 }
1268
convertToV1_0(const V1_1::Model & model)1269 V1_0::Model convertToV1_0(const V1_1::Model& model) {
1270 if (!compliantWithV1_0(model)) {
1271 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1272 << " from V1_1::Model to V1_0::Model";
1273 }
1274 return {.operands = model.operands,
1275 .operations = uncheckedConvertToV1_0(model.operations),
1276 .inputIndexes = model.inputIndexes,
1277 .outputIndexes = model.outputIndexes,
1278 .operandValues = model.operandValues,
1279 .pools = model.pools};
1280 }
1281
convertToV1_0(const V1_2::Model & model)1282 V1_0::Model convertToV1_0(const V1_2::Model& model) {
1283 if (!compliantWithV1_0(model)) {
1284 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1285 << " from V1_2::Model to V1_0::Model";
1286 }
1287 return {.operands = convertToV1_0(model.operands),
1288 .operations = uncheckedConvertToV1_0(model.operations),
1289 .inputIndexes = model.inputIndexes,
1290 .outputIndexes = model.outputIndexes,
1291 .operandValues = model.operandValues,
1292 .pools = model.pools};
1293 }
1294
convertToV1_0(const V1_3::Model & model)1295 V1_0::Model convertToV1_0(const V1_3::Model& model) {
1296 if (!compliantWithV1_0(model)) {
1297 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1298 << " from V1_3::Model to V1_0::Model";
1299 }
1300 return {.operands = convertToV1_0(model.main.operands),
1301 .operations = uncheckedConvertToV1_0(model.main.operations),
1302 .inputIndexes = model.main.inputIndexes,
1303 .outputIndexes = model.main.outputIndexes,
1304 .operandValues = model.operandValues,
1305 .pools = model.pools};
1306 }
1307
convertToV1_1(const V1_0::Model & model)1308 V1_1::Model convertToV1_1(const V1_0::Model& model) {
1309 return {.operands = model.operands,
1310 .operations = convertToV1_1(model.operations),
1311 .inputIndexes = model.inputIndexes,
1312 .outputIndexes = model.outputIndexes,
1313 .operandValues = model.operandValues,
1314 .pools = model.pools,
1315 .relaxComputationFloat32toFloat16 = false};
1316 }
1317
convertToV1_1(const V1_1::Model & model)1318 V1_1::Model convertToV1_1(const V1_1::Model& model) {
1319 return model;
1320 }
1321
convertToV1_1(const V1_2::Model & model)1322 V1_1::Model convertToV1_1(const V1_2::Model& model) {
1323 if (!compliantWithV1_1(model)) {
1324 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1325 << " from V1_2::Model to V1_1::Model";
1326 }
1327 return {.operands = convertToV1_0(model.operands), // Operands in 1.1 and 1.0 are identical.
1328 .operations = uncheckedConvertToV1_1(model.operations),
1329 .inputIndexes = model.inputIndexes,
1330 .outputIndexes = model.outputIndexes,
1331 .operandValues = model.operandValues,
1332 .pools = model.pools,
1333 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
1334 }
1335
convertToV1_1(const V1_3::Model & model)1336 V1_1::Model convertToV1_1(const V1_3::Model& model) {
1337 if (!compliantWithV1_1(model)) {
1338 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1339 << " from V1_3::Model to V1_1::Model";
1340 }
1341 return {// Operands in 1.1 and 1.0 are identical.
1342 .operands = convertToV1_0(model.main.operands),
1343 .operations = uncheckedConvertToV1_1(model.main.operations),
1344 .inputIndexes = model.main.inputIndexes,
1345 .outputIndexes = model.main.outputIndexes,
1346 .operandValues = model.operandValues,
1347 .pools = model.pools,
1348 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
1349 }
1350
convertToV1_2(const V1_0::Model & model)1351 V1_2::Model convertToV1_2(const V1_0::Model& model) {
1352 return {.operands = convertToV1_2(model.operands),
1353 .operations = convertToV1_2(model.operations),
1354 .inputIndexes = model.inputIndexes,
1355 .outputIndexes = model.outputIndexes,
1356 .operandValues = model.operandValues,
1357 .pools = model.pools,
1358 .relaxComputationFloat32toFloat16 = false};
1359 }
1360
convertToV1_2(const V1_1::Model & model)1361 V1_2::Model convertToV1_2(const V1_1::Model& model) {
1362 return {.operands = convertToV1_2(model.operands),
1363 .operations = convertToV1_2(model.operations),
1364 .inputIndexes = model.inputIndexes,
1365 .outputIndexes = model.outputIndexes,
1366 .operandValues = model.operandValues,
1367 .pools = model.pools,
1368 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
1369 }
1370
convertToV1_2(const V1_2::Model & model)1371 V1_2::Model convertToV1_2(const V1_2::Model& model) {
1372 return model;
1373 }
1374
convertToV1_2(const V1_3::Model & model)1375 V1_2::Model convertToV1_2(const V1_3::Model& model) {
1376 if (!compliantWithV1_2(model)) {
1377 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
1378 << " from V1_3::Model to V1_2::Model";
1379 }
1380 return {.operands = convertToV1_2(model.main.operands),
1381 .operations = uncheckedConvertToV1_2(model.main.operations),
1382 .inputIndexes = model.main.inputIndexes,
1383 .outputIndexes = model.main.outputIndexes,
1384 .operandValues = model.operandValues,
1385 .pools = model.pools,
1386 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
1387 .extensionNameToPrefix = model.extensionNameToPrefix};
1388 }
1389
convertToV1_3(const V1_0::Model & model)1390 V1_3::Model convertToV1_3(const V1_0::Model& model) {
1391 return {.main = {.operands = convertToV1_3(model.operands),
1392 .operations = convertToV1_3(model.operations),
1393 .inputIndexes = model.inputIndexes,
1394 .outputIndexes = model.outputIndexes},
1395 .operandValues = model.operandValues,
1396 .pools = model.pools,
1397 .relaxComputationFloat32toFloat16 = false};
1398 }
1399
convertToV1_3(const V1_1::Model & model)1400 V1_3::Model convertToV1_3(const V1_1::Model& model) {
1401 return {.main = {.operands = convertToV1_3(model.operands),
1402 .operations = convertToV1_3(model.operations),
1403 .inputIndexes = model.inputIndexes,
1404 .outputIndexes = model.outputIndexes},
1405 .operandValues = model.operandValues,
1406 .pools = model.pools,
1407 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
1408 }
1409
convertToV1_3(const V1_2::Model & model)1410 V1_3::Model convertToV1_3(const V1_2::Model& model) {
1411 return {.main = {.operands = convertToV1_3(model.operands),
1412 .operations = convertToV1_3(model.operations),
1413 .inputIndexes = model.inputIndexes,
1414 .outputIndexes = model.outputIndexes},
1415 .operandValues = model.operandValues,
1416 .pools = model.pools,
1417 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
1418 .extensionNameToPrefix = model.extensionNameToPrefix};
1419 }
1420
convertToV1_3(const V1_3::Model & model)1421 V1_3::Model convertToV1_3(const V1_3::Model& model) {
1422 return model;
1423 }
1424
compliantWithV1_0(const V1_0::Request &)1425 bool compliantWithV1_0(const V1_0::Request& /*request*/) {
1426 return true;
1427 }
1428
compliantWithV1_0(const V1_3::Request & request)1429 bool compliantWithV1_0(const V1_3::Request& request) {
1430 return std::all_of(request.pools.begin(), request.pools.end(), [](const auto& pool) {
1431 if (pool.getDiscriminator() != V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory) {
1432 return false;
1433 }
1434 const auto& name = pool.hidlMemory().name();
1435 return name == "ashmem" || name == "mmap_fd";
1436 });
1437 }
1438
compliantWithV1_2(const V1_3::Request & request)1439 bool compliantWithV1_2(const V1_3::Request& request) {
1440 return std::all_of(request.pools.begin(), request.pools.end(), [](const auto& pool) {
1441 if (pool.getDiscriminator() != V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory) {
1442 return false;
1443 }
1444 const auto& name = pool.hidlMemory().name();
1445 return name == "ashmem" || name == "mmap_fd" || name == "hardware_buffer_blob" ||
1446 name == "hardware_buffer";
1447 });
1448 }
1449
convertToV1_0(const V1_3::Request::MemoryPool & pool)1450 static hardware::hidl_memory convertToV1_0(const V1_3::Request::MemoryPool& pool) {
1451 switch (pool.getDiscriminator()) {
1452 case V1_3::Request::MemoryPool::hidl_discriminator::hidlMemory:
1453 return pool.hidlMemory();
1454 case V1_3::Request::MemoryPool::hidl_discriminator::token:
1455 return hardware::hidl_memory{};
1456 }
1457 }
1458
convertToV1_3(const hardware::hidl_memory & pool)1459 static V1_3::Request::MemoryPool convertToV1_3(const hardware::hidl_memory& pool) {
1460 V1_3::Request::MemoryPool ret;
1461 ret.hidlMemory(pool);
1462 return ret;
1463 }
1464
convertToV1_0(const V1_0::Request & request)1465 V1_0::Request convertToV1_0(const V1_0::Request& request) {
1466 return request;
1467 }
1468
uncheckedConvertToV1_0(const V1_3::Request & request)1469 static V1_0::Request uncheckedConvertToV1_0(const V1_3::Request& request) {
1470 hardware::hidl_vec<hardware::hidl_memory> pools(request.pools.size());
1471 std::transform(request.pools.begin(), request.pools.end(), pools.begin(),
1472 [](const auto& pool) { return convertToV1_0(pool); });
1473 return {.inputs = request.inputs, .outputs = request.outputs, .pools = std::move(pools)};
1474 }
1475
convertToV1_0(const V1_3::Request & request)1476 V1_0::Request convertToV1_0(const V1_3::Request& request) {
1477 if (!compliantWithV1_0(request)) {
1478 LOG(ERROR) << "Upcasting non-compliant request " << SHOW_IF_DEBUG(toString(request))
1479 << " from V1_3::Request to V1_0::Request of version 1.0";
1480 }
1481 return uncheckedConvertToV1_0(request);
1482 }
1483
convertToV1_2(const V1_3::Request & request)1484 V1_0::Request convertToV1_2(const V1_3::Request& request) {
1485 if (!compliantWithV1_2(request)) {
1486 LOG(ERROR) << "Upcasting non-compliant request " << SHOW_IF_DEBUG(toString(request))
1487 << " from V1_3::Request to V1_0::Request of version 1.2";
1488 }
1489 return uncheckedConvertToV1_0(request);
1490 }
1491
convertToV1_3(const V1_0::Request & request)1492 V1_3::Request convertToV1_3(const V1_0::Request& request) {
1493 hardware::hidl_vec<V1_3::Request::MemoryPool> pools(request.pools.size());
1494 std::transform(request.pools.begin(), request.pools.end(), pools.begin(),
1495 [](const auto& pool) { return convertToV1_3(pool); });
1496 return {.inputs = request.inputs, .outputs = request.outputs, .pools = std::move(pools)};
1497 }
1498
convertToV1_3(const V1_3::Request & request)1499 V1_3::Request convertToV1_3(const V1_3::Request& request) {
1500 return request;
1501 }
1502
uncheckedConvert(V1_0::ErrorStatus status)1503 ErrorStatus uncheckedConvert(V1_0::ErrorStatus status) {
1504 return handleError(convert(status));
1505 }
1506
uncheckedConvert(V1_3::ErrorStatus status)1507 ErrorStatus uncheckedConvert(V1_3::ErrorStatus status) {
1508 return handleError(convert(status));
1509 }
1510
uncheckedConvert(V1_3::OperandType operandType)1511 OperandType uncheckedConvert(V1_3::OperandType operandType) {
1512 return handleError(unvalidatedConvert(operandType));
1513 }
1514
uncheckedConvert(V1_3::OperationType operandType)1515 OperationType uncheckedConvert(V1_3::OperationType operandType) {
1516 return handleError(unvalidatedConvert(operandType));
1517 }
1518
uncheckedConvert(V1_3::OperandLifeTime lifetime)1519 Operand::LifeTime uncheckedConvert(V1_3::OperandLifeTime lifetime) {
1520 return handleError(unvalidatedConvert(lifetime));
1521 }
1522
uncheckedConvert(V1_2::MeasureTiming measure)1523 MeasureTiming uncheckedConvert(V1_2::MeasureTiming measure) {
1524 return handleError(convert(measure));
1525 }
1526
uncheckedConvert(const V1_0::DataLocation & location)1527 DataLocation uncheckedConvert(const V1_0::DataLocation& location) {
1528 return handleError(unvalidatedConvert(location));
1529 }
1530
uncheckedConvert(const V1_3::Operand & operand)1531 Operand uncheckedConvert(const V1_3::Operand& operand) {
1532 return handleError(unvalidatedConvert(operand));
1533 }
1534
uncheckedConvert(const V1_2::Operand::ExtraParams & params)1535 Operand::ExtraParams uncheckedConvert(const V1_2::Operand::ExtraParams& params) {
1536 return handleError(unvalidatedConvert(params));
1537 }
1538
uncheckedConvert(const V1_2::SymmPerChannelQuantParams & params)1539 Operand::SymmPerChannelQuantParams uncheckedConvert(const V1_2::SymmPerChannelQuantParams& params) {
1540 return handleError(unvalidatedConvert(params));
1541 }
1542
uncheckedConvert(const hardware::hidl_vec<uint8_t> & params)1543 Operand::ExtensionParams uncheckedConvert(const hardware::hidl_vec<uint8_t>& params) {
1544 return params;
1545 }
1546
uncheckedConvert(const V1_3::Operation & operation)1547 Operation uncheckedConvert(const V1_3::Operation& operation) {
1548 return handleError(unvalidatedConvert(operation));
1549 }
1550
1551 template <typename CanonicalType, typename HalType>
convertVec(const hardware::hidl_vec<HalType> & items)1552 static std::vector<CanonicalType> convertVec(const hardware::hidl_vec<HalType>& items) {
1553 std::vector<CanonicalType> result;
1554 result.reserve(items.size());
1555 std::transform(items.begin(), items.end(), std::back_inserter(result),
1556 [](const HalType& item) { return uncheckedConvert(item); });
1557 return result;
1558 }
1559
uncheckedConvert(const V1_3::Model & model)1560 Model uncheckedConvert(const V1_3::Model& model) {
1561 return handleError(convert(model));
1562 }
1563
uncheckedConvert(const V1_3::Subgraph & subgraph)1564 Model::Subgraph uncheckedConvert(const V1_3::Subgraph& subgraph) {
1565 return handleError(unvalidatedConvert(subgraph));
1566 }
1567
uncheckedConvert(const V1_2::Model::ExtensionNameAndPrefix & x)1568 ExtensionNameAndPrefix uncheckedConvert(const V1_2::Model::ExtensionNameAndPrefix& x) {
1569 return handleError(unvalidatedConvert(x));
1570 }
1571
uncheckedConvert(const V1_3::Request & request)1572 Request uncheckedConvert(const V1_3::Request& request) {
1573 return handleError(convert(request));
1574 }
1575
uncheckedConvert(const V1_0::RequestArgument & requestArgument)1576 Request::Argument uncheckedConvert(const V1_0::RequestArgument& requestArgument) {
1577 return handleError(unvalidatedConvert(requestArgument));
1578 }
1579
uncheckedConvert(const V1_3::Request::MemoryPool & memoryPool)1580 Request::MemoryPool uncheckedConvert(const V1_3::Request::MemoryPool& memoryPool) {
1581 return handleError(unvalidatedConvert(memoryPool));
1582 }
1583
uncheckedConvert(const V1_2::OutputShape & outputShape)1584 OutputShape uncheckedConvert(const V1_2::OutputShape& outputShape) {
1585 return handleError(unvalidatedConvert(outputShape));
1586 }
1587
uncheckedConvert(const hardware::hidl_vec<V1_2::OutputShape> & outputShapes)1588 std::vector<OutputShape> uncheckedConvert(
1589 const hardware::hidl_vec<V1_2::OutputShape>& outputShapes) {
1590 return convertVec<OutputShape>(outputShapes);
1591 }
1592
uncheckedConvert(const V1_3::Capabilities & capabilities)1593 Capabilities uncheckedConvert(const V1_3::Capabilities& capabilities) {
1594 return handleError(convert(capabilities));
1595 }
1596
uncheckedConvert(const V1_3::Capabilities::OperandPerformance & operandPerformance)1597 Capabilities::OperandPerformance uncheckedConvert(
1598 const V1_3::Capabilities::OperandPerformance& operandPerformance) {
1599 return handleError(unvalidatedConvert(operandPerformance));
1600 }
1601
uncheckedConvert(const V1_0::PerformanceInfo & performanceInfo)1602 Capabilities::PerformanceInfo uncheckedConvert(const V1_0::PerformanceInfo& performanceInfo) {
1603 return handleError(unvalidatedConvert(performanceInfo));
1604 }
1605
uncheckedConvert(const V1_2::Extension & extension)1606 Extension uncheckedConvert(const V1_2::Extension& extension) {
1607 return handleError(unvalidatedConvert(extension));
1608 }
1609
uncheckedConvert(const hardware::hidl_vec<V1_2::Extension> & extensions)1610 std::vector<Extension> uncheckedConvert(const hardware::hidl_vec<V1_2::Extension>& extensions) {
1611 return convertVec<Extension>(extensions);
1612 }
1613
uncheckedConvert(const V1_2::Extension::OperandTypeInformation & info)1614 Extension::OperandTypeInformation uncheckedConvert(
1615 const V1_2::Extension::OperandTypeInformation& info) {
1616 return handleError(unvalidatedConvert(info));
1617 }
1618
uncheckedConvert(const V1_3::OptionalTimeoutDuration & timeoutDuration)1619 OptionalDuration uncheckedConvert(const V1_3::OptionalTimeoutDuration& timeoutDuration) {
1620 return handleError(convert(timeoutDuration));
1621 }
1622
uncheckedConvert(const V1_2::Timing & timing)1623 Timing uncheckedConvert(const V1_2::Timing& timing) {
1624 return handleError(convert(timing));
1625 }
1626
convertToV1_0(ErrorStatus status)1627 V1_0::ErrorStatus convertToV1_0(ErrorStatus status) {
1628 return static_cast<V1_0::ErrorStatus>(static_cast<int>(status));
1629 }
1630
convertToV1_3(ErrorStatus status)1631 V1_3::ErrorStatus convertToV1_3(ErrorStatus status) {
1632 return handleError(V1_3::utils::convert(status));
1633 }
1634
convertToV1_3(OperandType operandType)1635 V1_3::OperandType convertToV1_3(OperandType operandType) {
1636 return handleError(V1_3::utils::unvalidatedConvert(operandType));
1637 }
1638
convertToV1_3(OperationType operandType)1639 V1_3::OperationType convertToV1_3(OperationType operandType) {
1640 return handleError(V1_3::utils::unvalidatedConvert(operandType));
1641 }
1642
convertToV1_3(Operand::LifeTime lifetime)1643 V1_3::OperandLifeTime convertToV1_3(Operand::LifeTime lifetime) {
1644 return handleError(V1_3::utils::unvalidatedConvert(lifetime));
1645 }
1646
convertToV1_1(ExecutionPreference preference)1647 V1_1::ExecutionPreference convertToV1_1(ExecutionPreference preference) {
1648 return handleError(V1_1::utils::convert(preference));
1649 }
1650
convertToV1_3(Priority priority)1651 V1_3::Priority convertToV1_3(Priority priority) {
1652 return handleError(V1_3::utils::convert(priority));
1653 }
1654
convertToV1_2(MeasureTiming measure)1655 V1_2::MeasureTiming convertToV1_2(MeasureTiming measure) {
1656 return handleError(V1_2::utils::convert(measure));
1657 }
1658
convertToV1_0(const DataLocation & location)1659 V1_0::DataLocation convertToV1_0(const DataLocation& location) {
1660 return handleError(V1_0::utils::unvalidatedConvert(location));
1661 }
1662
convertToV1_3(const Operand & operand)1663 V1_3::Operand convertToV1_3(const Operand& operand) {
1664 return handleError(V1_3::utils::unvalidatedConvert(operand));
1665 }
1666
convertToV1_2(const Operand::ExtraParams & params)1667 V1_2::Operand::ExtraParams convertToV1_2(const Operand::ExtraParams& params) {
1668 return handleError(V1_2::utils::unvalidatedConvert(params));
1669 }
1670
convertToV1_2(const Operand::SymmPerChannelQuantParams & params)1671 V1_2::SymmPerChannelQuantParams convertToV1_2(const Operand::SymmPerChannelQuantParams& params) {
1672 return handleError(V1_2::utils::unvalidatedConvert(params));
1673 }
1674
uncheckedConvert(const Operand::ExtensionParams & params)1675 hardware::hidl_vec<uint8_t> uncheckedConvert(const Operand::ExtensionParams& params) {
1676 return params;
1677 }
1678
convertToV1_3(const Operation & operation)1679 V1_3::Operation convertToV1_3(const Operation& operation) {
1680 return handleError(V1_3::utils::unvalidatedConvert(operation));
1681 }
1682
1683 template <typename HalType, typename CanonicalType>
convertVecToV1_0(const std::vector<CanonicalType> & items)1684 static hardware::hidl_vec<HalType> convertVecToV1_0(const std::vector<CanonicalType>& items) {
1685 hardware::hidl_vec<HalType> result(items.size());
1686 std::transform(items.begin(), items.end(), result.begin(),
1687 [](const CanonicalType& item) { return convertToV1_0(item); });
1688 return result;
1689 }
1690
1691 template <typename HalType, typename CanonicalType>
convertVecToV1_2(const std::vector<CanonicalType> & items)1692 static hardware::hidl_vec<HalType> convertVecToV1_2(const std::vector<CanonicalType>& items) {
1693 hardware::hidl_vec<HalType> result(items.size());
1694 std::transform(items.begin(), items.end(), result.begin(),
1695 [](const CanonicalType& item) { return convertToV1_2(item); });
1696 return result;
1697 }
1698
1699 template <typename HalType, typename CanonicalType>
convertVecToV1_3(const std::vector<CanonicalType> & items)1700 static hardware::hidl_vec<HalType> convertVecToV1_3(const std::vector<CanonicalType>& items) {
1701 hardware::hidl_vec<HalType> result(items.size());
1702 std::transform(items.begin(), items.end(), result.begin(),
1703 [](const CanonicalType& item) { return convertToV1_3(item); });
1704 return result;
1705 }
1706
convertToV1_2(const OutputShape & outputShape)1707 V1_2::OutputShape convertToV1_2(const OutputShape& outputShape) {
1708 return handleError(V1_2::utils::unvalidatedConvert(outputShape));
1709 }
1710
convertToV1_2(const std::vector<OutputShape> & outputShapes)1711 hardware::hidl_vec<V1_2::OutputShape> convertToV1_2(const std::vector<OutputShape>& outputShapes) {
1712 return convertVecToV1_2<V1_2::OutputShape>(outputShapes);
1713 }
1714
convertToV1_3(const Model & model)1715 V1_3::Model convertToV1_3(const Model& model) {
1716 return handleError(V1_3::utils::convert(model));
1717 }
1718
convertToV1_3(const Model::Subgraph & subgraph)1719 V1_3::Subgraph convertToV1_3(const Model::Subgraph& subgraph) {
1720 return handleError(V1_3::utils::unvalidatedConvert(subgraph));
1721 }
1722
convertToV1_2(const ExtensionNameAndPrefix & x)1723 V1_2::Model::ExtensionNameAndPrefix convertToV1_2(const ExtensionNameAndPrefix& x) {
1724 return handleError(V1_2::utils::unvalidatedConvert(x));
1725 }
1726
convertToV1_3(const Request & request)1727 V1_3::Request convertToV1_3(const Request& request) {
1728 return handleError(V1_3::utils::convert(request));
1729 }
1730
convertToV1_0(const Request::Argument & requestArgument)1731 V1_0::RequestArgument convertToV1_0(const Request::Argument& requestArgument) {
1732 return handleError(V1_0::utils::unvalidatedConvert(requestArgument));
1733 }
1734
convertToV1_3(const Request::MemoryPool & memoryPool)1735 V1_3::Request::MemoryPool convertToV1_3(const Request::MemoryPool& memoryPool) {
1736 return handleError(V1_3::utils::unvalidatedConvert(memoryPool));
1737 }
1738
uncheckedConvert(const hardware::hidl_vec<V1_3::Request::MemoryPool> & memoryPools)1739 std::vector<Request::MemoryPool> uncheckedConvert(
1740 const hardware::hidl_vec<V1_3::Request::MemoryPool>& memoryPools) {
1741 return convertVec<Request::MemoryPool>(memoryPools);
1742 }
1743
convertToV1_3(const OptionalTimePoint & timePoint)1744 V1_3::OptionalTimePoint convertToV1_3(const OptionalTimePoint& timePoint) {
1745 return handleError(V1_3::utils::convert(timePoint));
1746 }
1747
convertToV1_3(const OptionalDuration & timeoutDuration)1748 V1_3::OptionalTimeoutDuration convertToV1_3(const OptionalDuration& timeoutDuration) {
1749 return handleError(V1_3::utils::convert(timeoutDuration));
1750 }
1751
convertToV1_2(const Timing & timing)1752 V1_2::Timing convertToV1_2(const Timing& timing) {
1753 return handleError(V1_2::utils::convert(timing));
1754 }
1755
convertToV1_3(const BufferRole & bufferRole)1756 V1_3::BufferRole convertToV1_3(const BufferRole& bufferRole) {
1757 return handleError(V1_3::utils::unvalidatedConvert(bufferRole));
1758 }
1759
convertToV1_3(const std::vector<BufferRole> & bufferRoles)1760 hardware::hidl_vec<V1_3::BufferRole> convertToV1_3(const std::vector<BufferRole>& bufferRoles) {
1761 return convertVecToV1_3<V1_3::BufferRole>(bufferRoles);
1762 }
1763
convertToV1_0(const Model::OperandValues & operandValues)1764 hardware::hidl_vec<uint8_t> convertToV1_0(const Model::OperandValues& operandValues) {
1765 return handleError(V1_0::utils::unvalidatedConvert(operandValues));
1766 }
1767
convertToV1_0(const SharedMemory & memory)1768 hardware::hidl_memory convertToV1_0(const SharedMemory& memory) {
1769 return handleError(V1_0::utils::unvalidatedConvert(memory));
1770 }
1771
uncheckedConvert(const hardware::hidl_memory & memory)1772 SharedMemory uncheckedConvert(const hardware::hidl_memory& memory) {
1773 return handleError(convert(memory));
1774 }
1775
convertToV1_0(const std::vector<SharedMemory> & memories)1776 hardware::hidl_vec<hardware::hidl_memory> convertToV1_0(const std::vector<SharedMemory>& memories) {
1777 return convertVecToV1_0<hardware::hidl_memory>(memories);
1778 }
1779
uncheckedConvert(const hardware::hidl_vec<hardware::hidl_memory> & memories)1780 std::vector<SharedMemory> uncheckedConvert(
1781 const hardware::hidl_vec<hardware::hidl_memory>& memories) {
1782 return convertVec<SharedMemory>(memories);
1783 }
1784
uncheckedConvert(const hardware::hidl_vec<V1_3::Subgraph> & subgraphs)1785 std::vector<Model::Subgraph> uncheckedConvert(const hardware::hidl_vec<V1_3::Subgraph>& subgraphs) {
1786 return convertVec<Model::Subgraph>(subgraphs);
1787 }
1788
uncheckedConvert(const hardware::hidl_vec<V1_3::Operand> & operands)1789 std::vector<Operand> uncheckedConvert(const hardware::hidl_vec<V1_3::Operand>& operands) {
1790 return convertVec<Operand>(operands);
1791 }
1792
1793 } // namespace nn
1794 } // namespace android
1795