diff options
Diffstat (limited to 'source/val/validate_cfg.cpp')
-rw-r--r-- | source/val/validate_cfg.cpp | 147 |
1 files changed, 70 insertions, 77 deletions
diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 9ba66f42..cc0b999f 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -54,7 +54,7 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { << "OpPhi must not have void result type"; } if (_.IsPointerType(inst->type_id()) && - _.addressing_model() == spv::AddressingModel::Logical) { + _.addressing_model() == SpvAddressingModelLogical) { if (!_.features().variable_pointers) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Using pointers with OpPhi requires capability " @@ -64,14 +64,13 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { const Instruction* type_inst = _.FindDef(inst->type_id()); assert(type_inst); - const spv::Op type_opcode = type_inst->opcode(); + const SpvOp type_opcode = type_inst->opcode(); if (!_.options()->before_hlsl_legalization && - !_.HasCapability(spv::Capability::BindlessTextureNV)) { - if (type_opcode == spv::Op::OpTypeSampledImage || - (_.HasCapability(spv::Capability::Shader) && - (type_opcode == spv::Op::OpTypeImage || - type_opcode == spv::Op::OpTypeSampler))) { + !_.HasCapability(SpvCapabilityBindlessTextureNV)) { + if (type_opcode == SpvOpTypeSampledImage || + (_.HasCapability(SpvCapabilityShader) && + (type_opcode == SpvOpTypeImage || type_opcode == SpvOpTypeSampler))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Result type cannot be Op" << spvOpcodeString(type_opcode); } @@ -109,7 +108,7 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { << " type <id> " << _.getIdName(inc_type_id) << "."; } } else { - if (_.GetIdOpcode(inc_id) != spv::Op::OpLabel) { + if (_.GetIdOpcode(inc_id) != SpvOpLabel) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpPhi's incoming basic block <id> " << _.getIdName(inc_id) << " is not an OpLabel."; @@ -144,7 +143,7 @@ spv_result_t ValidateBranch(ValidationState_t& _, const Instruction* inst) { // target operands must be OpLabel const auto id = inst->GetOperandAs<uint32_t>(0); const auto target = _.FindDef(id); - if (!target || spv::Op::OpLabel != target->opcode()) { + if (!target || SpvOpLabel != target->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "'Target Label' operands for OpBranch must be the ID " "of an OpLabel instruction"; @@ -179,7 +178,7 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, // PerformCfgChecks already checks for that const auto true_id = inst->GetOperandAs<uint32_t>(1); const auto true_target = _.FindDef(true_id); - if (!true_target || spv::Op::OpLabel != true_target->opcode()) { + if (!true_target || SpvOpLabel != true_target->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "The 'True Label' operand for OpBranchConditional must be the " "ID of an OpLabel instruction"; @@ -187,7 +186,7 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, const auto false_id = inst->GetOperandAs<uint32_t>(2); const auto false_target = _.FindDef(false_id); - if (!false_target || spv::Op::OpLabel != false_target->opcode()) { + if (!false_target || SpvOpLabel != false_target->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "The 'False Label' operand for OpBranchConditional must be the " "ID of an OpLabel instruction"; @@ -214,7 +213,7 @@ spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) { } const auto default_label = _.FindDef(inst->GetOperandAs<uint32_t>(1)); - if (default_label->opcode() != spv::Op::OpLabel) { + if (default_label->opcode() != SpvOpLabel) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Default must be an OpLabel instruction"; } @@ -224,7 +223,7 @@ spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) { // literal, id const auto id = inst->GetOperandAs<uint32_t>(i + 1); const auto target = _.FindDef(id); - if (!target || spv::Op::OpLabel != target->opcode()) { + if (!target || SpvOpLabel != target->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "'Target Label' operands for OpSwitch must be IDs of an " "OpLabel instruction"; @@ -244,14 +243,14 @@ spv_result_t ValidateReturnValue(ValidationState_t& _, << " does not represent a value."; } auto value_type = _.FindDef(value->type_id()); - if (!value_type || spv::Op::OpTypeVoid == value_type->opcode()) { + if (!value_type || SpvOpTypeVoid == value_type->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpReturnValue value's type <id> " << _.getIdName(value->type_id()) << " is missing or void."; } - if (_.addressing_model() == spv::AddressingModel::Logical && - spv::Op::OpTypePointer == value_type->opcode() && + if (_.addressing_model() == SpvAddressingModelLogical && + SpvOpTypePointer == value_type->opcode() && !_.features().variable_pointers && !_.options()->relax_logical_pointer) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpReturnValue value's type <id> " @@ -271,15 +270,10 @@ spv_result_t ValidateReturnValue(ValidationState_t& _, return SPV_SUCCESS; } -uint32_t operator>>(const spv::LoopControlShift& lhs, - const spv::LoopControlShift& rhs) { - return uint32_t(lhs) >> uint32_t(rhs); -} - spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { const auto merge_id = inst->GetOperandAs<uint32_t>(0); const auto merge = _.FindDef(merge_id); - if (!merge || merge->opcode() != spv::Op::OpLabel) { + if (!merge || merge->opcode() != SpvOpLabel) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Merge Block " << _.getIdName(merge_id) << " must be an OpLabel"; } @@ -290,7 +284,7 @@ spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { const auto continue_id = inst->GetOperandAs<uint32_t>(1); const auto continue_target = _.FindDef(continue_id); - if (!continue_target || continue_target->opcode() != spv::Op::OpLabel) { + if (!continue_target || continue_target->opcode() != SpvOpLabel) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Continue Target " << _.getIdName(continue_id) << " must be an OpLabel"; @@ -301,36 +295,36 @@ spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { << "Merge Block and Continue Target must be different ids"; } - const auto loop_control = inst->GetOperandAs<spv::LoopControlShift>(2); - if ((loop_control >> spv::LoopControlShift::Unroll) & 0x1 && - (loop_control >> spv::LoopControlShift::DontUnroll) & 0x1) { + const auto loop_control = inst->GetOperandAs<uint32_t>(2); + if ((loop_control >> SpvLoopControlUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlDontUnrollShift) & 0x1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Unroll and DontUnroll loop controls must not both be specified"; } - if ((loop_control >> spv::LoopControlShift::DontUnroll) & 0x1 && - (loop_control >> spv::LoopControlShift::PeelCount) & 0x1) { + if ((loop_control >> SpvLoopControlDontUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlPeelCountShift) & 0x1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PeelCount and DontUnroll " "loop controls must not " "both be specified"; } - if ((loop_control >> spv::LoopControlShift::DontUnroll) & 0x1 && - (loop_control >> spv::LoopControlShift::PartialCount) & 0x1) { + if ((loop_control >> SpvLoopControlDontUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlPartialCountShift) & 0x1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PartialCount and " "DontUnroll loop controls " "must not both be specified"; } uint32_t operand = 3; - if ((loop_control >> spv::LoopControlShift::DependencyLength) & 0x1) { + if ((loop_control >> SpvLoopControlDependencyLengthShift) & 0x1) { ++operand; } - if ((loop_control >> spv::LoopControlShift::MinIterations) & 0x1) { + if ((loop_control >> SpvLoopControlMinIterationsShift) & 0x1) { ++operand; } - if ((loop_control >> spv::LoopControlShift::MaxIterations) & 0x1) { + if ((loop_control >> SpvLoopControlMaxIterationsShift) & 0x1) { ++operand; } - if ((loop_control >> spv::LoopControlShift::IterationMultiple) & 0x1) { + if ((loop_control >> SpvLoopControlIterationMultipleShift) & 0x1) { if (inst->operands().size() < operand || inst->GetOperandAs<uint32_t>(operand) == 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "IterationMultiple loop " @@ -339,10 +333,10 @@ spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { } ++operand; } - if ((loop_control >> spv::LoopControlShift::PeelCount) & 0x1) { + if ((loop_control >> SpvLoopControlPeelCountShift) & 0x1) { ++operand; } - if ((loop_control >> spv::LoopControlShift::PartialCount) & 0x1) { + if ((loop_control >> SpvLoopControlPartialCountShift) & 0x1) { ++operand; } @@ -560,7 +554,7 @@ spv_result_t StructuredSwitchChecks(ValidationState_t& _, Function* function, target_block->structurally_reachable() && !header->structurally_dominates(*target_block)) { return _.diag(SPV_ERROR_INVALID_CFG, header->label()) - << "Switch header " << _.getIdName(header->id()) + << "Selection header " << _.getIdName(header->id()) << " does not structurally dominate its case construct " << _.getIdName(target); } @@ -650,9 +644,9 @@ spv_result_t ValidateStructuredSelections( const auto index = terminator - &_.ordered_instructions()[0]; auto* merge = &_.ordered_instructions()[index - 1]; // Marks merges and continues as seen. - if (merge->opcode() == spv::Op::OpSelectionMerge) { + if (merge->opcode() == SpvOpSelectionMerge) { seen.insert(merge->GetOperandAs<uint32_t>(0)); - } else if (merge->opcode() == spv::Op::OpLoopMerge) { + } else if (merge->opcode() == SpvOpLoopMerge) { seen.insert(merge->GetOperandAs<uint32_t>(0)); seen.insert(merge->GetOperandAs<uint32_t>(1)); } else { @@ -663,7 +657,7 @@ spv_result_t ValidateStructuredSelections( // Skip unreachable blocks. if (!block->structurally_reachable()) continue; - if (terminator->opcode() == spv::Op::OpBranchConditional) { + if (terminator->opcode() == SpvOpBranchConditional) { const auto true_label = terminator->GetOperandAs<uint32_t>(1); const auto false_label = terminator->GetOperandAs<uint32_t>(2); // Mark the upcoming blocks as seen now, but only error out if this block @@ -675,7 +669,7 @@ spv_result_t ValidateStructuredSelections( return _.diag(SPV_ERROR_INVALID_CFG, terminator) << "Selection must be structured"; } - } else if (terminator->opcode() == spv::Op::OpSwitch) { + } else if (terminator->opcode() == SpvOpSwitch) { if (!merge) { return _.diag(SPV_ERROR_INVALID_CFG, terminator) << "OpSwitch must be preceded by an OpSelectionMerge " @@ -752,7 +746,6 @@ spv_result_t StructuredControlFlowChecks( _.getIdName(merge->id()), "does not structurally dominate"); } - // If it's really a merge block for a selection or loop, then it must be // *strictly* structrually dominated by the header. if (construct.ExitBlockIsMergeBlock() && (header == merge)) { @@ -805,8 +798,8 @@ spv_result_t StructuredControlFlowChecks( block->is_type(BlockType::kBlockTypeLoop)) { size_t index = (block->terminator() - &_.ordered_instructions()[0]) - 1; const auto& merge_inst = _.ordered_instructions()[index]; - if (merge_inst.opcode() == spv::Op::OpSelectionMerge || - merge_inst.opcode() == spv::Op::OpLoopMerge) { + if (merge_inst.opcode() == SpvOpSelectionMerge || + merge_inst.opcode() == SpvOpLoopMerge) { uint32_t merge_id = merge_inst.GetOperandAs<uint32_t>(0); auto merge_block = function->GetBlock(merge_id).first; if (merge_block->structurally_reachable() && @@ -861,7 +854,7 @@ spv_result_t StructuredControlFlowChecks( // Checks rules for case constructs. if (construct.type() == ConstructType::kSelection && - header->terminator()->opcode() == spv::Op::OpSwitch) { + header->terminator()->opcode() == SpvOpSwitch) { const auto terminator = header->terminator(); if (auto error = StructuredSwitchChecks(_, function, terminator, header, merge)) { @@ -935,7 +928,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { } // If we have structured control flow, check that no block has a control // flow nesting depth larger than the limit. - if (_.HasCapability(spv::Capability::Shader)) { + if (_.HasCapability(SpvCapabilityShader)) { const int control_flow_nesting_depth_limit = _.options()->universal_limits_.max_control_flow_nesting_depth; for (auto block = begin(blocks); block != end(blocks); ++block) { @@ -949,7 +942,7 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { } /// Structured control flow checks are only required for shader capabilities - if (_.HasCapability(spv::Capability::Shader)) { + if (_.HasCapability(SpvCapabilityShader)) { // Calculate structural dominance. postorder.clear(); std::vector<const BasicBlock*> postdom_postorder; @@ -1005,9 +998,9 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { } spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { - spv::Op opcode = inst->opcode(); + SpvOp opcode = inst->opcode(); switch (opcode) { - case spv::Op::OpLabel: + case SpvOpLabel: if (auto error = _.current_function().RegisterBlock(inst->id())) return error; @@ -1016,7 +1009,7 @@ spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { // passes the OpLabel ends up not being part of the basic block it starts. _.current_function().current_block()->set_label(inst); break; - case spv::Op::OpLoopMerge: { + case SpvOpLoopMerge: { uint32_t merge_block = inst->GetOperandAs<uint32_t>(0); uint32_t continue_block = inst->GetOperandAs<uint32_t>(1); CFG_ASSERT(MergeBlockAssert, merge_block); @@ -1025,20 +1018,20 @@ spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { continue_block)) return error; } break; - case spv::Op::OpSelectionMerge: { + case SpvOpSelectionMerge: { uint32_t merge_block = inst->GetOperandAs<uint32_t>(0); CFG_ASSERT(MergeBlockAssert, merge_block); if (auto error = _.current_function().RegisterSelectionMerge(merge_block)) return error; } break; - case spv::Op::OpBranch: { + case SpvOpBranch: { uint32_t target = inst->GetOperandAs<uint32_t>(0); CFG_ASSERT(FirstBlockAssert, target); _.current_function().RegisterBlockEnd({target}); } break; - case spv::Op::OpBranchConditional: { + case SpvOpBranchConditional: { uint32_t tlabel = inst->GetOperandAs<uint32_t>(1); uint32_t flabel = inst->GetOperandAs<uint32_t>(2); CFG_ASSERT(FirstBlockAssert, tlabel); @@ -1047,7 +1040,7 @@ spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { _.current_function().RegisterBlockEnd({tlabel, flabel}); } break; - case spv::Op::OpSwitch: { + case SpvOpSwitch: { std::vector<uint32_t> cases; for (size_t i = 1; i < inst->operands().size(); i += 2) { uint32_t target = inst->GetOperandAs<uint32_t>(i); @@ -1056,44 +1049,44 @@ spv_result_t CfgPass(ValidationState_t& _, const Instruction* inst) { } _.current_function().RegisterBlockEnd({cases}); } break; - case spv::Op::OpReturn: { + case SpvOpReturn: { const uint32_t return_type = _.current_function().GetResultTypeId(); const Instruction* return_type_inst = _.FindDef(return_type); assert(return_type_inst); - if (return_type_inst->opcode() != spv::Op::OpTypeVoid) + if (return_type_inst->opcode() != SpvOpTypeVoid) return _.diag(SPV_ERROR_INVALID_CFG, inst) << "OpReturn can only be called from a function with void " << "return type."; _.current_function().RegisterBlockEnd(std::vector<uint32_t>()); break; } - case spv::Op::OpKill: - case spv::Op::OpReturnValue: - case spv::Op::OpUnreachable: - case spv::Op::OpTerminateInvocation: - case spv::Op::OpIgnoreIntersectionKHR: - case spv::Op::OpTerminateRayKHR: - case spv::Op::OpEmitMeshTasksEXT: + case SpvOpKill: + case SpvOpReturnValue: + case SpvOpUnreachable: + case SpvOpTerminateInvocation: + case SpvOpIgnoreIntersectionKHR: + case SpvOpTerminateRayKHR: + case SpvOpEmitMeshTasksEXT: _.current_function().RegisterBlockEnd(std::vector<uint32_t>()); // Ops with dedicated passes check for the Execution Model there - if (opcode == spv::Op::OpKill) { + if (opcode == SpvOpKill) { _.current_function().RegisterExecutionModelLimitation( - spv::ExecutionModel::Fragment, + SpvExecutionModelFragment, "OpKill requires Fragment execution model"); } - if (opcode == spv::Op::OpTerminateInvocation) { + if (opcode == SpvOpTerminateInvocation) { _.current_function().RegisterExecutionModelLimitation( - spv::ExecutionModel::Fragment, + SpvExecutionModelFragment, "OpTerminateInvocation requires Fragment execution model"); } - if (opcode == spv::Op::OpIgnoreIntersectionKHR) { + if (opcode == SpvOpIgnoreIntersectionKHR) { _.current_function().RegisterExecutionModelLimitation( - spv::ExecutionModel::AnyHitKHR, + SpvExecutionModelAnyHitKHR, "OpIgnoreIntersectionKHR requires AnyHitKHR execution model"); } - if (opcode == spv::Op::OpTerminateRayKHR) { + if (opcode == SpvOpTerminateRayKHR) { _.current_function().RegisterExecutionModelLimitation( - spv::ExecutionModel::AnyHitKHR, + SpvExecutionModelAnyHitKHR, "OpTerminateRayKHR requires AnyHitKHR execution model"); } @@ -1147,22 +1140,22 @@ void ReachabilityPass(ValidationState_t& _) { spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst) { switch (inst->opcode()) { - case spv::Op::OpPhi: + case SpvOpPhi: if (auto error = ValidatePhi(_, inst)) return error; break; - case spv::Op::OpBranch: + case SpvOpBranch: if (auto error = ValidateBranch(_, inst)) return error; break; - case spv::Op::OpBranchConditional: + case SpvOpBranchConditional: if (auto error = ValidateBranchConditional(_, inst)) return error; break; - case spv::Op::OpReturnValue: + case SpvOpReturnValue: if (auto error = ValidateReturnValue(_, inst)) return error; break; - case spv::Op::OpSwitch: + case SpvOpSwitch: if (auto error = ValidateSwitch(_, inst)) return error; break; - case spv::Op::OpLoopMerge: + case SpvOpLoopMerge: if (auto error = ValidateLoopMerge(_, inst)) return error; break; default: |