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