From: Ehsan Nasiri Date: Tue, 29 Nov 2016 20:50:34 +0000 (-0500) Subject: Validate the number of global and local variables. X-Git-Tag: upstream/2018.6~999 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4b26d514efa4eaf5e1069c5ca974d558d0391334;p=platform%2Fupstream%2FSPIRV-Tools.git Validate the number of global and local variables. According to the Universal Limits section of the SPIR-V Spec (2.17), the number of global variables may not exceed 65,535 and the number of local variables may not exceed 524,287. Also added unit tests for each one. --- diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index c69749c..b11e6fc 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -192,6 +192,8 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx) module_capabilities_(), ordered_instructions_(), all_definitions_(), + num_global_vars_(0), + num_local_vars_(0), grammar_(ctx), addressing_model_(SpvAddressingModelLogical), memory_model_(SpvMemoryModelSimple), diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 7e69a9d..ad90ef9 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -193,6 +193,18 @@ class ValidationState_t { void RegisterSampledImageConsumer(uint32_t sampled_image_id, uint32_t cons_id); + /// Returns the number of Global Variables + uint32_t num_global_vars() { return num_global_vars_; } + + /// Returns the number of Local Variables + uint32_t num_local_vars() { return num_local_vars_; } + + /// Increments the number of Global Variables + void incrementNumGlobalVars() { ++num_global_vars_; } + + /// Increments the number of Local Variables + void incrementNumLocalVars() { ++num_local_vars_; } + private: ValidationState_t(const ValidationState_t&); @@ -236,6 +248,12 @@ class ValidationState_t { /// ID Bound from the Header uint32_t id_bound_; + /// Number of Global Variables (Storage Class other than 'Function') + uint32_t num_global_vars_; + + /// Number of Local Variables ('Function' Storage Class) + uint32_t num_local_vars_; + AssemblyGrammar grammar_; SpvAddressingModel addressing_model_; diff --git a/source/validate_instruction.cpp b/source/validate_instruction.cpp index 3fdd362..0b3d0c0 100644 --- a/source/validate_instruction.cpp +++ b/source/validate_instruction.cpp @@ -176,6 +176,31 @@ spv_result_t LimitCheckSwitch(ValidationState_t& _, return SPV_SUCCESS; } +// Ensure the number of variables of the given class does not exceed the limit. +spv_result_t LimitCheckNumVars(ValidationState_t& _, + const SpvStorageClass storage_class) { + if (SpvStorageClassFunction == storage_class) { + _.incrementNumLocalVars(); + const uint32_t num_local_vars_limit = 0x7FFFF; + if (_.num_local_vars() > num_local_vars_limit) { + return _.diag(SPV_ERROR_INVALID_BINARY) + << "Number of local variables ('Function' Storage Class) " + "exceeded the valid limit (" + << num_local_vars_limit << ")."; + } + } else { + _.incrementNumGlobalVars(); + const uint32_t num_global_vars_limit = 0xFFFF; + if (_.num_global_vars() > num_global_vars_limit) { + return _.diag(SPV_ERROR_INVALID_BINARY) + << "Number of Global Variables (Storage Class other than " + "'Function') exceeded the valid limit (" + << num_global_vars_limit << ")."; + } + } + return SPV_SUCCESS; +} + spv_result_t InstructionPass(ValidationState_t& _, const spv_parsed_instruction_t* inst) { const SpvOp opcode = static_cast(inst->opcode); @@ -191,6 +216,9 @@ spv_result_t InstructionPass(ValidationState_t& _, if (opcode == SpvOpVariable) { const auto storage_class = static_cast(inst->words[inst->operands[2].offset]); + if (auto error = LimitCheckNumVars(_, storage_class)) { + return error; + } if (storage_class == SpvStorageClassGeneric) return _.diag(SPV_ERROR_INVALID_BINARY) << "OpVariable storage class cannot be Generic"; diff --git a/test/val/val_limits_test.cpp b/test/val/val_limits_test.cpp index 0d34259..3774afe 100644 --- a/test/val/val_limits_test.cpp +++ b/test/val/val_limits_test.cpp @@ -194,3 +194,96 @@ TEST_F(ValidateLimits, OpTypeFunctionBad) { HasSubstr("OpTypeFunction may not take more than 255 arguments. " "OpTypeFunction '2' has 256 arguments.")); } + +// Valid: module has 65,535 global variables. +TEST_F(ValidateLimits, NumGlobalVarsGood) { + int num_globals = 65535; + std::ostringstream spirv; + spirv << header << R"( + %int = OpTypeInt 32 0 +%_ptr_int = OpTypePointer Input %int + )"; + + for (int i = 0; i < num_globals; ++i) { + spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n"; + } + + CompileSuccessfully(spirv.str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +// Invalid: module has 65,536 global variables (limit is 65,535). +TEST_F(ValidateLimits, NumGlobalVarsBad) { + int num_globals = 65536; + std::ostringstream spirv; + spirv << header << R"( + %int = OpTypeInt 32 0 +%_ptr_int = OpTypePointer Input %int + )"; + + for (int i = 0; i < num_globals; ++i) { + spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n"; + } + + CompileSuccessfully(spirv.str()); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Number of Global Variables (Storage Class other than " + "'Function') exceeded the valid limit (65535).")); +} + +// Valid: module has 524,287 local variables. +TEST_F(ValidateLimits, NumLocalVarsGood) { + int num_locals = 524287; + std::ostringstream spirv; + spirv << header << R"( + %int = OpTypeInt 32 0 + %_ptr_int = OpTypePointer Function %int + %voidt = OpTypeVoid + %funct = OpTypeFunction %voidt + %main = OpFunction %voidt None %funct + %entry = OpLabel + )"; + + for (int i = 0; i < num_locals; ++i) { + spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n"; + } + + spirv << R"( + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv.str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +// Invalid: module has 524,288 local variables (limit is 524,287). +TEST_F(ValidateLimits, NumLocalVarsBad) { + int num_locals = 524288; + std::ostringstream spirv; + spirv << header << R"( + %int = OpTypeInt 32 0 + %_ptr_int = OpTypePointer Function %int + %voidt = OpTypeVoid + %funct = OpTypeFunction %voidt + %main = OpFunction %voidt None %funct + %entry = OpLabel + )"; + + for (int i = 0; i < num_locals; ++i) { + spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n"; + } + + spirv << R"( + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv.str()); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Number of local variables ('Function' Storage Class) " + "exceeded the valid limit (524287).")); +} +