1// Copyright (c) 2018 Google LLC. 2// Copyright (c) 2019 NVIDIA Corporation 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#include "source/val/validate.h" 17 18#include "source/opcode.h" 19#include "source/spirv_target_env.h" 20#include "source/val/instruction.h" 21#include "source/val/validate_scopes.h" 22#include "source/val/validation_state.h" 23 24namespace spvtools { 25namespace val { 26namespace { 27 28spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) { 29 if (_.IsVoidType(inst->type_id())) { 30 return _.diag(SPV_ERROR_INVALID_ID, inst) 31 << "Cannot create undefined values with void type"; 32 } 33 if (_.HasCapability(spv::Capability::Shader) && 34 _.ContainsLimitedUseIntOrFloatType(inst->type_id()) && 35 !_.IsPointerType(inst->type_id())) { 36 return _.diag(SPV_ERROR_INVALID_ID, inst) 37 << "Cannot create undefined values with 8- or 16-bit types"; 38 } 39 40 return SPV_SUCCESS; 41} 42 43spv_result_t ValidateShaderClock(ValidationState_t& _, 44 const Instruction* inst) { 45 const uint32_t scope = inst->GetOperandAs<uint32_t>(2); 46 if (auto error = ValidateScope(_, inst, scope)) { 47 return error; 48 } 49 50 bool is_int32 = false, is_const_int32 = false; 51 uint32_t value = 0; 52 std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); 53 if (is_const_int32 && spv::Scope(value) != spv::Scope::Subgroup && 54 spv::Scope(value) != spv::Scope::Device) { 55 return _.diag(SPV_ERROR_INVALID_DATA, inst) 56 << _.VkErrorID(4652) << "Scope must be Subgroup or Device"; 57 } 58 59 // Result Type must be a 64 - bit unsigned integer type or 60 // a vector of two - components of 32 - 61 // bit unsigned integer type 62 const uint32_t result_type = inst->type_id(); 63 if (!_.IsUnsigned64BitHandle(result_type)) { 64 return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a " 65 "vector of two components" 66 " of unsigned integer" 67 " or 64bit unsigned integer"; 68 } 69 70 return SPV_SUCCESS; 71} 72 73spv_result_t ValidateAssumeTrue(ValidationState_t& _, const Instruction* inst) { 74 const auto operand_type_id = _.GetOperandTypeId(inst, 0); 75 if (!operand_type_id || !_.IsBoolScalarType(operand_type_id)) { 76 return _.diag(SPV_ERROR_INVALID_ID, inst) 77 << "Value operand of OpAssumeTrueKHR must be a boolean scalar"; 78 } 79 return SPV_SUCCESS; 80} 81 82spv_result_t ValidateExpect(ValidationState_t& _, const Instruction* inst) { 83 const auto result_type = inst->type_id(); 84 if (!_.IsBoolScalarOrVectorType(result_type) && 85 !_.IsIntScalarOrVectorType(result_type)) { 86 return _.diag(SPV_ERROR_INVALID_ID, inst) 87 << "Result of OpExpectKHR must be a scalar or vector of integer " 88 "type or boolean type"; 89 } 90 91 if (_.GetOperandTypeId(inst, 2) != result_type) { 92 return _.diag(SPV_ERROR_INVALID_ID, inst) 93 << "Type of Value operand of OpExpectKHR does not match the result " 94 "type "; 95 } 96 if (_.GetOperandTypeId(inst, 3) != result_type) { 97 return _.diag(SPV_ERROR_INVALID_ID, inst) 98 << "Type of ExpectedValue operand of OpExpectKHR does not match the " 99 "result type "; 100 } 101 return SPV_SUCCESS; 102} 103 104} // namespace 105 106spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) { 107 switch (inst->opcode()) { 108 case spv::Op::OpUndef: 109 if (auto error = ValidateUndef(_, inst)) return error; 110 break; 111 default: 112 break; 113 } 114 switch (inst->opcode()) { 115 case spv::Op::OpBeginInvocationInterlockEXT: 116 case spv::Op::OpEndInvocationInterlockEXT: 117 _.function(inst->function()->id()) 118 ->RegisterExecutionModelLimitation( 119 spv::ExecutionModel::Fragment, 120 "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " 121 "require Fragment execution model"); 122 123 _.function(inst->function()->id()) 124 ->RegisterLimitation([](const ValidationState_t& state, 125 const Function* entry_point, 126 std::string* message) { 127 const auto* execution_modes = 128 state.GetExecutionModes(entry_point->id()); 129 130 auto find_interlock = [](const spv::ExecutionMode& mode) { 131 switch (mode) { 132 case spv::ExecutionMode::PixelInterlockOrderedEXT: 133 case spv::ExecutionMode::PixelInterlockUnorderedEXT: 134 case spv::ExecutionMode::SampleInterlockOrderedEXT: 135 case spv::ExecutionMode::SampleInterlockUnorderedEXT: 136 case spv::ExecutionMode::ShadingRateInterlockOrderedEXT: 137 case spv::ExecutionMode::ShadingRateInterlockUnorderedEXT: 138 return true; 139 default: 140 return false; 141 } 142 }; 143 144 bool found = false; 145 if (execution_modes) { 146 auto i = std::find_if(execution_modes->begin(), 147 execution_modes->end(), find_interlock); 148 found = (i != execution_modes->end()); 149 } 150 151 if (!found) { 152 *message = 153 "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " 154 "require a fragment shader interlock execution mode."; 155 return false; 156 } 157 return true; 158 }); 159 break; 160 case spv::Op::OpDemoteToHelperInvocationEXT: 161 _.function(inst->function()->id()) 162 ->RegisterExecutionModelLimitation( 163 spv::ExecutionModel::Fragment, 164 "OpDemoteToHelperInvocationEXT requires Fragment execution " 165 "model"); 166 break; 167 case spv::Op::OpIsHelperInvocationEXT: { 168 const uint32_t result_type = inst->type_id(); 169 _.function(inst->function()->id()) 170 ->RegisterExecutionModelLimitation( 171 spv::ExecutionModel::Fragment, 172 "OpIsHelperInvocationEXT requires Fragment execution model"); 173 if (!_.IsBoolScalarType(result_type)) 174 return _.diag(SPV_ERROR_INVALID_DATA, inst) 175 << "Expected bool scalar type as Result Type: " 176 << spvOpcodeString(inst->opcode()); 177 break; 178 } 179 case spv::Op::OpReadClockKHR: 180 if (auto error = ValidateShaderClock(_, inst)) { 181 return error; 182 } 183 break; 184 case spv::Op::OpAssumeTrueKHR: 185 if (auto error = ValidateAssumeTrue(_, inst)) { 186 return error; 187 } 188 break; 189 case spv::Op::OpExpectKHR: 190 if (auto error = ValidateExpect(_, inst)) { 191 return error; 192 } 193 break; 194 default: 195 break; 196 } 197 198 return SPV_SUCCESS; 199} 200 201} // namespace val 202} // namespace spvtools 203