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. |
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)) { |
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)) { |
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)) { |
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 | |