xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/val/validate_barriers.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 <string>
18 
19 #include "source/opcode.h"
20 #include "source/spirv_constant.h"
21 #include "source/val/instruction.h"
22 #include "source/val/validate.h"
23 #include "source/val/validate_memory_semantics.h"
24 #include "source/val/validate_scopes.h"
25 #include "source/val/validation_state.h"
26 
27 namespace spvtools {
28 namespace val {
29 
30 // Validates correctness of barrier instructions.
BarriersPass(ValidationState_t & _,const Instruction * inst)31 spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) {
32   const spv::Op opcode = inst->opcode();
33   const uint32_t result_type = inst->type_id();
34 
35   switch (opcode) {
36     case spv::Op::OpControlBarrier: {
37       if (_.version() < SPV_SPIRV_VERSION_WORD(1, 3)) {
38         _.function(inst->function()->id())
39             ->RegisterExecutionModelLimitation(
40                 [](spv::ExecutionModel model, std::string* message) {
41                   if (model != spv::ExecutionModel::TessellationControl &&
42                       model != spv::ExecutionModel::GLCompute &&
43                       model != spv::ExecutionModel::Kernel &&
44                       model != spv::ExecutionModel::TaskNV &&
45                       model != spv::ExecutionModel::MeshNV) {
46                     if (message) {
47                       *message =
48                           "OpControlBarrier requires one of the following "
49                           "Execution "
50                           "Models: TessellationControl, GLCompute, Kernel, "
51                           "MeshNV or TaskNV";
52                     }
53                     return false;
54                   }
55                   return true;
56                 });
57       }
58 
59       const uint32_t execution_scope = inst->word(1);
60       const uint32_t memory_scope = inst->word(2);
61 
62       if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
63         return error;
64       }
65 
66       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
67         return error;
68       }
69 
70       if (auto error = ValidateMemorySemantics(_, inst, 2, memory_scope)) {
71         return error;
72       }
73       break;
74     }
75 
76     case spv::Op::OpMemoryBarrier: {
77       const uint32_t memory_scope = inst->word(1);
78 
79       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
80         return error;
81       }
82 
83       if (auto error = ValidateMemorySemantics(_, inst, 1, memory_scope)) {
84         return error;
85       }
86       break;
87     }
88 
89     case spv::Op::OpNamedBarrierInitialize: {
90       if (_.GetIdOpcode(result_type) != spv::Op::OpTypeNamedBarrier) {
91         return _.diag(SPV_ERROR_INVALID_DATA, inst)
92                << spvOpcodeString(opcode)
93                << ": expected Result Type to be OpTypeNamedBarrier";
94       }
95 
96       const uint32_t subgroup_count_type = _.GetOperandTypeId(inst, 2);
97       if (!_.IsIntScalarType(subgroup_count_type) ||
98           _.GetBitWidth(subgroup_count_type) != 32) {
99         return _.diag(SPV_ERROR_INVALID_DATA, inst)
100                << spvOpcodeString(opcode)
101                << ": expected Subgroup Count to be a 32-bit int";
102       }
103       break;
104     }
105 
106     case spv::Op::OpMemoryNamedBarrier: {
107       const uint32_t named_barrier_type = _.GetOperandTypeId(inst, 0);
108       if (_.GetIdOpcode(named_barrier_type) != spv::Op::OpTypeNamedBarrier) {
109         return _.diag(SPV_ERROR_INVALID_DATA, inst)
110                << spvOpcodeString(opcode)
111                << ": expected Named Barrier to be of type OpTypeNamedBarrier";
112       }
113 
114       const uint32_t memory_scope = inst->word(2);
115 
116       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
117         return error;
118       }
119 
120       if (auto error = ValidateMemorySemantics(_, inst, 2, memory_scope)) {
121         return error;
122       }
123       break;
124     }
125 
126     default:
127       break;
128   }
129 
130   return SPV_SUCCESS;
131 }
132 
133 }  // namespace val
134 }  // namespace spvtools
135