Skip to content

Commit 19042c8

Browse files
spirv-val: Improve Explicit Layout message (KhronosGroup#6331)
closes KhronosGroup#6323 and KhronosGroup#6071 New messages now look like > [VUID-StandaloneSpirv-None-10684] Invalid explicit layout decorations on type for operand '5[%_ptr_Private__struct_2]', the Private storage class has a explicit layout from the Offset decoration. and > [VUID-StandaloneSpirv-None-10684] Invalid explicit layout decorations on type for operand '6[%_ptr_Workgroup__arr_uint_uint_4]', the Workgroup storage class has a explicit layout from the ArrayStride decoration. ---- Providing both the storage class and the decoration that makes it explicit layout should be enough, the whole details around which version make it valid or not-valid I think is overkill, the main thing is showing a SPIR-V generator what to look for
1 parent 42809ea commit 19042c8

File tree

3 files changed

+132
-39
lines changed

3 files changed

+132
-39
lines changed

source/table2.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,69 @@ bool GetExtensionFromString(const char* name, Extension* extension) {
372372
return false;
373373
}
374374

375+
// This is dirty copy of the spirv.hpp11 function
376+
// TODO - Use a generated version of this function
377+
const char* StorageClassToString(spv::StorageClass value) {
378+
switch (value) {
379+
case spv::StorageClass::UniformConstant:
380+
return "UniformConstant";
381+
case spv::StorageClass::Input:
382+
return "Input";
383+
case spv::StorageClass::Uniform:
384+
return "Uniform";
385+
case spv::StorageClass::Output:
386+
return "Output";
387+
case spv::StorageClass::Workgroup:
388+
return "Workgroup";
389+
case spv::StorageClass::CrossWorkgroup:
390+
return "CrossWorkgroup";
391+
case spv::StorageClass::Private:
392+
return "Private";
393+
case spv::StorageClass::Function:
394+
return "Function";
395+
case spv::StorageClass::Generic:
396+
return "Generic";
397+
case spv::StorageClass::PushConstant:
398+
return "PushConstant";
399+
case spv::StorageClass::AtomicCounter:
400+
return "AtomicCounter";
401+
case spv::StorageClass::Image:
402+
return "Image";
403+
case spv::StorageClass::StorageBuffer:
404+
return "StorageBuffer";
405+
case spv::StorageClass::TileImageEXT:
406+
return "TileImageEXT";
407+
case spv::StorageClass::TileAttachmentQCOM:
408+
return "TileAttachmentQCOM";
409+
case spv::StorageClass::NodePayloadAMDX:
410+
return "NodePayloadAMDX";
411+
case spv::StorageClass::CallableDataKHR:
412+
return "CallableDataKHR";
413+
case spv::StorageClass::IncomingCallableDataKHR:
414+
return "IncomingCallableDataKHR";
415+
case spv::StorageClass::RayPayloadKHR:
416+
return "RayPayloadKHR";
417+
case spv::StorageClass::HitAttributeKHR:
418+
return "HitAttributeKHR";
419+
case spv::StorageClass::IncomingRayPayloadKHR:
420+
return "IncomingRayPayloadKHR";
421+
case spv::StorageClass::ShaderRecordBufferKHR:
422+
return "ShaderRecordBufferKHR";
423+
case spv::StorageClass::PhysicalStorageBuffer:
424+
return "PhysicalStorageBuffer";
425+
case spv::StorageClass::HitObjectAttributeNV:
426+
return "HitObjectAttributeNV";
427+
case spv::StorageClass::TaskPayloadWorkgroupEXT:
428+
return "TaskPayloadWorkgroupEXT";
429+
case spv::StorageClass::CodeSectionINTEL:
430+
return "CodeSectionINTEL";
431+
case spv::StorageClass::DeviceOnlyINTEL:
432+
return "DeviceOnlyINTEL";
433+
case spv::StorageClass::HostOnlyINTEL:
434+
return "HostOnlyINTEL";
435+
default:
436+
return "Unknown";
437+
}
438+
}
439+
375440
} // namespace spvtools

source/table2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,5 +256,8 @@ bool GetExtensionFromString(const char* str, Extension* extension);
256256
// Returns text string corresponding to |extension|.
257257
const char* ExtensionToString(Extension extension);
258258

259+
/// Used to provide better error message
260+
const char* StorageClassToString(spv::StorageClass value);
261+
259262
} // namespace spvtools
260263
#endif // SOURCE_TABLE2_H_

source/val/validate_decorations.cpp

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,17 +2176,19 @@ bool AllowsLayout(ValidationState_t& vstate, const spv::StorageClass sc) {
21762176
}
21772177
}
21782178

2179-
bool UsesExplicitLayout(ValidationState_t& vstate, uint32_t type_id,
2180-
std::unordered_map<uint32_t, bool>& cache) {
2179+
// Returns a decoration used to make it explicit
2180+
spv::Decoration UsesExplicitLayout(
2181+
ValidationState_t& vstate, uint32_t type_id,
2182+
std::unordered_map<uint32_t, spv::Decoration>& cache) {
21812183
if (type_id == 0) {
2182-
return false;
2184+
return spv::Decoration::Max;
21832185
}
21842186

21852187
if (cache.count(type_id)) {
21862188
return cache[type_id];
21872189
}
21882190

2189-
bool res = false;
2191+
spv::Decoration res = spv::Decoration::Max;
21902192
const auto type_inst = vstate.FindDef(type_id);
21912193
if (type_inst->opcode() == spv::Op::OpTypeStruct ||
21922194
type_inst->opcode() == spv::Op::OpTypeArray ||
@@ -2202,21 +2204,26 @@ bool UsesExplicitLayout(ValidationState_t& vstate, uint32_t type_id,
22022204
allowLayoutDecorations = AllowsLayout(vstate, sc);
22032205
}
22042206
if (!allowLayoutDecorations) {
2205-
res = std::any_of(
2206-
iter->second.begin(), iter->second.end(), [](const Decoration& d) {
2207-
return d.dec_type() == spv::Decoration::Block ||
2208-
d.dec_type() == spv::Decoration::BufferBlock ||
2209-
d.dec_type() == spv::Decoration::Offset ||
2210-
d.dec_type() == spv::Decoration::ArrayStride ||
2211-
d.dec_type() == spv::Decoration::MatrixStride;
2212-
});
2207+
for (const auto& d : iter->second) {
2208+
const spv::Decoration dec = d.dec_type();
2209+
if (dec == spv::Decoration::Block ||
2210+
dec == spv::Decoration::BufferBlock ||
2211+
dec == spv::Decoration::Offset ||
2212+
dec == spv::Decoration::ArrayStride ||
2213+
dec == spv::Decoration::MatrixStride) {
2214+
res = dec;
2215+
break;
2216+
}
2217+
}
22132218
}
22142219
}
22152220

2216-
if (!res) {
2221+
if (res == spv::Decoration::Max) {
22172222
switch (type_inst->opcode()) {
22182223
case spv::Op::OpTypeStruct:
2219-
for (uint32_t i = 1; !res && i < type_inst->operands().size(); i++) {
2224+
for (uint32_t i = 1;
2225+
res == spv::Decoration::Max && i < type_inst->operands().size();
2226+
i++) {
22202227
res = UsesExplicitLayout(
22212228
vstate, type_inst->GetOperandAs<uint32_t>(i), cache);
22222229
}
@@ -2248,10 +2255,13 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
22482255
return SPV_SUCCESS;
22492256
}
22502257

2251-
std::unordered_map<uint32_t, bool> cache;
2258+
std::unordered_map<uint32_t, spv::Decoration> cache;
22522259
for (const auto& inst : vstate.ordered_instructions()) {
22532260
const auto type_id = inst.type_id();
22542261
const auto type_inst = vstate.FindDef(type_id);
2262+
2263+
spv::StorageClass sc = spv::StorageClass::Max;
2264+
spv::Decoration layout_dec = spv::Decoration::Max;
22552265
uint32_t fail_id = 0;
22562266
// Variables are the main place to check for improper decorations, but some
22572267
// untyped pointer instructions must also be checked since those types may
@@ -2261,16 +2271,18 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
22612271
switch (inst.opcode()) {
22622272
case spv::Op::OpVariable:
22632273
case spv::Op::OpUntypedVariableKHR: {
2264-
const auto sc = inst.GetOperandAs<spv::StorageClass>(2);
2274+
sc = inst.GetOperandAs<spv::StorageClass>(2);
22652275
auto check_id = type_id;
22662276
if (inst.opcode() == spv::Op::OpUntypedVariableKHR) {
22672277
if (inst.operands().size() > 3) {
22682278
check_id = inst.GetOperandAs<uint32_t>(3);
22692279
}
22702280
}
2271-
if (!AllowsLayout(vstate, sc) &&
2272-
UsesExplicitLayout(vstate, check_id, cache)) {
2273-
fail_id = check_id;
2281+
if (!AllowsLayout(vstate, sc)) {
2282+
layout_dec = UsesExplicitLayout(vstate, check_id, cache);
2283+
if (layout_dec != spv::Decoration::Max) {
2284+
fail_id = check_id;
2285+
}
22742286
}
22752287
break;
22762288
}
@@ -2280,13 +2292,17 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
22802292
case spv::Op::OpUntypedInBoundsPtrAccessChainKHR: {
22812293
// Check both the base type and return type. The return type may have an
22822294
// invalid array stride.
2283-
const auto sc = type_inst->GetOperandAs<spv::StorageClass>(1);
2284-
const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
2295+
sc = type_inst->GetOperandAs<spv::StorageClass>(1);
22852296
if (!AllowsLayout(vstate, sc)) {
2286-
if (UsesExplicitLayout(vstate, base_type_id, cache)) {
2297+
const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
2298+
layout_dec = UsesExplicitLayout(vstate, base_type_id, cache);
2299+
if (layout_dec != spv::Decoration::Max) {
22872300
fail_id = base_type_id;
2288-
} else if (UsesExplicitLayout(vstate, type_id, cache)) {
2289-
fail_id = type_id;
2301+
} else {
2302+
layout_dec = UsesExplicitLayout(vstate, type_id, cache);
2303+
if (layout_dec != spv::Decoration::Max) {
2304+
fail_id = type_id;
2305+
}
22902306
}
22912307
}
22922308
break;
@@ -2296,11 +2312,13 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
22962312
const auto ptr_ty_id =
22972313
vstate.FindDef(inst.GetOperandAs<uint32_t>(3))->type_id();
22982314
const auto ptr_ty = vstate.FindDef(ptr_ty_id);
2299-
const auto sc = ptr_ty->GetOperandAs<spv::StorageClass>(1);
2300-
const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
2301-
if (!AllowsLayout(vstate, sc) &&
2302-
UsesExplicitLayout(vstate, base_type_id, cache)) {
2303-
fail_id = base_type_id;
2315+
sc = ptr_ty->GetOperandAs<spv::StorageClass>(1);
2316+
if (!AllowsLayout(vstate, sc)) {
2317+
const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
2318+
layout_dec = UsesExplicitLayout(vstate, base_type_id, cache);
2319+
if (layout_dec != spv::Decoration::Max) {
2320+
fail_id = base_type_id;
2321+
}
23042322
}
23052323
break;
23062324
}
@@ -2309,10 +2327,12 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
23092327
const auto ptr_type = vstate.FindDef(vstate.FindDef(ptr_id)->type_id());
23102328
if (ptr_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
23112329
// For untyped pointers check the return type for an invalid layout.
2312-
const auto sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
2313-
if (!AllowsLayout(vstate, sc) &&
2314-
UsesExplicitLayout(vstate, type_id, cache)) {
2315-
fail_id = type_id;
2330+
sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
2331+
if (!AllowsLayout(vstate, sc)) {
2332+
layout_dec = UsesExplicitLayout(vstate, type_id, cache);
2333+
if (layout_dec != spv::Decoration::Max) {
2334+
fail_id = type_id;
2335+
}
23162336
}
23172337
}
23182338
break;
@@ -2323,11 +2343,13 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
23232343
if (ptr_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
23242344
// For untyped pointers, check the type of the data operand for an
23252345
// invalid layout.
2326-
const auto sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
2327-
const auto data_type_id = vstate.GetOperandTypeId(&inst, 1);
2328-
if (!AllowsLayout(vstate, sc) &&
2329-
UsesExplicitLayout(vstate, data_type_id, cache)) {
2330-
fail_id = inst.GetOperandAs<uint32_t>(2);
2346+
sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
2347+
if (!AllowsLayout(vstate, sc)) {
2348+
const auto data_type_id = vstate.GetOperandTypeId(&inst, 1);
2349+
layout_dec = UsesExplicitLayout(vstate, data_type_id, cache);
2350+
if (layout_dec != spv::Decoration::Max) {
2351+
fail_id = inst.GetOperandAs<uint32_t>(2);
2352+
}
23312353
}
23322354
}
23332355
break;
@@ -2339,7 +2361,10 @@ spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
23392361
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
23402362
<< vstate.VkErrorID(10684)
23412363
<< "Invalid explicit layout decorations on type for operand "
2342-
<< vstate.getIdName(fail_id);
2364+
<< vstate.getIdName(fail_id) << ", the "
2365+
<< spvtools::StorageClassToString(sc)
2366+
<< " storage class has a explicit layout from the "
2367+
<< vstate.SpvDecorationString(layout_dec) << " decoration.";
23432368
}
23442369
}
23452370

0 commit comments

Comments
 (0)