1 // Copyright (c) 2018 Google LLC. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Validates correctness of barrier SPIR-V instructions. 16 17 #include "source/val/validate.h" 18 19 #include <string> 20 21 #include "source/diagnostic.h" 22 #include "source/opcode.h" 23 #include "source/spirv_constant.h" 24 #include "source/spirv_target_env.h" 25 #include "source/util/bitutils.h" 26 #include "source/val/instruction.h" 27 #include "source/val/validate_memory_semantics.h" 28 #include "source/val/validate_scopes.h" 29 #include "source/val/validation_state.h" 30 31 namespace spvtools { 32 namespace val { 33 34 // Validates correctness of barrier instructions. 35 spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { 36 const SpvOp opcode = inst->opcode(); 37 const uint32_t result_type = inst->type_id(); 38 39 switch (opcode) { 40 case SpvOpControlBarrier: { 41 if (spvVersionForTargetEnv(_.context()->target_env) < 42 SPV_SPIRV_VERSION_WORD(1, 3)) { 43 _.function(inst->function()->id()) 44 ->RegisterExecutionModelLimitation( 45 [](SpvExecutionModel model, std::string* message) { 46 if (model != SpvExecutionModelTessellationControl && 47 model != SpvExecutionModelGLCompute && 48 model != SpvExecutionModelKernel && 49 model != SpvExecutionModelTaskNV && 50 model != SpvExecutionModelMeshNV) { 51 if (message) { 52 *message = 53 "OpControlBarrier requires one of the following " 54 "Execution " 55 "Models: TessellationControl, GLCompute or Kernel"; 56 } 57 return false; 58 } 59 return true; 60 }); 61 } 62 63 const uint32_t execution_scope = inst->word(1); 64 const uint32_t memory_scope = inst->word(2); 65 66 if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { 67 return error; 68 } 69 70 if (auto error = ValidateMemoryScope(_, inst, memory_scope)) { 71 return error; 72 } 73 74 if (auto error = ValidateMemorySemantics(_, inst, 2)) { 75 return error; 76 } 77 break; 78 } 79 80 case SpvOpMemoryBarrier: { 81 const uint32_t memory_scope = inst->word(1); 82 83 if (auto error = ValidateMemoryScope(_, inst, memory_scope)) { 84 return error; 85 } 86 87 if (auto error = ValidateMemorySemantics(_, inst, 1)) { 88 return error; 89 } 90 break; 91 } 92 93 case SpvOpNamedBarrierInitialize: { 94 if (_.GetIdOpcode(result_type) != SpvOpTypeNamedBarrier) { 95 return _.diag(SPV_ERROR_INVALID_DATA, inst) 96 << spvOpcodeString(opcode) 97 << ": expected Result Type to be OpTypeNamedBarrier"; 98 } 99 100 const uint32_t subgroup_count_type = _.GetOperandTypeId(inst, 2); 101 if (!_.IsIntScalarType(subgroup_count_type) || 102 _.GetBitWidth(subgroup_count_type) != 32) { 103 return _.diag(SPV_ERROR_INVALID_DATA, inst) 104 << spvOpcodeString(opcode) 105 << ": expected Subgroup Count to be a 32-bit int"; 106 } 107 break; 108 } 109 110 case SpvOpMemoryNamedBarrier: { 111 const uint32_t named_barrier_type = _.GetOperandTypeId(inst, 0); 112 if (_.GetIdOpcode(named_barrier_type) != SpvOpTypeNamedBarrier) { 113 return _.diag(SPV_ERROR_INVALID_DATA, inst) 114 << spvOpcodeString(opcode) 115 << ": expected Named Barrier to be of type OpTypeNamedBarrier"; 116 } 117 118 const uint32_t memory_scope = inst->word(2); 119 120 if (auto error = ValidateMemoryScope(_, inst, memory_scope)) { 121 return error; 122 } 123 124 if (auto error = ValidateMemorySemantics(_, inst, 2)) { 125 return error; 126 } 127 break; 128 } 129 130 default: 131 break; 132 } 133 134 return SPV_SUCCESS; 135 } 136 137 } // namespace val 138 } // namespace spvtools 139