1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 *
24 */
25
26 #include "nir_spirv.h"
27
28 #include "vtn_private.h"
29 #include "spirv_info.h"
30
31 static bool
vtn_validate_preamble_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)32 vtn_validate_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
33 const uint32_t *w, unsigned count)
34 {
35 switch (opcode) {
36 case SpvOpString:
37 case SpvOpSource:
38 case SpvOpSourceExtension:
39 case SpvOpSourceContinued:
40 case SpvOpModuleProcessed:
41 /* We need this since vtn_foreach_instruction automatically handles
42 * OpLine / OpNoLine and relies on the SpvOpString from preamble being
43 * handled.
44 */
45 vtn_handle_debug_text(b, opcode, w, count);
46 break;
47
48 case SpvOpExtension:
49 case SpvOpCapability:
50 case SpvOpExtInstImport:
51 case SpvOpMemoryModel:
52 case SpvOpName:
53 case SpvOpMemberName:
54 case SpvOpExecutionMode:
55 case SpvOpDecorationGroup:
56 case SpvOpMemberDecorate:
57 case SpvOpGroupDecorate:
58 case SpvOpGroupMemberDecorate:
59 break;
60
61 case SpvOpEntryPoint:
62 vtn_handle_entry_point(b, w, count);
63 break;
64
65 case SpvOpDecorate:
66 vtn_handle_decoration(b, opcode, w, count);
67 break;
68
69 default:
70 return false; /* End of preamble */
71 }
72
73 return true;
74 }
75
76 static void
spec_constant_decoration_cb(struct vtn_builder * b,struct vtn_value * v,int member,const struct vtn_decoration * dec,void * data)77 spec_constant_decoration_cb(struct vtn_builder *b, struct vtn_value *v,
78 int member, const struct vtn_decoration *dec,
79 void *data)
80 {
81 vtn_assert(member == -1);
82 if (dec->decoration != SpvDecorationSpecId)
83 return;
84
85 for (unsigned i = 0; i < b->num_specializations; i++) {
86 if (b->specializations[i].id == dec->operands[0]) {
87 b->specializations[i].defined_on_module = true;
88 return;
89 }
90 }
91 }
92
93 static void
vtn_validate_handle_constant(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)94 vtn_validate_handle_constant(struct vtn_builder *b, SpvOp opcode,
95 const uint32_t *w, unsigned count)
96 {
97 struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);
98
99 switch (opcode) {
100 case SpvOpConstant:
101 case SpvOpConstantNull:
102 case SpvOpSpecConstantComposite:
103 case SpvOpConstantComposite:
104 /* Nothing to do here for gl_spirv needs */
105 break;
106
107 case SpvOpConstantTrue:
108 case SpvOpConstantFalse:
109 case SpvOpSpecConstantTrue:
110 case SpvOpSpecConstantFalse:
111 case SpvOpSpecConstant:
112 case SpvOpSpecConstantOp:
113 vtn_foreach_decoration(b, val, spec_constant_decoration_cb, NULL);
114 break;
115
116 case SpvOpConstantSampler:
117 vtn_fail("OpConstantSampler requires Kernel Capability");
118 break;
119
120 default:
121 vtn_fail("Unhandled opcode");
122 }
123 }
124
125 static bool
vtn_validate_handle_constant_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)126 vtn_validate_handle_constant_instruction(struct vtn_builder *b, SpvOp opcode,
127 const uint32_t *w, unsigned count)
128 {
129 switch (opcode) {
130 case SpvOpSource:
131 case SpvOpSourceContinued:
132 case SpvOpSourceExtension:
133 case SpvOpExtension:
134 case SpvOpCapability:
135 case SpvOpExtInstImport:
136 case SpvOpMemoryModel:
137 case SpvOpEntryPoint:
138 case SpvOpExecutionMode:
139 case SpvOpString:
140 case SpvOpName:
141 case SpvOpMemberName:
142 case SpvOpDecorationGroup:
143 case SpvOpDecorate:
144 case SpvOpMemberDecorate:
145 case SpvOpGroupDecorate:
146 case SpvOpGroupMemberDecorate:
147 vtn_fail("Invalid opcode types and variables section");
148 break;
149
150 case SpvOpTypeVoid:
151 case SpvOpTypeBool:
152 case SpvOpTypeInt:
153 case SpvOpTypeFloat:
154 case SpvOpTypeVector:
155 case SpvOpTypeMatrix:
156 case SpvOpTypeImage:
157 case SpvOpTypeSampler:
158 case SpvOpTypeSampledImage:
159 case SpvOpTypeArray:
160 case SpvOpTypeRuntimeArray:
161 case SpvOpTypeStruct:
162 case SpvOpTypeOpaque:
163 case SpvOpTypePointer:
164 case SpvOpTypeFunction:
165 case SpvOpTypeEvent:
166 case SpvOpTypeDeviceEvent:
167 case SpvOpTypeReserveId:
168 case SpvOpTypeQueue:
169 case SpvOpTypePipe:
170 /* We don't need to handle types */
171 break;
172
173 case SpvOpConstantTrue:
174 case SpvOpConstantFalse:
175 case SpvOpConstant:
176 case SpvOpConstantComposite:
177 case SpvOpConstantSampler:
178 case SpvOpConstantNull:
179 case SpvOpSpecConstantTrue:
180 case SpvOpSpecConstantFalse:
181 case SpvOpSpecConstant:
182 case SpvOpSpecConstantComposite:
183 case SpvOpSpecConstantOp:
184 vtn_validate_handle_constant(b, opcode, w, count);
185 break;
186
187 case SpvOpUndef:
188 case SpvOpVariable:
189 /* We don't need to handle them */
190 break;
191
192 default:
193 return false; /* End of preamble */
194 }
195
196 return true;
197 }
198
199 /*
200 * Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the
201 * new methods, glSpecializeShader include some possible errors when trying to
202 * use it.
203 *
204 * From OpenGL 4.6, Section 7.2.1, "Shader Specialization":
205 *
206 * "void SpecializeShaderARB(uint shader,
207 * const char* pEntryPoint,
208 * uint numSpecializationConstants,
209 * const uint* pConstantIndex,
210 * const uint* pConstantValue);
211 * <skip>
212 *
213 * INVALID_VALUE is generated if <pEntryPoint> does not name a valid
214 * entry point for <shader>.
215 *
216 * An INVALID_VALUE error is generated if any element of pConstantIndex refers
217 * to a specialization constant that does not exist in the shader module
218 * contained in shader."
219 *
220 * We could do those checks on spirv_to_nir, but we are only interested on the
221 * full translation later, during linking. This method is a simplified version
222 * of spirv_to_nir, looking for only the checks needed by SpecializeShader.
223 *
224 * This method returns NULL if no entry point was found, and fill the
225 * nir_spirv_specialization field "defined_on_module" accordingly. Caller
226 * would need to trigger the specific errors.
227 *
228 */
229 enum spirv_verify_result
spirv_verify_gl_specialization_constants(const uint32_t * words,size_t word_count,struct nir_spirv_specialization * spec,unsigned num_spec,gl_shader_stage stage,const char * entry_point_name)230 spirv_verify_gl_specialization_constants(
231 const uint32_t *words, size_t word_count,
232 struct nir_spirv_specialization *spec, unsigned num_spec,
233 gl_shader_stage stage, const char *entry_point_name)
234 {
235 /* vtn_warn/vtn_log uses debug.func. Setting a null to prevent crash. Not
236 * need to print the warnings now, would be done later, on the real
237 * spirv_to_nir
238 */
239 const struct spirv_capabilities spirv_caps = { false, };
240 const struct spirv_to_nir_options options = {
241 .capabilities = &spirv_caps,
242 .debug.func = NULL,
243 };
244 const uint32_t *word_end = words + word_count;
245
246 struct vtn_builder *b = vtn_create_builder(words, word_count,
247 stage, entry_point_name,
248 &options);
249
250 if (b == NULL)
251 return false;
252
253 /* See also _vtn_fail() */
254 if (vtn_setjmp(b->fail_jump)) {
255 ralloc_free(b);
256 return SPIRV_VERIFY_PARSER_ERROR;
257 }
258
259 /* Skip the SPIR-V header, handled at vtn_create_builder */
260 words+= 5;
261
262 /* Search entry point from preamble */
263 words = vtn_foreach_instruction(b, words, word_end,
264 vtn_validate_preamble_instruction);
265
266 if (b->entry_point == NULL) {
267 ralloc_free(b);
268 return SPIRV_VERIFY_ENTRY_POINT_NOT_FOUND;
269 }
270
271 b->specializations = spec;
272 b->num_specializations = num_spec;
273
274 /* Handle constant instructions (we don't need to handle
275 * variables or types for gl_spirv)
276 */
277 words = vtn_foreach_instruction(b, words, word_end,
278 vtn_validate_handle_constant_instruction);
279
280 ralloc_free(b);
281
282 for (unsigned i = 0; i < num_spec; i++) {
283 if (!spec[i].defined_on_module)
284 return SPIRV_VERIFY_UNKNOWN_SPEC_INDEX;
285 }
286
287 return SPIRV_VERIFY_OK;
288 }
289
290