1// Copyright (c) 2015-2016 The Khronos Group Inc.
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// Source code for logical layout validation as described in section 2.4
16
17#include <cassert>
18
19#include "DebugInfo.h"
20#include "OpenCLDebugInfo100.h"
21#include "source/diagnostic.h"
22#include "source/opcode.h"
23#include "source/operand.h"
24#include "source/val/function.h"
25#include "source/val/instruction.h"
26#include "source/val/validate.h"
27#include "source/val/validation_state.h"
28
29namespace spvtools {
30namespace val {
31namespace {
32
33// Module scoped instructions are processed by determining if the opcode
34// is part of the current layout section. If it is not then the next sections is
35// checked.
36spv_result_t ModuleScopedInstructions(ValidationState_t& _,
37 const Instruction* inst, SpvOp opcode) {
38 switch (opcode) {
39 case SpvOpExtInst:
40 if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
41 // non-semantic extinst opcodes are allowed beginning in the types
42 // section, but since they must name a return type they cannot be the
43 // first instruction in the types section. Therefore check that we are
44 // already in it.
45 if (_.current_layout_section() < kLayoutTypes) {
46 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
47 << "Non-semantic OpExtInst must not appear before types "
48 << "section";
49 }
50 } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
51 const uint32_t ext_inst_index = inst->word(4);
52 bool local_debug_info = false;
53 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
54 const OpenCLDebugInfo100Instructions ext_inst_key =
55 OpenCLDebugInfo100Instructions(ext_inst_index);
56 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
57 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
58 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
59 ext_inst_key == OpenCLDebugInfo100DebugValue) {
60 local_debug_info = true;
61 }
62 } else {
63 const DebugInfoInstructions ext_inst_key =
64 DebugInfoInstructions(ext_inst_index);
65 if (ext_inst_key == DebugInfoDebugScope ||
66 ext_inst_key == DebugInfoDebugNoScope ||
67 ext_inst_key == DebugInfoDebugDeclare ||
68 ext_inst_key == DebugInfoDebugValue) {
69 local_debug_info = true;
70 }
71 }
72
73 if (local_debug_info) {
74 if (_.in_function_body() == false) {
75 // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
76 // appear in a function body.
77 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
78 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
79 << "of debug info extension must appear in a function "
80 << "body";
81 }
82 } else {
83 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
84 // DebugDeclare, DebugValue must be placed between section 9 (types,
85 // constants, global variables) and section 10 (function
86 // declarations).
87 if (_.current_layout_section() < kLayoutTypes ||
88 _.current_layout_section() >= kLayoutFunctionDeclarations) {
89 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
90 << "Debug info extension instructions other than "
91 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
92 << "must appear between section 9 (types, constants, "
93 << "global variables) and section 10 (function "
94 << "declarations)";
95 }
96 }
97 } else {
98 // otherwise they must be used in a block
99 if (_.current_layout_section() < kLayoutFunctionDefinitions) {
100 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
101 << spvOpcodeString(opcode) << " must appear in a block";
102 }
103 }
104 break;
105 default:
106 break;
107 }
108
109 while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) {
110 _.ProgressToNextLayoutSectionOrder();
111
112 switch (_.current_layout_section()) {
113 case kLayoutMemoryModel:
114 if (opcode != SpvOpMemoryModel) {
115 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
116 << spvOpcodeString(opcode)
117 << " cannot appear before the memory model instruction";
118 }
119 break;
120 case kLayoutFunctionDeclarations:
121 // All module sections have been processed. Recursively call
122 // ModuleLayoutPass to process the next section of the module
123 return ModuleLayoutPass(_, inst);
124 default:
125 break;
126 }
127 }
128 return SPV_SUCCESS;
129}
130
131// Function declaration validation is performed by making sure that the
132// FunctionParameter and FunctionEnd instructions only appear inside of
133// functions. It also ensures that the Function instruction does not appear
134// inside of another function. This stage ends when the first label is
135// encountered inside of a function.
136spv_result_t FunctionScopedInstructions(ValidationState_t& _,
137 const Instruction* inst, SpvOp opcode) {
138 if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
139 switch (opcode) {
140 case SpvOpFunction: {
141 if (_.in_function_body()) {
142 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
143 << "Cannot declare a function in a function body";
144 }
145 auto control_mask = inst->GetOperandAs<SpvFunctionControlMask>(2);
146 if (auto error =
147 _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
148 inst->GetOperandAs<uint32_t>(3)))
149 return error;
150 if (_.current_layout_section() == kLayoutFunctionDefinitions) {
151 if (auto error = _.current_function().RegisterSetFunctionDeclType(
152 FunctionDecl::kFunctionDeclDefinition))
153 return error;
154 }
155 } break;
156
157 case SpvOpFunctionParameter:
158 if (_.in_function_body() == false) {
159 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
160 << "Function parameter instructions must be in a "
161 "function body";
162 }
163 if (_.current_function().block_count() != 0) {
164 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
165 << "Function parameters must only appear immediately after "
166 "the function definition";
167 }
168 if (auto error = _.current_function().RegisterFunctionParameter(
169 inst->id(), inst->type_id()))
170 return error;
171 break;
172
173 case SpvOpFunctionEnd:
174 if (_.in_function_body() == false) {
175 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
176 << "Function end instructions must be in a function body";
177 }
178 if (_.in_block()) {
179 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
180 << "Function end cannot be called in blocks";
181 }
182 if (_.current_function().block_count() == 0 &&
183 _.current_layout_section() == kLayoutFunctionDefinitions) {
184 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
185 << "Function declarations must appear before "
186 "function definitions.";
187 }
188 if (_.current_layout_section() == kLayoutFunctionDeclarations) {
189 if (auto error = _.current_function().RegisterSetFunctionDeclType(
190 FunctionDecl::kFunctionDeclDeclaration))
191 return error;
192 }
193 if (auto error = _.RegisterFunctionEnd()) return error;
194 break;
195
196 case SpvOpLine:
197 case SpvOpNoLine:
198 break;
199 case SpvOpLabel:
200 // If the label is encountered then the current function is a
201 // definition so set the function to a declaration and update the
202 // module section
203 if (_.in_function_body() == false) {
204 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
205 << "Label instructions must be in a function body";
206 }
207 if (_.in_block()) {
208 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
209 << "A block must end with a branch instruction.";
210 }
211 if (_.current_layout_section() == kLayoutFunctionDeclarations) {
212 _.ProgressToNextLayoutSectionOrder();
213 if (auto error = _.current_function().RegisterSetFunctionDeclType(
214 FunctionDecl::kFunctionDeclDefinition))
215 return error;
216 }
217 break;
218
219 case SpvOpExtInst:
220 if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
221 // non-semantic extinst opcodes are allowed beginning in the types
222 // section, but must either be placed outside a function declaration,
223 // or inside a block.
224 if (_.current_layout_section() < kLayoutTypes) {
225 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
226 << "Non-semantic OpExtInst must not appear before types "
227 << "section";
228 } else if (_.in_function_body() && _.in_block() == false) {
229 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
230 << "Non-semantic OpExtInst within function definition must "
231 "appear in a block";
232 }
233 } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
234 const uint32_t ext_inst_index = inst->word(4);
235 bool local_debug_info = false;
236 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
237 const OpenCLDebugInfo100Instructions ext_inst_key =
238 OpenCLDebugInfo100Instructions(ext_inst_index);
239 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
240 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
241 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
242 ext_inst_key == OpenCLDebugInfo100DebugValue) {
243 local_debug_info = true;
244 }
245 } else {
246 const DebugInfoInstructions ext_inst_key =
247 DebugInfoInstructions(ext_inst_index);
248 if (ext_inst_key == DebugInfoDebugScope ||
249 ext_inst_key == DebugInfoDebugNoScope ||
250 ext_inst_key == DebugInfoDebugDeclare ||
251 ext_inst_key == DebugInfoDebugValue) {
252 local_debug_info = true;
253 }
254 }
255
256 if (local_debug_info) {
257 if (_.in_function_body() == false) {
258 // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
259 // appear in a function body.
260 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
261 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
262 << "of debug info extension must appear in a function "
263 << "body";
264 }
265 } else {
266 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
267 // DebugDeclare, DebugValue must be placed between section 9 (types,
268 // constants, global variables) and section 10 (function
269 // declarations).
270 if (_.current_layout_section() < kLayoutTypes ||
271 _.current_layout_section() >= kLayoutFunctionDeclarations) {
272 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
273 << "Debug info extension instructions other than "
274 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
275 << "must appear between section 9 (types, constants, "
276 << "global variables) and section 10 (function "
277 << "declarations)";
278 }
279 }
280 } else {
281 // otherwise they must be used in a block
282 if (_.in_block() == false) {
283 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
284 << spvOpcodeString(opcode) << " must appear in a block";
285 }
286 }
287 break;
288
289 default:
290 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
291 _.in_function_body()) {
292 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
293 << "A function must begin with a label";
294 } else {
295 if (_.in_block() == false) {
296 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
297 << spvOpcodeString(opcode) << " must appear in a block";
298 }
299 }
300 break;
301 }
302 } else {
303 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
304 << spvOpcodeString(opcode)
305 << " cannot appear in a function declaration";
306 }
307 return SPV_SUCCESS;
308}
309
310} // namespace
311
312// TODO(umar): Check linkage capabilities for function declarations
313// TODO(umar): Better error messages
314// NOTE: This function does not handle CFG related validation
315// Performs logical layout validation. See Section 2.4
316spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
317 const SpvOp opcode = inst->opcode();
318
319 switch (_.current_layout_section()) {
320 case kLayoutCapabilities:
321 case kLayoutExtensions:
322 case kLayoutExtInstImport:
323 case kLayoutMemoryModel:
324 case kLayoutEntryPoint:
325 case kLayoutExecutionMode:
326 case kLayoutDebug1:
327 case kLayoutDebug2:
328 case kLayoutDebug3:
329 case kLayoutAnnotations:
330 case kLayoutTypes:
331 if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
332 break;
333 case kLayoutFunctionDeclarations:
334 case kLayoutFunctionDefinitions:
335 if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
336 return error;
337 }
338 break;
339 }
340 return SPV_SUCCESS;
341}
342
343} // namespace val
344} // namespace spvtools
345