diff options
Diffstat (limited to 'nn/common')
-rw-r--r-- | nn/common/Utils.cpp | 15 | ||||
-rw-r--r-- | nn/common/ValidateHal.cpp | 25 | ||||
-rw-r--r-- | nn/common/include/Utils.h | 3 | ||||
-rw-r--r-- | nn/common/include/ValidateHal.h | 6 |
4 files changed, 38 insertions, 11 deletions
diff --git a/nn/common/Utils.cpp b/nn/common/Utils.cpp index 188436f11..1694c9c23 100644 --- a/nn/common/Utils.cpp +++ b/nn/common/Utils.cpp @@ -762,6 +762,15 @@ static bool validateIfOperation(uint32_t inputCount, const uint32_t* inputs, uin return true; } +static bool validateControlFlowOperandUnknownSize(const SubgraphValidationHelper& helper, + const Operand& operand) { + if (!helper.allowControlFlowOperationWithOperandOfUnknownSize && + !isExtensionOperandType(operand.type)) { + NN_RET_CHECK_NE(nonExtensionOperandSizeOfData(operand.type, operand.dimensions), 0u); + } + return true; +} + static bool validateWhileOperation(uint32_t inputCount, const uint32_t* inputs, uint32_t outputCount, const uint32_t* outputs, const std::vector<Operand>& operands, @@ -789,6 +798,8 @@ static bool validateWhileOperation(uint32_t inputCount, const uint32_t* inputs, const Operand& innerOperand = *helper.getSubgraphInputOperand(condModelOperand, i); const Operand& outerOperand = operands[inputs[op::kFirstInput + i]]; NN_RET_CHECK(compatible(innerOperand, outerOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, innerOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, outerOperand)); } NN_RET_CHECK( validateConditionOperand(*helper.getSubgraphOutputOperand(condModelOperand, 0))); @@ -809,16 +820,20 @@ static bool validateWhileOperation(uint32_t inputCount, const uint32_t* inputs, const Operand& innerOperand = *helper.getSubgraphInputOperand(bodyModelOperand, i); const Operand& outerOperand = operands[inputs[op::kFirstInput + i]]; NN_RET_CHECK(compatible(innerOperand, outerOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, innerOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, outerOperand)); } for (uint32_t i = 0; i < inputOutputCount; ++i) { const Operand& innerOperand = *helper.getSubgraphOutputOperand(bodyModelOperand, i); const Operand& outerOperand = operands[outputs[i]]; NN_RET_CHECK(compatible(innerOperand, outerOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, outerOperand)); } for (uint32_t i = 0, n = inputOutputCount + stateOnlyCount; i < n; ++i) { const Operand& inputOperand = *helper.getSubgraphInputOperand(bodyModelOperand, i); const Operand& outputOperand = *helper.getSubgraphOutputOperand(bodyModelOperand, i); NN_RET_CHECK(compatible(inputOperand, outputOperand)); + NN_RET_CHECK(validateControlFlowOperandUnknownSize(helper, outputOperand)); } return true; }; diff --git a/nn/common/ValidateHal.cpp b/nn/common/ValidateHal.cpp index 5668ff5ab..e5b9b12a8 100644 --- a/nn/common/ValidateHal.cpp +++ b/nn/common/ValidateHal.cpp @@ -448,7 +448,7 @@ static HalVersion getHalVersion(const V1_3::Operation&) { template <typename VersionedOperation> static bool validateOperations(const hidl_vec<VersionedOperation>& operations, const hidl_vec<Operand>& operands, - const hidl_vec<Subgraph>& subgraphs) { + const hidl_vec<Subgraph>& subgraphs, ValidationMode mode) { auto isValidSubgraphReference = [&subgraphs](const Operand& modelOperand) -> bool { NN_RET_CHECK(modelOperand.type == OperandType::SUBGRAPH) << "Unexpected operand type: " << toString(modelOperand.type); @@ -490,7 +490,11 @@ static bool validateOperations(const hidl_vec<VersionedOperation>& operations, .getSubgraphInputCount = getInputCount, .getSubgraphOutputCount = getOutputCount, .getSubgraphInputOperand = getInputOperand, - .getSubgraphOutputOperand = getOutputOperand}); + .getSubgraphOutputOperand = getOutputOperand, + // 1.3 HAL does not support CF operations with operands of + // unknown size. See http://b/132458982#comment63. + .allowControlFlowOperationWithOperandOfUnknownSize = + mode == ValidationMode::RUNTIME}); if (error != ANEURALNETWORKS_NO_ERROR) { LOG(ERROR) << "Invalid operation " << toString(op.type); return false; @@ -687,7 +691,7 @@ static bool checkNoReferenceCycles(const V1_3::Model& model) { } template <class T_Model> -bool validateModel(const T_Model& model) { +bool validateModel(const T_Model& model, ValidationMode mode) { NNTRACE_FULL(NNTRACE_LAYER_UTILITY, NNTRACE_PHASE_UNSPECIFIED, "validateModel"); HalVersion version = ModelToHalVersion<T_Model>::version; if (model.operations.size() == 0 || model.operands.size() == 0) { @@ -699,7 +703,7 @@ bool validateModel(const T_Model& model) { const hidl_vec<Operand> latestVersionOperands = convertToV1_3(model.operands); return (validateOperands(model.operands, model.operandValues, model.pools, /*subgraphs=*/{}, /*allowUnspecifiedRank=*/version >= HalVersion::V1_2) && - validateOperations(model.operations, latestVersionOperands, /*subgraphs=*/{}) && + validateOperations(model.operations, latestVersionOperands, /*subgraphs=*/{}, mode) && validateModelInputOutputs(model.inputIndexes, latestVersionOperands, OperandLifeTime::SUBGRAPH_INPUT) && validateModelInputOutputs(model.outputIndexes, latestVersionOperands, @@ -707,21 +711,22 @@ bool validateModel(const T_Model& model) { validatePools(model.pools, version) && validateGraph(model)); } -template bool validateModel<V1_0::Model>(const V1_0::Model& model); -template bool validateModel<V1_1::Model>(const V1_1::Model& model); -template bool validateModel<V1_2::Model>(const V1_2::Model& model); +template bool validateModel<V1_0::Model>(const V1_0::Model& model, ValidationMode mode); +template bool validateModel<V1_1::Model>(const V1_1::Model& model, ValidationMode mode); +template bool validateModel<V1_2::Model>(const V1_2::Model& model, ValidationMode mode); template <> -bool validateModel(const V1_3::Model& model) { +bool validateModel(const V1_3::Model& model, ValidationMode mode) { NNTRACE_FULL(NNTRACE_LAYER_UTILITY, NNTRACE_PHASE_UNSPECIFIED, "validateModel"); if (model.main.operations.size() == 0 || model.main.operands.size() == 0) { LOG(ERROR) << "Invalid empty model."; return false; } - auto validateSubgraph = [&model](const Subgraph& subgraph) -> bool { + auto validateSubgraph = [&model, mode](const Subgraph& subgraph) -> bool { return (validateOperands(subgraph.operands, model.operandValues, model.pools, model.referenced, /*allowUnspecifiedRank=*/true) && - validateOperations(subgraph.operations, subgraph.operands, model.referenced) && + validateOperations(subgraph.operations, subgraph.operands, model.referenced, + mode) && validateModelInputOutputs(subgraph.inputIndexes, subgraph.operands, OperandLifeTime::SUBGRAPH_INPUT) && validateModelInputOutputs(subgraph.outputIndexes, subgraph.operands, diff --git a/nn/common/include/Utils.h b/nn/common/include/Utils.h index ca11c5ebc..4bbbf8215 100644 --- a/nn/common/include/Utils.h +++ b/nn/common/include/Utils.h @@ -391,6 +391,9 @@ struct SubgraphValidationHelper { std::function<const hal::Operand*(const hal::Operand&, uint32_t)> getSubgraphInputOperand; // Gets the specified output operand of a subgraph referenced by a given operand. std::function<const hal::Operand*(const hal::Operand&, uint32_t)> getSubgraphOutputOperand; + // Whether control flow operations with inner or outer input or output + // operands of unknown size are allowed. + bool allowControlFlowOperationWithOperandOfUnknownSize; }; // Returns ANEURALNETWORKS_NO_ERROR if the corresponding operation is defined and can handle the diff --git a/nn/common/include/ValidateHal.h b/nn/common/include/ValidateHal.h index 7b097fd20..32d7662ed 100644 --- a/nn/common/include/ValidateHal.h +++ b/nn/common/include/ValidateHal.h @@ -37,6 +37,10 @@ enum class HalVersion : int32_t { enum class IOType { INPUT, OUTPUT }; using PreparedModelRole = std::tuple<const hal::IPreparedModel*, IOType, uint32_t>; +// 1.3 HAL does not support control flow operations with operands of unknown size. +// See http://b/132458982#comment63. +enum class ValidationMode { DRIVER, RUNTIME }; + // Verifies that the model is valid, i.e. it is consistent, takes // only acceptable values, the constants don't extend outside the memory // regions they are part of, etc. @@ -44,7 +48,7 @@ using PreparedModelRole = std::tuple<const hal::IPreparedModel*, IOType, uint32_ // are correctly defined, as these are specific to each implementation. // Each driver should do their own validation of OEM types. template <class T_Model> -bool validateModel(const T_Model& model); +bool validateModel(const T_Model& model, ValidationMode mode = ValidationMode::DRIVER); // Verifies that the request for the given model is valid. // IMPORTANT: This function cannot validate that OEM operation and operands |