45
// Check that the operand of a debug info instruction |inst| at |word_index|
46
// is a result id of an instruction with |expected_opcode|.
47
spv_result_t ValidateOperandForDebugInfo(
48
ValidationState_t& _, const std::string& operand_name,
49
SpvOp expected_opcode, const Instruction* inst, uint32_t word_index,
50
const std::function<std::string()>& ext_inst_name) {
51
auto* operand = _.FindDef(inst->word(word_index));
52
if (operand->opcode() != expected_opcode) {
53
spv_opcode_desc desc = nullptr;
54
if (_.grammar().lookupOpcode(expected_opcode, &desc) != SPV_SUCCESS ||
56
return _.diag(SPV_ERROR_INVALID_DATA, inst)
57
<< ext_inst_name() << ": "
58
<< "expected operand " << operand_name << " is invalid";
60
return _.diag(SPV_ERROR_INVALID_DATA, inst)
61
<< ext_inst_name() << ": "
62
<< "expected operand " << operand_name << " must be a result id of "
63
<< "Op" << desc->name;
68
#define CHECK_OPERAND(NAME, opcode, index) \
70
auto result = ValidateOperandForDebugInfo(_, NAME, opcode, inst, index, \
72
if (result != SPV_SUCCESS) return result; \
75
// True if the operand of a debug info instruction |inst| at |word_index|
76
// satisifies |expectation| that is given as a function. Otherwise,
78
bool DoesDebugInfoOperandMatchExpectation(
79
const ValidationState_t& _,
80
const std::function<bool(OpenCLDebugInfo100Instructions)>& expectation,
81
const Instruction* inst, uint32_t word_index) {
82
auto* debug_inst = _.FindDef(inst->word(word_index));
83
if (debug_inst->opcode() != SpvOpExtInst ||
84
debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 ||
85
!expectation(OpenCLDebugInfo100Instructions(debug_inst->word(4)))) {
91
// Check that the operand of a debug info instruction |inst| at |word_index|
92
// is a result id of an debug info instruction whose debug instruction type
93
// is |expected_debug_inst|.
94
spv_result_t ValidateDebugInfoOperand(
95
ValidationState_t& _, const std::string& debug_inst_name,
96
OpenCLDebugInfo100Instructions expected_debug_inst, const Instruction* inst,
97
uint32_t word_index, const std::function<std::string()>& ext_inst_name) {
98
std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
99
[expected_debug_inst](OpenCLDebugInfo100Instructions dbg_inst) {
100
return dbg_inst == expected_debug_inst;
102
if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
105
spv_ext_inst_desc desc = nullptr;
106
_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
107
expected_debug_inst, &desc);
108
if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100,
109
expected_debug_inst, &desc) != SPV_SUCCESS ||
111
return _.diag(SPV_ERROR_INVALID_DATA, inst)
112
<< ext_inst_name() << ": "
113
<< "expected operand " << debug_inst_name << " is invalid";
115
return _.diag(SPV_ERROR_INVALID_DATA, inst)
116
<< ext_inst_name() << ": "
117
<< "expected operand " << debug_inst_name << " must be a result id of "
121
#define CHECK_DEBUG_OPERAND(NAME, debug_opcode, index) \
123
auto result = ValidateDebugInfoOperand(_, NAME, debug_opcode, inst, index, \
125
if (result != SPV_SUCCESS) return result; \
128
// Check that the operand of a debug info instruction |inst| at |word_index|
129
// is a result id of an debug info instruction with DebugTypeBasic.
130
spv_result_t ValidateOperandBaseType(
131
ValidationState_t& _, const Instruction* inst, uint32_t word_index,
132
const std::function<std::string()>& ext_inst_name) {
133
return ValidateDebugInfoOperand(_, "Base Type",
134
OpenCLDebugInfo100DebugTypeBasic, inst,
135
word_index, ext_inst_name);
138
// Check that the operand of a debug info instruction |inst| at |word_index|
139
// is a result id of a debug lexical scope instruction which is one of
140
// DebugCompilationUnit, DebugFunction, DebugLexicalBlock, or
141
// DebugTypeComposite.
142
spv_result_t ValidateOperandLexicalScope(
143
ValidationState_t& _, const std::string& debug_inst_name,
144
const Instruction* inst, uint32_t word_index,
145
const std::function<std::string()>& ext_inst_name) {
146
std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
147
[](OpenCLDebugInfo100Instructions dbg_inst) {
148
return dbg_inst == OpenCLDebugInfo100DebugCompilationUnit ||
149
dbg_inst == OpenCLDebugInfo100DebugFunction ||
150
dbg_inst == OpenCLDebugInfo100DebugLexicalBlock ||
151
dbg_inst == OpenCLDebugInfo100DebugTypeComposite;
153
if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
156
return _.diag(SPV_ERROR_INVALID_DATA, inst)
157
<< ext_inst_name() << ": "
158
<< "expected operand " << debug_inst_name
159
<< " must be a result id of a lexical scope";
162
// Check that the operand of a debug info instruction |inst| at |word_index|
163
// is a result id of a debug type instruction (See DebugTypeXXX in
164
// "4.3. Type instructions" section of OpenCL.DebugInfo.100 spec.
165
spv_result_t ValidateOperandDebugType(
166
ValidationState_t& _, const std::string& debug_inst_name,
167
const Instruction* inst, uint32_t word_index,
168
const std::function<std::string()>& ext_inst_name) {
169
std::function<bool(OpenCLDebugInfo100Instructions)> expectation =
170
[](OpenCLDebugInfo100Instructions dbg_inst) {
171
return OpenCLDebugInfo100DebugTypeBasic <= dbg_inst &&
172
dbg_inst <= OpenCLDebugInfo100DebugTypePtrToMember;
174
if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index))
177
return _.diag(SPV_ERROR_INVALID_DATA, inst)
178
<< ext_inst_name() << ": "
179
<< "expected operand " << debug_inst_name
180
<< " is not a valid debug type";
45
183
} // anonymous namespace
47
185
spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) {
2169
} else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) {
2170
if (!_.IsVoidType(result_type)) {
2171
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2172
<< ext_inst_name() << ": "
2173
<< "expected result type must be a result id of "
2177
auto num_words = inst->words().size();
2179
const OpenCLDebugInfo100Instructions ext_inst_key =
2180
OpenCLDebugInfo100Instructions(ext_inst_index);
2181
switch (ext_inst_key) {
2182
case OpenCLDebugInfo100DebugInfoNone:
2183
case OpenCLDebugInfo100DebugNoScope:
2184
case OpenCLDebugInfo100DebugOperation:
2185
// The binary parser validates the opcode for DebugInfoNone,
2186
// DebugNoScope, DebugOperation, and the literal values don't need
2189
case OpenCLDebugInfo100DebugCompilationUnit: {
2190
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2193
case OpenCLDebugInfo100DebugSource: {
2194
CHECK_OPERAND("File", SpvOpString, 5);
2195
if (num_words == 7) CHECK_OPERAND("Text", SpvOpString, 6);
2198
case OpenCLDebugInfo100DebugTypeBasic: {
2199
CHECK_OPERAND("Name", SpvOpString, 5);
2200
CHECK_OPERAND("Size", SpvOpConstant, 6);
2201
// "Encoding" param is already validated by the binary parsing stage.
2204
case OpenCLDebugInfo100DebugTypePointer:
2205
case OpenCLDebugInfo100DebugTypeQualifier: {
2206
auto validate_base_type =
2207
ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2208
if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2211
case OpenCLDebugInfo100DebugTypeVector: {
2212
auto validate_base_type =
2213
ValidateOperandBaseType(_, inst, 5, ext_inst_name);
2214
if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2216
uint32_t component_count = inst->word(6);
2217
if (!component_count || component_count > 4) {
2218
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2219
<< ext_inst_name() << ": Component Count must be positive "
2220
<< "integer less than or equal to 4";
2224
case OpenCLDebugInfo100DebugTypeArray: {
2225
auto validate_base_type =
2226
ValidateOperandDebugType(_, "Base Type", inst, 5, ext_inst_name);
2227
if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2228
for (uint32_t i = 6; i < num_words; ++i) {
2229
CHECK_OPERAND("Component Count", SpvOpConstant, i);
2230
auto* component_count = _.FindDef(inst->word(i));
2231
if (!_.IsIntScalarType(component_count->type_id()) ||
2232
!component_count->word(3)) {
2233
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2234
<< ext_inst_name() << ": Component Count must be positive "
2240
case OpenCLDebugInfo100DebugTypedef: {
2241
CHECK_OPERAND("Name", SpvOpString, 5);
2242
auto validate_base_type =
2243
ValidateOperandBaseType(_, inst, 6, ext_inst_name);
2244
if (validate_base_type != SPV_SUCCESS) return validate_base_type;
2245
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2246
auto validate_parent =
2247
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2248
if (validate_parent != SPV_SUCCESS) return validate_parent;
2251
case OpenCLDebugInfo100DebugTypeFunction: {
2252
auto* return_type = _.FindDef(inst->word(6));
2253
if (return_type->opcode() != SpvOpTypeVoid) {
2254
auto validate_return = ValidateOperandDebugType(
2255
_, "Return Type", inst, 6, ext_inst_name);
2256
if (validate_return != SPV_SUCCESS) return validate_return;
2258
for (uint32_t word_index = 7; word_index < num_words; ++word_index) {
2259
auto validate_param = ValidateOperandDebugType(
2260
_, "Parameter Types", inst, word_index, ext_inst_name);
2261
if (validate_param != SPV_SUCCESS) return validate_param;
2265
case OpenCLDebugInfo100DebugTypeEnum: {
2266
CHECK_OPERAND("Name", SpvOpString, 5);
2267
if (!DoesDebugInfoOperandMatchExpectation(
2269
[](OpenCLDebugInfo100Instructions dbg_inst) {
2270
return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2273
auto validate_underlying_type = ValidateOperandDebugType(
2274
_, "Underlying Types", inst, 6, ext_inst_name);
2275
if (validate_underlying_type != SPV_SUCCESS)
2276
return validate_underlying_type;
2278
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2279
auto validate_parent =
2280
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2281
if (validate_parent != SPV_SUCCESS) return validate_parent;
2282
CHECK_OPERAND("Size", SpvOpConstant, 11);
2283
auto* size = _.FindDef(inst->word(11));
2284
if (!_.IsIntScalarType(size->type_id()) || !size->word(3)) {
2285
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2286
<< ext_inst_name() << ": expected operand Size is a "
2287
<< "positive integer";
2289
for (uint32_t word_index = 13; word_index + 1 < num_words;
2291
CHECK_OPERAND("Value", SpvOpConstant, word_index);
2292
CHECK_OPERAND("Name", SpvOpString, word_index + 1);
2296
case OpenCLDebugInfo100DebugTypeComposite: {
2297
CHECK_OPERAND("Name", SpvOpString, 5);
2298
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2299
auto validate_parent =
2300
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2301
if (validate_parent != SPV_SUCCESS) return validate_parent;
2302
CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2303
if (!DoesDebugInfoOperandMatchExpectation(
2305
[](OpenCLDebugInfo100Instructions dbg_inst) {
2306
return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2309
CHECK_OPERAND("Size", SpvOpConstant, 12);
2311
for (uint32_t word_index = 14; word_index < num_words; ++word_index) {
2312
if (!DoesDebugInfoOperandMatchExpectation(
2314
[](OpenCLDebugInfo100Instructions dbg_inst) {
2315
return dbg_inst == OpenCLDebugInfo100DebugTypeMember ||
2316
dbg_inst == OpenCLDebugInfo100DebugFunction ||
2317
dbg_inst == OpenCLDebugInfo100DebugTypeInheritance;
2319
inst, word_index)) {
2320
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2321
<< ext_inst_name() << ": "
2322
<< "expected operand Members "
2323
<< "must be DebugTypeMember, DebugFunction, or "
2324
"DebugTypeInheritance";
2329
case OpenCLDebugInfo100DebugTypeMember: {
2330
CHECK_OPERAND("Name", SpvOpString, 5);
2331
auto validate_type =
2332
ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2333
if (validate_type != SPV_SUCCESS) return validate_type;
2334
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2335
CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 10);
2336
CHECK_OPERAND("Offset", SpvOpConstant, 11);
2337
CHECK_OPERAND("Size", SpvOpConstant, 12);
2338
if (num_words == 15) CHECK_OPERAND("Value", SpvOpConstant, 14);
2341
case OpenCLDebugInfo100DebugTypeInheritance: {
2342
CHECK_DEBUG_OPERAND("Child", OpenCLDebugInfo100DebugTypeComposite, 5);
2343
auto* debug_inst = _.FindDef(inst->word(5));
2344
auto composite_type =
2345
OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2346
if (composite_type != OpenCLDebugInfo100Class &&
2347
composite_type != OpenCLDebugInfo100Structure) {
2348
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2349
<< ext_inst_name() << ": "
2350
<< "expected operand Child must be class or struct debug type";
2352
CHECK_DEBUG_OPERAND("Parent", OpenCLDebugInfo100DebugTypeComposite, 6);
2353
debug_inst = _.FindDef(inst->word(6));
2355
OpenCLDebugInfo100DebugCompositeType(debug_inst->word(6));
2356
if (composite_type != OpenCLDebugInfo100Class &&
2357
composite_type != OpenCLDebugInfo100Structure) {
2358
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2359
<< ext_inst_name() << ": "
2360
<< "expected operand Parent must be class or struct debug "
2363
CHECK_OPERAND("Offset", SpvOpConstant, 7);
2364
CHECK_OPERAND("Size", SpvOpConstant, 8);
2367
case OpenCLDebugInfo100DebugFunction: {
2368
CHECK_OPERAND("Name", SpvOpString, 5);
2369
auto validate_type =
2370
ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2371
if (validate_type != SPV_SUCCESS) return validate_type;
2372
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2373
auto validate_parent =
2374
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2375
if (validate_parent != SPV_SUCCESS) return validate_parent;
2376
CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2377
// TODO: The current OpenCL.100.DebugInfo spec says "Function
2378
// is an OpFunction which is described by this instruction.".
2379
// However, the function definition can be opted-out e.g.,
2380
// inlining. We assume that Function operand can be a
2381
// DebugInfoNone, but we must discuss it and update the spec.
2382
if (!DoesDebugInfoOperandMatchExpectation(
2384
[](OpenCLDebugInfo100Instructions dbg_inst) {
2385
return dbg_inst == OpenCLDebugInfo100DebugInfoNone;
2388
CHECK_OPERAND("Function", SpvOpFunction, 14);
2390
if (num_words == 16) {
2391
CHECK_DEBUG_OPERAND("Declaration",
2392
OpenCLDebugInfo100DebugFunctionDeclaration, 15);
2396
case OpenCLDebugInfo100DebugFunctionDeclaration: {
2397
CHECK_OPERAND("Name", SpvOpString, 5);
2398
auto validate_type =
2399
ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2400
if (validate_type != SPV_SUCCESS) return validate_type;
2401
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2402
auto validate_parent =
2403
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2404
if (validate_parent != SPV_SUCCESS) return validate_parent;
2405
CHECK_OPERAND("Linkage Name", SpvOpString, 11);
2408
case OpenCLDebugInfo100DebugLexicalBlock: {
2409
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 5);
2410
auto validate_parent =
2411
ValidateOperandLexicalScope(_, "Parent", inst, 8, ext_inst_name);
2412
if (validate_parent != SPV_SUCCESS) return validate_parent;
2413
if (num_words == 10) CHECK_OPERAND("Name", SpvOpString, 9);
2416
case OpenCLDebugInfo100DebugScope: {
2417
// TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We are
2418
// still in spec discussion about what must be "Scope" operand of
2419
// DebugScope. Update this code if the conclusion is different.
2420
auto validate_scope =
2421
ValidateOperandLexicalScope(_, "Scope", inst, 5, ext_inst_name);
2422
if (validate_scope != SPV_SUCCESS) return validate_scope;
2423
if (num_words == 7) {
2424
CHECK_DEBUG_OPERAND("Inlined At", OpenCLDebugInfo100DebugInlinedAt,
2429
case OpenCLDebugInfo100DebugLocalVariable: {
2430
CHECK_OPERAND("Name", SpvOpString, 5);
2431
auto validate_type =
2432
ValidateOperandDebugType(_, "Type", inst, 6, ext_inst_name);
2433
if (validate_type != SPV_SUCCESS) return validate_type;
2434
CHECK_DEBUG_OPERAND("Source", OpenCLDebugInfo100DebugSource, 7);
2435
auto validate_parent =
2436
ValidateOperandLexicalScope(_, "Parent", inst, 10, ext_inst_name);
2437
if (validate_parent != SPV_SUCCESS) return validate_parent;
2440
case OpenCLDebugInfo100DebugDeclare: {
2441
CHECK_DEBUG_OPERAND("Local Variable",
2442
OpenCLDebugInfo100DebugLocalVariable, 5);
2444
// TODO: We must discuss DebugDeclare.Variable of OpenCL.100.DebugInfo.
2445
// Currently, it says "Variable must be an id of OpVariable instruction
2446
// which defines the local variable.", but we want to allow
2447
// OpFunctionParameter as well.
2448
auto* operand = _.FindDef(inst->word(6));
2449
if (operand->opcode() != SpvOpVariable &&
2450
operand->opcode() != SpvOpFunctionParameter) {
2451
return _.diag(SPV_ERROR_INVALID_DATA, inst)
2452
<< ext_inst_name() << ": "
2453
<< "expected operand Variable must be a result id of "
2454
"OpVariable or OpFunctionParameter";
2457
CHECK_DEBUG_OPERAND("Expression", OpenCLDebugInfo100DebugExpression, 7);
2460
case OpenCLDebugInfo100DebugExpression: {
2461
for (uint32_t word_index = 5; word_index < num_words; ++word_index) {
2462
CHECK_DEBUG_OPERAND("Operation", OpenCLDebugInfo100DebugOperation,
2468
// TODO: Add validation rules for remaining cases as well.
2469
case OpenCLDebugInfo100DebugTypePtrToMember:
2470
case OpenCLDebugInfo100DebugTypeTemplate:
2471
case OpenCLDebugInfo100DebugTypeTemplateParameter:
2472
case OpenCLDebugInfo100DebugTypeTemplateTemplateParameter:
2473
case OpenCLDebugInfo100DebugTypeTemplateParameterPack:
2474
case OpenCLDebugInfo100DebugGlobalVariable:
2475
case OpenCLDebugInfo100DebugLexicalBlockDiscriminator:
2476
case OpenCLDebugInfo100DebugInlinedAt:
2477
case OpenCLDebugInfo100DebugInlinedVariable:
2478
case OpenCLDebugInfo100DebugValue:
2479
case OpenCLDebugInfo100DebugMacroDef:
2480
case OpenCLDebugInfo100DebugMacroUndef:
2481
case OpenCLDebugInfo100DebugImportedEntity:
2483
case OpenCLDebugInfo100InstructionsMax:
2033
2489
return SPV_SUCCESS;