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
30namespace spvtools {
31namespace val {
32
33// Validates correctness of barrier instructions.
34spv_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