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 SpvOpSource:
37 case SpvOpSourceExtension:
38 case SpvOpSourceContinued:
39 case SpvOpExtension:
40 case SpvOpCapability:
41 case SpvOpExtInstImport:
42 case SpvOpMemoryModel:
43 case SpvOpString:
44 case SpvOpName:
45 case SpvOpMemberName:
46 case SpvOpExecutionMode:
47 case SpvOpDecorationGroup:
48 case SpvOpMemberDecorate:
49 case SpvOpGroupDecorate:
50 case SpvOpGroupMemberDecorate:
51 break;
52
53 case SpvOpEntryPoint:
54 vtn_handle_entry_point(b, w, count);
55 break;
56
57 case SpvOpDecorate:
58 vtn_handle_decoration(b, opcode, w, count);
59 break;
60
61 default:
62 return false; /* End of preamble */
63 }
64
65 return true;
66 }
67
68 static void
spec_constant_decoration_cb(struct vtn_builder * b,struct vtn_value * v,int member,const struct vtn_decoration * dec,void * data)69 spec_constant_decoration_cb(struct vtn_builder *b, struct vtn_value *v,
70 int member, const struct vtn_decoration *dec,
71 void *data)
72 {
73 vtn_assert(member == -1);
74 if (dec->decoration != SpvDecorationSpecId)
75 return;
76
77 for (unsigned i = 0; i < b->num_specializations; i++) {
78 if (b->specializations[i].id == dec->operands[0]) {
79 b->specializations[i].defined_on_module = true;
80 return;
81 }
82 }
83 }
84
85 static void
vtn_validate_handle_constant(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)86 vtn_validate_handle_constant(struct vtn_builder *b, SpvOp opcode,
87 const uint32_t *w, unsigned count)
88 {
89 struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);
90
91 switch (opcode) {
92 case SpvOpConstant:
93 case SpvOpConstantNull:
94 case SpvOpSpecConstantComposite:
95 case SpvOpConstantComposite:
96 /* Nothing to do here for gl_spirv needs */
97 break;
98
99 case SpvOpConstantTrue:
100 case SpvOpConstantFalse:
101 case SpvOpSpecConstantTrue:
102 case SpvOpSpecConstantFalse:
103 case SpvOpSpecConstant:
104 case SpvOpSpecConstantOp:
105 vtn_foreach_decoration(b, val, spec_constant_decoration_cb, NULL);
106 break;
107
108 case SpvOpConstantSampler:
109 vtn_fail("OpConstantSampler requires Kernel Capability");
110 break;
111
112 default:
113 vtn_fail("Unhandled opcode");
114 }
115 }
116
117 static bool
vtn_validate_handle_constant_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)118 vtn_validate_handle_constant_instruction(struct vtn_builder *b, SpvOp opcode,
119 const uint32_t *w, unsigned count)
120 {
121 switch (opcode) {
122 case SpvOpSource:
123 case SpvOpSourceContinued:
124 case SpvOpSourceExtension:
125 case SpvOpExtension:
126 case SpvOpCapability:
127 case SpvOpExtInstImport:
128 case SpvOpMemoryModel:
129 case SpvOpEntryPoint:
130 case SpvOpExecutionMode:
131 case SpvOpString:
132 case SpvOpName:
133 case SpvOpMemberName:
134 case SpvOpDecorationGroup:
135 case SpvOpDecorate:
136 case SpvOpMemberDecorate:
137 case SpvOpGroupDecorate:
138 case SpvOpGroupMemberDecorate:
139 vtn_fail("Invalid opcode types and variables section");
140 break;
141
142 case SpvOpTypeVoid:
143 case SpvOpTypeBool:
144 case SpvOpTypeInt:
145 case SpvOpTypeFloat:
146 case SpvOpTypeVector:
147 case SpvOpTypeMatrix:
148 case SpvOpTypeImage:
149 case SpvOpTypeSampler:
150 case SpvOpTypeSampledImage:
151 case SpvOpTypeArray:
152 case SpvOpTypeRuntimeArray:
153 case SpvOpTypeStruct:
154 case SpvOpTypeOpaque:
155 case SpvOpTypePointer:
156 case SpvOpTypeFunction:
157 case SpvOpTypeEvent:
158 case SpvOpTypeDeviceEvent:
159 case SpvOpTypeReserveId:
160 case SpvOpTypeQueue:
161 case SpvOpTypePipe:
162 /* We don't need to handle types */
163 break;
164
165 case SpvOpConstantTrue:
166 case SpvOpConstantFalse:
167 case SpvOpConstant:
168 case SpvOpConstantComposite:
169 case SpvOpConstantSampler:
170 case SpvOpConstantNull:
171 case SpvOpSpecConstantTrue:
172 case SpvOpSpecConstantFalse:
173 case SpvOpSpecConstant:
174 case SpvOpSpecConstantComposite:
175 case SpvOpSpecConstantOp:
176 vtn_validate_handle_constant(b, opcode, w, count);
177 break;
178
179 case SpvOpUndef:
180 case SpvOpVariable:
181 /* We don't need to handle them */
182 break;
183
184 default:
185 return false; /* End of preamble */
186 }
187
188 return true;
189 }
190
191 /*
192 * Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the
193 * new methods, glSpecializeShader include some possible errors when trying to
194 * use it.
195 *
196 * From OpenGL 4.6, Section 7.2.1, "Shader Specialization":
197 *
198 * "void SpecializeShaderARB(uint shader,
199 * const char* pEntryPoint,
200 * uint numSpecializationConstants,
201 * const uint* pConstantIndex,
202 * const uint* pConstantValue);
203 * <skip>
204 *
205 * INVALID_VALUE is generated if <pEntryPoint> does not name a valid
206 * entry point for <shader>.
207 *
208 * An INVALID_VALUE error is generated if any element of pConstantIndex refers
209 * to a specialization constant that does not exist in the shader module
210 * contained in shader."
211 *
212 * We could do those checks on spirv_to_nir, but we are only interested on the
213 * full translation later, during linking. This method is a simplified version
214 * of spirv_to_nir, looking for only the checks needed by SpecializeShader.
215 *
216 * This method returns NULL if no entry point was found, and fill the
217 * nir_spirv_specialization field "defined_on_module" accordingly. Caller
218 * would need to trigger the specific errors.
219 *
220 */
221 bool
gl_spirv_validation(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)222 gl_spirv_validation(const uint32_t *words, size_t word_count,
223 struct nir_spirv_specialization *spec, unsigned num_spec,
224 gl_shader_stage stage, const char *entry_point_name)
225 {
226 /* vtn_warn/vtn_log uses debug.func. Setting a null to prevent crash. Not
227 * need to print the warnings now, would be done later, on the real
228 * spirv_to_nir
229 */
230 const struct spirv_to_nir_options options = { .debug.func = NULL};
231 const uint32_t *word_end = words + word_count;
232
233 struct vtn_builder *b = vtn_create_builder(words, word_count,
234 stage, entry_point_name,
235 &options);
236
237 if (b == NULL)
238 return false;
239
240 /* See also _vtn_fail() */
241 if (setjmp(b->fail_jump)) {
242 ralloc_free(b);
243 return false;
244 }
245
246 /* Skip the SPIR-V header, handled at vtn_create_builder */
247 words+= 5;
248
249 /* Search entry point from preamble */
250 words = vtn_foreach_instruction(b, words, word_end,
251 vtn_validate_preamble_instruction);
252
253 if (b->entry_point == NULL) {
254 ralloc_free(b);
255 return false;
256 }
257
258 b->specializations = spec;
259 b->num_specializations = num_spec;
260
261 /* Handle constant instructions (we don't need to handle
262 * variables or types for gl_spirv)
263 */
264 words = vtn_foreach_instruction(b, words, word_end,
265 vtn_validate_handle_constant_instruction);
266
267 ralloc_free(b);
268
269 return true;
270 }
271
272