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