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