Updated spirv-cross.

This commit is contained in:
Бранимир Караџић 2023-06-24 09:55:14 -07:00
parent aaf0fdf7cf
commit 6cedc01d19
6 changed files with 278 additions and 57 deletions

View File

@ -820,6 +820,43 @@ spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *
#endif
}
size_t spvc_compiler_get_num_required_extensions(spvc_compiler compiler)
{
#if SPIRV_CROSS_C_API_GLSL
if (compiler->backend != SPVC_BACKEND_GLSL)
{
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
return SPVC_ERROR_INVALID_ARGUMENT;
}
return static_cast<CompilerGLSL *>(compiler->compiler.get())->get_required_extensions().size();
#else
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
return 0;
#endif
}
const char *spvc_compiler_get_required_extension(spvc_compiler compiler, size_t index)
{
#if SPIRV_CROSS_C_API_GLSL
if (compiler->backend != SPVC_BACKEND_GLSL)
{
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
return nullptr;
}
auto &exts = static_cast<CompilerGLSL *>(compiler->compiler.get())->get_required_extensions();
if (index < exts.size())
return exts[index].c_str();
else
return nullptr;
#else
(void)index;
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
return nullptr;
#endif
}
spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id)
{
#if SPIRV_CROSS_C_API_GLSL

View File

@ -40,7 +40,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 56
#define SPVC_C_API_VERSION_MINOR 57
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@ -784,6 +784,8 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_compile(spvc_compiler compiler, const
/* Maps to C++ API. */
SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler, const char *line);
SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext);
SPVC_PUBLIC_API size_t spvc_compiler_get_num_required_extensions(spvc_compiler compiler);
SPVC_PUBLIC_API const char *spvc_compiler_get_required_extension(spvc_compiler compiler, size_t index);
SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id);
SPVC_PUBLIC_API spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id);

View File

@ -5102,8 +5102,27 @@ string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_ty
return constant_expression(tmp);
}
string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
string CompilerGLSL::to_rerolled_array_expression(const SPIRType &parent_type,
const string &base_expr, const SPIRType &type)
{
bool remapped_boolean = parent_type.basetype == SPIRType::Struct &&
type.basetype == SPIRType::Boolean &&
backend.boolean_in_struct_remapped_type != SPIRType::Boolean;
SPIRType tmp_type;
if (remapped_boolean)
{
tmp_type = get<SPIRType>(type.parent_type);
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
}
else if (type.basetype == SPIRType::Boolean && backend.boolean_in_struct_remapped_type != SPIRType::Boolean)
{
// It's possible that we have an r-value expression that was OpLoaded from a struct.
// We have to reroll this and explicitly cast the input to bool, because the r-value is short.
tmp_type = get<SPIRType>(type.parent_type);
remapped_boolean = true;
}
uint32_t size = to_array_size_literal(type);
auto &parent = get<SPIRType>(type.parent_type);
string expr = "{ ";
@ -5111,10 +5130,14 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const
for (uint32_t i = 0; i < size; i++)
{
auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
if (parent.array.empty())
if (!type_is_top_level_array(parent))
{
if (remapped_boolean)
subexpr = join(type_to_glsl(tmp_type), "(", subexpr, ")");
expr += subexpr;
}
else
expr += to_rerolled_array_expression(subexpr, parent);
expr += to_rerolled_array_expression(parent_type, subexpr, parent);
if (i + 1 < size)
expr += ", ";
@ -5124,13 +5147,26 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const
return expr;
}
string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool block_like_type)
string CompilerGLSL::to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type)
{
auto &type = expression_type(id);
bool reroll_array = !type.array.empty() &&
(!backend.array_is_value_type ||
(block_like_type && !backend.array_is_value_type_in_buffer_blocks));
bool reroll_array = false;
bool remapped_boolean = parent_type.basetype == SPIRType::Struct &&
type.basetype == SPIRType::Boolean &&
backend.boolean_in_struct_remapped_type != SPIRType::Boolean;
if (type_is_top_level_array(type))
{
reroll_array = !backend.array_is_value_type ||
(block_like_type && !backend.array_is_value_type_in_buffer_blocks);
if (remapped_boolean)
{
// Forced to reroll if we have to change bool[] to short[].
reroll_array = true;
}
}
if (reroll_array)
{
@ -5144,10 +5180,20 @@ string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool block
// We're only triggering one read of the array expression, but this is fine since arrays have to be declared
// as temporaries anyways.
return to_rerolled_array_expression(to_enclosed_expression(id), type);
return to_rerolled_array_expression(parent_type, to_enclosed_expression(id), type);
}
else
return to_unpacked_expression(id);
{
auto expr = to_unpacked_expression(id);
if (remapped_boolean)
{
auto tmp_type = type;
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
expr = join(type_to_glsl(tmp_type), "(", expr, ")");
}
return expr;
}
}
string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id)
@ -5657,11 +5703,13 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
}
}
string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope)
string CompilerGLSL::constant_expression(const SPIRConstant &c,
bool inside_block_like_struct_scope,
bool inside_struct_scope)
{
auto &type = get<SPIRType>(c.constant_type);
if (type.pointer)
if (type_is_top_level_pointer(type))
{
return backend.null_pointer_literal;
}
@ -5676,19 +5724,32 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
// with Offset = 0, using no ArrayStride on the enclosed array type.
// A particular CTS test hits this scenario.
bool array_type_decays = inside_block_like_struct_scope &&
!type.array.empty() && !backend.array_is_value_type_in_buffer_blocks;
type_is_top_level_array(type) &&
!backend.array_is_value_type_in_buffer_blocks;
// Allow Metal to use the array<T> template to make arrays a value type
bool needs_trailing_tracket = false;
if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
type.array.empty())
!type_is_top_level_array(type))
{
res = type_to_glsl_constructor(type) + "{ ";
}
else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
!type.array.empty() && !array_type_decays)
type_is_top_level_array(type) && !array_type_decays)
{
res = type_to_glsl_constructor(type) + "({ ";
const auto *p_type = &type;
SPIRType tmp_type;
if (inside_struct_scope &&
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
type.basetype == SPIRType::Boolean)
{
tmp_type = type;
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
p_type = &tmp_type;
}
res = type_to_glsl_constructor(*p_type) + "({ ";
needs_trailing_tracket = true;
}
else if (backend.use_initializer_list)
@ -5718,7 +5779,7 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
res += to_name(elem);
else
{
if (type.array.empty() && type.basetype == SPIRType::Struct)
if (!type_is_top_level_array(type) && type.basetype == SPIRType::Struct)
{
// When we get down to emitting struct members, override the block-like information.
// For constants, we can freely mix and match block-like state.
@ -5726,7 +5787,10 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
has_member_decoration(type.self, subconstant_index, DecorationOffset);
}
res += constant_expression(subc, inside_block_like_struct_scope);
if (type.basetype == SPIRType::Struct)
inside_struct_scope = true;
res += constant_expression(subc, inside_block_like_struct_scope, inside_struct_scope);
}
}
@ -5748,19 +5812,30 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
if (backend.supports_empty_struct)
return "{ }";
else if (backend.use_typed_initializer_list)
return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
return join(type_to_glsl(type), "{ 0 }");
else if (backend.use_initializer_list)
return "{ 0 }";
else
return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
return join(type_to_glsl(type), "(0)");
}
else if (c.columns() == 1)
{
return constant_expression_vector(c, 0);
auto res = constant_expression_vector(c, 0);
if (inside_struct_scope &&
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
type.basetype == SPIRType::Boolean)
{
SPIRType tmp_type = type;
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
res = join(type_to_glsl(tmp_type), "(", res, ")");
}
return res;
}
else
{
string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
string res = type_to_glsl(type) + "(";
for (uint32_t col = 0; col < c.columns(); col++)
{
if (c.specialization_constant_id(col) != 0)
@ -5772,6 +5847,16 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
res += ", ";
}
res += ")";
if (inside_struct_scope &&
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
type.basetype == SPIRType::Boolean)
{
SPIRType tmp_type = type;
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
res = join(type_to_glsl(tmp_type), "(", res, ")");
}
return res;
}
}
@ -11107,7 +11192,7 @@ string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32
bool uses_buffer_offset =
type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
subop = to_composite_constructor_expression(type, elems[i], uses_buffer_offset);
}
base = e ? e->base_expression : ID(0);
@ -11197,8 +11282,15 @@ void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
if (backend.requires_relaxed_precision_analysis)
{
// If PHI variables are consumed in unexpected precision contexts, copy them here.
for (auto &phi : block.phi_variables)
for (size_t i = 0, n = block.phi_variables.size(); i < n; i++)
{
auto &phi = block.phi_variables[i];
// Ensure we only copy once. We know a-priori that this array will lay out
// the same function variables together.
if (i && block.phi_variables[i - 1].function_variable == phi.function_variable)
continue;
auto itr = temporary_to_mirror_precision_alias.find(phi.function_variable);
if (itr != temporary_to_mirror_precision_alias.end())
{
@ -11737,7 +11829,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
// it is an array, and our backend does not support arrays as value types.
// Emit the temporary, and copy it explicitly.
e = &emit_uninitialized_temporary_expression(result_type, id);
emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
emit_array_copy(nullptr, id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
}
else
e = &emit_op(result_type, id, expr, forward, !usage_tracking);
@ -15565,6 +15657,11 @@ void CompilerGLSL::require_extension(const std::string &ext)
forced_extensions.push_back(ext);
}
const SmallVector<std::string> &CompilerGLSL::get_required_extensions() const
{
return forced_extensions;
}
void CompilerGLSL::require_extension_internal(const string &ext)
{
if (backend.supports_extensions && !has_extension(ext))
@ -16329,6 +16426,17 @@ bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
return true;
}
void CompilerGLSL::emit_block_instructions_with_masked_debug(SPIRBlock &block)
{
// Have to block debug instructions such as OpLine here, since it will be treated as a statement otherwise,
// which breaks loop optimizations.
// Any line directive would be declared outside the loop body, which would just be confusing either way.
bool old_block_debug_directives = block_debug_directives;
block_debug_directives = true;
emit_block_instructions(block);
block_debug_directives = old_block_debug_directives;
}
bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
{
SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
@ -16339,7 +16447,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
// If we're trying to create a true for loop,
// we need to make sure that all opcodes before branch statement do not actually emit any code.
// We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
emit_block_instructions(block);
emit_block_instructions_with_masked_debug(block);
bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
@ -16419,7 +16527,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
// If we're trying to create a true for loop,
// we need to make sure that all opcodes before branch statement do not actually emit any code.
// We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
emit_block_instructions(child);
emit_block_instructions_with_masked_debug(child);
bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
@ -16557,6 +16665,24 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
if (block.merge == SPIRBlock::MergeLoop)
add_loop_level();
// If we're emitting PHI variables with precision aliases, we have to emit them as hoisted temporaries.
for (auto var_id : block.dominated_variables)
{
auto &var = get<SPIRVariable>(var_id);
if (var.phi_variable)
{
auto mirrored_precision_itr = temporary_to_mirror_precision_alias.find(var_id);
if (mirrored_precision_itr != temporary_to_mirror_precision_alias.end() &&
find_if(block.declare_temporary.begin(), block.declare_temporary.end(),
[mirrored_precision_itr](const std::pair<TypeID, VariableID> &p) {
return p.second == mirrored_precision_itr->second;
}) == block.declare_temporary.end())
{
block.declare_temporary.push_back({ var.basetype, mirrored_precision_itr->second });
}
}
}
emit_hoisted_temporaries(block.declare_temporary);
SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
@ -17338,9 +17464,16 @@ uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
}
void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass)
bool CompilerGLSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, StorageClass, StorageClass)
{
string lhs;
if (expr)
lhs = expr;
else
lhs = to_expression(lhs_id);
statement(lhs, " = ", to_expression(rhs_id), ";");
return true;
}
bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
@ -17773,6 +17906,11 @@ void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
if (redirect_statement)
return;
// If we're emitting code in a sensitive context such as condition blocks in for loops, don't emit
// any line directives, because it's not possible.
if (block_debug_directives)
return;
if (options.emit_line_directives)
{
require_extension_internal("GL_GOOGLE_cpp_style_line_directive");

View File

@ -258,6 +258,10 @@ public:
// require_extension("GL_KHR_my_extension");
void require_extension(const std::string &ext);
// Returns the list of required extensions. After compilation this will contains any other
// extensions that the compiler used automatically, in addition to the user specified ones.
const SmallVector<std::string> &get_required_extensions() const;
// Legacy GLSL compatibility method.
// Takes a uniform or push constant variable and flattens it into a (i|u)vec4 array[N]; array instead.
// For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but
@ -393,6 +397,7 @@ protected:
};
TemporaryCopy handle_instruction_precision(const Instruction &instr);
void emit_block_instructions(SPIRBlock &block);
void emit_block_instructions_with_masked_debug(SPIRBlock &block);
// For relax_nan_checks.
GLSLstd450 get_remapped_glsl_op(GLSLstd450 std450_op) const;
@ -426,7 +431,9 @@ protected:
const std::string &qualifier = "", uint32_t base_offset = 0);
virtual void emit_struct_padding_target(const SPIRType &type);
virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0);
std::string constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope = false);
std::string constant_expression(const SPIRConstant &c,
bool inside_block_like_struct_scope = false,
bool inside_struct_scope = false);
virtual std::string constant_op_expression(const SPIRConstantOp &cop);
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
virtual void emit_fixup();
@ -539,6 +546,7 @@ protected:
SmallVector<std::string> *redirect_statement = nullptr;
const SPIRBlock *current_continue_block = nullptr;
bool block_temporary_hoisting = false;
bool block_debug_directives = false;
void begin_scope();
void end_scope();
@ -604,6 +612,7 @@ protected:
const char *uint16_t_literal_suffix = "us";
const char *nonuniform_qualifier = "nonuniformEXT";
const char *boolean_mix_function = "mix";
SPIRType::BaseType boolean_in_struct_remapped_type = SPIRType::Boolean;
bool swizzle_is_function = false;
bool shared_is_implied = false;
bool unsized_array_supported = true;
@ -772,8 +781,8 @@ protected:
void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
std::string to_non_uniform_aware_expression(uint32_t id);
std::string to_expression(uint32_t id, bool register_expression_read = true);
std::string to_composite_constructor_expression(uint32_t id, bool block_like_type);
std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
std::string to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type);
std::string to_rerolled_array_expression(const SPIRType &parent_type, const std::string &expr, const SPIRType &type);
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
std::string to_unpacked_row_major_matrix_expression(uint32_t id);
@ -806,7 +815,7 @@ protected:
std::string layout_for_variable(const SPIRVariable &variable);
std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id);
virtual bool skip_argument(uint32_t id) const;
virtual void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id,
virtual bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
spv::StorageClass lhs_storage, spv::StorageClass rhs_storage);
virtual void emit_block_hints(const SPIRBlock &block);
virtual std::string to_initializer_expression(const SPIRVariable &var);

View File

@ -1467,6 +1467,7 @@ string CompilerMSL::compile()
backend.support_small_type_sampling_result = true;
backend.supports_empty_struct = true;
backend.support_64bit_switch = true;
backend.boolean_in_struct_remapped_type = SPIRType::Short;
// Allow Metal to use the array<T> template unless we force it off.
backend.can_return_array = !msl_options.force_native_arrays;
@ -7234,7 +7235,7 @@ void CompilerMSL::declare_constant_arrays()
// FIXME: However, hoisting constants to main() means we need to pass down constant arrays to leaf functions if they are used there.
// If there are multiple functions in the module, drop this case to avoid breaking use cases which do not need to
// link into Metal libraries. This is hacky.
if (!type.array.empty() && (!fully_inlined || is_scalar(type) || is_vector(type)))
if (type_is_top_level_array(type) && (!fully_inlined || is_scalar(type) || is_vector(type)))
{
add_resource_name(c.self);
auto name = to_name(c.self);
@ -7266,7 +7267,7 @@ void CompilerMSL::declare_complex_constant_arrays()
return;
auto &type = this->get<SPIRType>(c.constant_type);
if (!type.array.empty() && !(is_scalar(type) || is_vector(type)))
if (type_is_top_level_array(type) && !(is_scalar(type) || is_vector(type)))
{
add_resource_name(c.self);
auto name = to_name(c.self);
@ -7376,11 +7377,6 @@ void CompilerMSL::emit_specialization_constants_and_structs()
string sc_type_name = type_to_glsl(type);
add_resource_name(c.self);
string sc_name = to_name(c.self);
uint32_t constant_id = get_decoration(c.self, DecorationSpecId);
if (!unique_func_constants.count(constant_id))
unique_func_constants.insert(make_pair(constant_id, c.self));
SPIRType::BaseType sc_tmp_type = expression_type(unique_func_constants[constant_id]).basetype;
string sc_tmp_name = to_name(unique_func_constants[constant_id]) + "_tmp";
// Function constants are only supported in MSL 1.2 and later.
// If we don't support it just declare the "default" directly.
@ -7391,6 +7387,11 @@ void CompilerMSL::emit_specialization_constants_and_structs()
!c.is_used_as_array_length)
{
// Only scalar, non-composite values can be function constants.
uint32_t constant_id = get_decoration(c.self, DecorationSpecId);
if (!unique_func_constants.count(constant_id))
unique_func_constants.insert(make_pair(constant_id, c.self));
SPIRType::BaseType sc_tmp_type = expression_type(unique_func_constants[constant_id]).basetype;
string sc_tmp_name = to_name(unique_func_constants[constant_id]) + "_tmp";
if (unique_func_constants[constant_id] == c.self)
statement("constant ", sc_type_name, " ", sc_tmp_name, " [[function_constant(", constant_id,
")]];");
@ -9469,7 +9470,7 @@ static bool storage_class_array_is_thread(StorageClass storage)
}
}
void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t rhs_id,
bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
StorageClass lhs_storage, StorageClass rhs_storage)
{
// Allow Metal to use the array<T> template to make arrays a value type.
@ -9508,10 +9509,21 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r
// Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier.
if (lhs_is_array_template && rhs_is_array_template && !using_builtin_array())
{
statement(lhs, " = ", to_expression(rhs_id), ";");
// Fall back to normal copy path.
return false;
}
else
{
// Ensure the LHS variable has been declared
if (lhs_var)
flush_variable_declaration(lhs_var->self);
string lhs;
if (expr)
lhs = expr;
else
lhs = to_expression(lhs_id);
// Assignment from an array initializer is fine.
auto &type = expression_type(rhs_id);
auto *var = maybe_get_backing_variable(rhs_id);
@ -9585,6 +9597,8 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r
else
statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");");
}
return true;
}
uint32_t CompilerMSL::get_physical_tess_level_array_size(spv::BuiltIn builtin) const
@ -9641,14 +9655,11 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs)
}
}
// Ensure the LHS variable has been declared
auto *p_v_lhs = maybe_get_backing_variable(id_lhs);
if (p_v_lhs)
flush_variable_declaration(p_v_lhs->self);
auto lhs_storage = get_expression_effective_storage_class(id_lhs);
auto rhs_storage = get_expression_effective_storage_class(id_rhs);
emit_array_copy(to_expression(id_lhs), id_lhs, id_rhs, lhs_storage, rhs_storage);
if (!emit_array_copy(nullptr, id_lhs, id_rhs, lhs_storage, rhs_storage))
return false;
register_write(id_lhs);
return true;
@ -16784,20 +16795,31 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr,
auto *source_expr = maybe_get<SPIRExpression>(source_id);
auto *var = maybe_get_backing_variable(source_id);
const SPIRType *var_type = nullptr, *phys_type = nullptr;
if (uint32_t phys_id = get_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypeID))
phys_type = &get<SPIRType>(phys_id);
else
phys_type = &expr_type;
if (var)
{
source_id = var->self;
var_type = &get_variable_data_type(*var);
}
bool rewrite_boolean_load =
expr_type.basetype == SPIRType::Boolean &&
(var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct));
// Type fixups for workgroup variables if they are booleans.
if (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct) &&
expr_type.basetype == SPIRType::Boolean)
expr = join(type_to_glsl(expr_type), "(", expr, ")");
if (rewrite_boolean_load)
{
if (type_is_top_level_array(expr_type))
expr = to_rerolled_array_expression(expr_type, expr, expr_type);
else
expr = join(type_to_glsl(expr_type), "(", expr, ")");
}
// Type fixups for workgroup variables if they are matrices.
// Don't do fixup for packed types; those are handled specially.
// FIXME: Maybe use a type like spvStorageMatrix for packed matrices?
@ -16910,24 +16932,37 @@ void CompilerMSL::cast_to_variable_store(uint32_t target_id, std::string &expr,
auto *target_expr = maybe_get<SPIRExpression>(target_id);
auto *var = maybe_get_backing_variable(target_id);
const SPIRType *var_type = nullptr, *phys_type = nullptr;
if (uint32_t phys_id = get_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypeID))
phys_type = &get<SPIRType>(phys_id);
else
phys_type = &expr_type;
if (var)
{
target_id = var->self;
var_type = &get_variable_data_type(*var);
}
// Type fixups for workgroup variables if they are booleans.
if (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct) &&
expr_type.basetype == SPIRType::Boolean)
bool rewrite_boolean_store =
expr_type.basetype == SPIRType::Boolean &&
(var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct));
// Type fixups for workgroup variables or struct members if they are booleans.
if (rewrite_boolean_store)
{
auto short_type = expr_type;
short_type.basetype = SPIRType::Short;
expr = join(type_to_glsl(short_type), "(", expr, ")");
if (type_is_top_level_array(expr_type))
{
expr = to_rerolled_array_expression(*var_type, expr, expr_type);
}
else
{
auto short_type = expr_type;
short_type.basetype = SPIRType::Short;
expr = join(type_to_glsl(short_type), "(", expr, ")");
}
}
// Type fixups for workgroup variables if they are matrices.
// Don't do fixup for packed types; those are handled specially.
// FIXME: Maybe use a type like spvStorageMatrix for packed matrices?

View File

@ -1032,7 +1032,7 @@ protected:
void add_pragma_line(const std::string &line);
void add_typedef_line(const std::string &line);
void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem);
void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id,
bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
spv::StorageClass lhs_storage, spv::StorageClass rhs_storage) override;
void build_implicit_builtins();
uint32_t build_constant_uint_array_pointer();