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
29 namespace spvtools {
30 namespace val {
31 namespace {
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.
ModuleScopedInstructions(ValidationState_t & _,const Instruction * inst,SpvOp opcode)36 spv_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 if (_.IsOpcodeInPreviousLayoutSection(opcode)) {
111 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
112 << spvOpcodeString(opcode) << " is in an invalid layout section";
113 }
114
115 _.ProgressToNextLayoutSectionOrder();
116
117 switch (_.current_layout_section()) {
118 case kLayoutMemoryModel:
119 if (opcode != SpvOpMemoryModel) {
120 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
121 << spvOpcodeString(opcode)
122 << " cannot appear before the memory model instruction";
123 }
124 break;
125 case kLayoutFunctionDeclarations:
126 // All module sections have been processed. Recursively call
127 // ModuleLayoutPass to process the next section of the module
128 return ModuleLayoutPass(_, inst);
129 default:
130 break;
131 }
132 }
133 return SPV_SUCCESS;
134 }
135
136 // Function declaration validation is performed by making sure that the
137 // FunctionParameter and FunctionEnd instructions only appear inside of
138 // functions. It also ensures that the Function instruction does not appear
139 // inside of another function. This stage ends when the first label is
140 // encountered inside of a function.
FunctionScopedInstructions(ValidationState_t & _,const Instruction * inst,SpvOp opcode)141 spv_result_t FunctionScopedInstructions(ValidationState_t& _,
142 const Instruction* inst, SpvOp opcode) {
143 // Make sure we advance into the function definitions when we hit
144 // non-function declaration instructions.
145 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
146 !_.IsOpcodeInCurrentLayoutSection(opcode)) {
147 _.ProgressToNextLayoutSectionOrder();
148
149 if (_.in_function_body()) {
150 if (auto error = _.current_function().RegisterSetFunctionDeclType(
151 FunctionDecl::kFunctionDeclDefinition)) {
152 return error;
153 }
154 }
155 }
156
157 if (_.IsOpcodeInCurrentLayoutSection(opcode)) {
158 switch (opcode) {
159 case SpvOpFunction: {
160 if (_.in_function_body()) {
161 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
162 << "Cannot declare a function in a function body";
163 }
164 auto control_mask = inst->GetOperandAs<SpvFunctionControlMask>(2);
165 if (auto error =
166 _.RegisterFunction(inst->id(), inst->type_id(), control_mask,
167 inst->GetOperandAs<uint32_t>(3)))
168 return error;
169 if (_.current_layout_section() == kLayoutFunctionDefinitions) {
170 if (auto error = _.current_function().RegisterSetFunctionDeclType(
171 FunctionDecl::kFunctionDeclDefinition))
172 return error;
173 }
174 } break;
175
176 case SpvOpFunctionParameter:
177 if (_.in_function_body() == false) {
178 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
179 << "Function parameter instructions must be in a "
180 "function body";
181 }
182 if (_.current_function().block_count() != 0) {
183 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
184 << "Function parameters must only appear immediately after "
185 "the function definition";
186 }
187 if (auto error = _.current_function().RegisterFunctionParameter(
188 inst->id(), inst->type_id()))
189 return error;
190 break;
191
192 case SpvOpFunctionEnd:
193 if (_.in_function_body() == false) {
194 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
195 << "Function end instructions must be in a function body";
196 }
197 if (_.in_block()) {
198 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
199 << "Function end cannot be called in blocks";
200 }
201 if (_.current_function().block_count() == 0 &&
202 _.current_layout_section() == kLayoutFunctionDefinitions) {
203 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
204 << "Function declarations must appear before "
205 "function definitions.";
206 }
207 if (_.current_layout_section() == kLayoutFunctionDeclarations) {
208 if (auto error = _.current_function().RegisterSetFunctionDeclType(
209 FunctionDecl::kFunctionDeclDeclaration))
210 return error;
211 }
212 if (auto error = _.RegisterFunctionEnd()) return error;
213 break;
214
215 case SpvOpLine:
216 case SpvOpNoLine:
217 break;
218 case SpvOpLabel:
219 // If the label is encountered then the current function is a
220 // definition so set the function to a declaration and update the
221 // module section
222 if (_.in_function_body() == false) {
223 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
224 << "Label instructions must be in a function body";
225 }
226 if (_.in_block()) {
227 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
228 << "A block must end with a branch instruction.";
229 }
230 break;
231
232 case SpvOpExtInst:
233 if (spvExtInstIsNonSemantic(inst->ext_inst_type())) {
234 // non-semantic extinst opcodes are allowed beginning in the types
235 // section, but must either be placed outside a function declaration,
236 // or inside a block.
237 if (_.current_layout_section() < kLayoutTypes) {
238 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
239 << "Non-semantic OpExtInst must not appear before types "
240 << "section";
241 } else if (_.in_function_body() && _.in_block() == false) {
242 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
243 << "Non-semantic OpExtInst within function definition must "
244 "appear in a block";
245 }
246 } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) {
247 const uint32_t ext_inst_index = inst->word(4);
248 bool local_debug_info = false;
249 if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
250 const OpenCLDebugInfo100Instructions ext_inst_key =
251 OpenCLDebugInfo100Instructions(ext_inst_index);
252 if (ext_inst_key == OpenCLDebugInfo100DebugScope ||
253 ext_inst_key == OpenCLDebugInfo100DebugNoScope ||
254 ext_inst_key == OpenCLDebugInfo100DebugDeclare ||
255 ext_inst_key == OpenCLDebugInfo100DebugValue) {
256 local_debug_info = true;
257 }
258 } else {
259 const DebugInfoInstructions ext_inst_key =
260 DebugInfoInstructions(ext_inst_index);
261 if (ext_inst_key == DebugInfoDebugScope ||
262 ext_inst_key == DebugInfoDebugNoScope ||
263 ext_inst_key == DebugInfoDebugDeclare ||
264 ext_inst_key == DebugInfoDebugValue) {
265 local_debug_info = true;
266 }
267 }
268
269 if (local_debug_info) {
270 if (_.in_function_body() == false) {
271 // DebugScope, DebugNoScope, DebugDeclare, DebugValue must
272 // appear in a function body.
273 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
274 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
275 << "of debug info extension must appear in a function "
276 << "body";
277 }
278 } else {
279 // Debug info extinst opcodes other than DebugScope, DebugNoScope,
280 // DebugDeclare, DebugValue must be placed between section 9 (types,
281 // constants, global variables) and section 10 (function
282 // declarations).
283 if (_.current_layout_section() < kLayoutTypes ||
284 _.current_layout_section() >= kLayoutFunctionDeclarations) {
285 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
286 << "Debug info extension instructions other than "
287 << "DebugScope, DebugNoScope, DebugDeclare, DebugValue "
288 << "must appear between section 9 (types, constants, "
289 << "global variables) and section 10 (function "
290 << "declarations)";
291 }
292 }
293 } else {
294 // otherwise they must be used in a block
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 default:
303 if (_.current_layout_section() == kLayoutFunctionDeclarations &&
304 _.in_function_body()) {
305 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
306 << "A function must begin with a label";
307 } else {
308 if (_.in_block() == false) {
309 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
310 << spvOpcodeString(opcode) << " must appear in a block";
311 }
312 }
313 break;
314 }
315 } else {
316 return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
317 << spvOpcodeString(opcode)
318 << " cannot appear in a function declaration";
319 }
320 return SPV_SUCCESS;
321 }
322
323 } // namespace
324
325 // TODO(umar): Check linkage capabilities for function declarations
326 // TODO(umar): Better error messages
327 // NOTE: This function does not handle CFG related validation
328 // Performs logical layout validation. See Section 2.4
ModuleLayoutPass(ValidationState_t & _,const Instruction * inst)329 spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
330 const SpvOp opcode = inst->opcode();
331
332 switch (_.current_layout_section()) {
333 case kLayoutCapabilities:
334 case kLayoutExtensions:
335 case kLayoutExtInstImport:
336 case kLayoutMemoryModel:
337 case kLayoutEntryPoint:
338 case kLayoutExecutionMode:
339 case kLayoutDebug1:
340 case kLayoutDebug2:
341 case kLayoutDebug3:
342 case kLayoutAnnotations:
343 case kLayoutTypes:
344 if (auto error = ModuleScopedInstructions(_, inst, opcode)) return error;
345 break;
346 case kLayoutFunctionDeclarations:
347 case kLayoutFunctionDefinitions:
348 if (auto error = FunctionScopedInstructions(_, inst, opcode)) {
349 return error;
350 }
351 break;
352 }
353 return SPV_SUCCESS;
354 }
355
356 } // namespace val
357 } // namespace spvtools
358