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