From 71fe651e43e94c2ebc54a2655f3d93970fec0d3b Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 11 May 2023 11:42:32 +0200 Subject: [PATCH] Be more precise in usage of pointer/array mixing. --- spirv_cross.cpp | 42 +++++++++++++++++++++++++++++++++++++----- spirv_cross.hpp | 1 + spirv_msl.cpp | 4 ++-- spirv_reflect.cpp | 2 +- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/spirv_cross.cpp b/spirv_cross.cpp index c269adc3..49cc8386 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -5445,23 +5445,55 @@ void Compiler::analyze_interlocked_resource_usage() } bool Compiler::type_is_array_of_pointers(const SPIRType &type) const +{ + if (!type_is_top_level_array(type)) + return false; + + // BDA types must have parent type hierarchy. + if (!type.parent_type) + return false; + + // Punch through all array layers. + auto *parent = &get(type.parent_type); + while (type_is_top_level_array(*parent)) + parent = &get(parent->parent_type); + + return type_is_top_level_pointer(*parent); +} + +bool Compiler::type_is_top_level_pointer(const SPIRType &type) const { if (!type.pointer) return false; - // If parent type has same pointer depth, we must have an array of pointers. - return type.pointer_depth == get(type.parent_type).pointer_depth; + // Function pointers, should not be hit by valid SPIR-V. + // Parent type will be SPIRFunction instead. + if (type.basetype == SPIRType::Unknown) + return false; + + // Some types are synthesized in-place without complete type hierarchy and might not have parent types, + // but these types are never array-of-pointer or any complicated BDA type, infer reasonable defaults. + if (type.parent_type) + return type.pointer_depth > get(type.parent_type).pointer_depth; + else + return true; } bool Compiler::type_is_top_level_physical_pointer(const SPIRType &type) const { - return type.pointer && type.storage == StorageClassPhysicalStorageBuffer && - type.pointer_depth > get(type.parent_type).pointer_depth; + return type_is_top_level_pointer(type) && type.storage == StorageClassPhysicalStorageBuffer; } bool Compiler::type_is_top_level_array(const SPIRType &type) const { - return !type.array.empty() && type.array.size() > get(type.parent_type).array.size(); + if (type.array.empty()) + return false; + + // If we have pointer and array, we infer pointer-to-array as it's the only meaningful thing outside BDA. + if (type.parent_type) + return type.array.size() > get(type.parent_type).array.size(); + else + return !type.pointer; } bool Compiler::flush_phi_required(BlockID from, BlockID to) const diff --git a/spirv_cross.hpp b/spirv_cross.hpp index 9e9b5c8a..b99b7ae7 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -1145,6 +1145,7 @@ protected: bool type_is_array_of_pointers(const SPIRType &type) const; bool type_is_top_level_physical_pointer(const SPIRType &type) const; + bool type_is_top_level_pointer(const SPIRType &type) const; bool type_is_top_level_array(const SPIRType &type) const; bool type_is_block_like(const SPIRType &type) const; bool type_is_opaque_value(const SPIRType &type) const; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 630bc4c7..3318712a 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -14550,7 +14550,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id, bool member) string type_name; // Pointer? - if (type.pointer) + if (type_is_top_level_pointer(type) || type_is_array_of_pointers(type)) { assert(type.pointer_depth > 0); @@ -14578,7 +14578,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id, bool member) // the C-style nesting works right. // FIXME: This is somewhat of a hack. bool old_is_using_builtin_array = is_using_builtin_array; - if (type.storage == StorageClassPhysicalStorageBuffer) + if (type_is_top_level_physical_pointer(type)) is_using_builtin_array = false; type_name = join(type_address_space, " ", type_to_glsl(*p_parent_type, id)); diff --git a/spirv_reflect.cpp b/spirv_reflect.cpp index 0bd224e6..9fcd3bc0 100644 --- a/spirv_reflect.cpp +++ b/spirv_reflect.cpp @@ -292,7 +292,7 @@ bool CompilerReflection::type_is_reference(const SPIRType &type) const { // Physical pointers and arrays of physical pointers need to refer to the pointee's type. return type_is_top_level_physical_pointer(type) || - (!type.array.empty() && type_is_top_level_physical_pointer(get(type.parent_type))); + (type_is_array_of_pointers(type) && type.storage == StorageClassPhysicalStorageBuffer); } void CompilerReflection::emit_types()