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.
BarriersPass(ValidationState_t & _,const Instruction * inst)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