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 (vtn_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