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 31static bool 32vtn_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 68static void 69spec_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 85static void 86vtn_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 117static bool 118vtn_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 */ 221bool 222gl_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