MSL: Re-roll array expressions in initializers.

We cannot rely on copy path when using an array as part of a struct
initializer, so reroll such expressions to an initializer list again.
This commit is contained in:
Hans-Kristian Arntzen 2019-07-10 11:19:33 +02:00
parent 53ab2144b9
commit f6f849397e
4 changed files with 50 additions and 27 deletions

View File

@ -73,17 +73,11 @@ kernel void main0(device BUF& o [[buffer(0)]])
o.a = int(c[1][1][1]); o.a = int(c[1][1][1]);
float _43[2] = { o.b, o.c }; float _43[2] = { o.b, o.c };
float _48[2] = { o.b, o.b }; float _48[2] = { o.b, o.b };
float _49[2][2]; float _49[2][2] = { { _43[0], _43[1] }, { _48[0], _48[1] } };
spvArrayCopyFromStack1(_49[0], _43);
spvArrayCopyFromStack1(_49[1], _48);
float _54[2] = { o.c, o.c }; float _54[2] = { o.c, o.c };
float _59[2] = { o.c, o.b }; float _59[2] = { o.c, o.b };
float _60[2][2]; float _60[2][2] = { { _54[0], _54[1] }, { _59[0], _59[1] } };
spvArrayCopyFromStack1(_60[0], _54); float _61[2][2][2] = { { { _49[0][0], _49[0][1] }, { _49[1][0], _49[1][1] } }, { { _60[0][0], _60[0][1] }, { _60[1][0], _60[1][1] } } };
spvArrayCopyFromStack1(_60[1], _59);
float _61[2][2][2];
spvArrayCopyFromStack2(_61[0], _49);
spvArrayCopyFromStack2(_61[1], _60);
float d[2][2][2]; float d[2][2][2];
spvArrayCopyFromStack3(d, _61); spvArrayCopyFromStack3(d, _61);
float e[2][2][2]; float e[2][2][2];

View File

@ -2886,6 +2886,49 @@ string CompilerGLSL::to_extract_component_expression(uint32_t id, uint32_t index
return join(expr, ".", index_to_swizzle(index)); return join(expr, ".", index_to_swizzle(index));
} }
string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
{
uint32_t size = to_array_size_literal(type);
auto &parent = get<SPIRType>(type.parent_type);
string expr = "{ ";
for (uint32_t i = 0; i < size; i++)
{
auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
if (parent.array.empty())
expr += subexpr;
else
expr += to_rerolled_array_expression(subexpr, parent);
if (i + 1 < size)
expr += ", ";
}
expr += " }";
return expr;
}
string CompilerGLSL::to_composite_constructor_expression(uint32_t id)
{
auto &type = expression_type(id);
if (!backend.array_is_value_type && !type.array.empty())
{
// For this case, we need to "re-roll" an array initializer from a temporary.
// We cannot simply pass the array directly, since it decays to a pointer and it cannot
// participate in a struct initializer. E.g.
// float arr[2] = { 1.0, 2.0 };
// Foo foo = { arr }; must be transformed to
// Foo foo = { { arr[0], arr[1] } };
// The array sizes cannot be deduced from specialization constants since we cannot use any loops.
// 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);
}
else
return to_expression(id);
}
string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
{ {
auto itr = invalid_expressions.find(id); auto itr = invalid_expressions.find(id);
@ -7302,7 +7345,7 @@ string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32
if (i) if (i)
op += ", "; op += ", ";
subop = to_expression(elems[i]); subop = to_composite_constructor_expression(elems[i]);
} }
base = e ? e->base_expression : 0; base = e ? e->base_expression : 0;
@ -7858,15 +7901,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
forward = false; forward = false;
string constructor_op; string constructor_op;
if (!backend.array_is_value_type && out_type.array.size() > 1) if (backend.use_initializer_list && composite)
{
// We cannot construct array of arrays because we cannot treat the inputs
// as value types. Need to declare the array-of-arrays, and copy in elements one by one.
emit_uninitialized_temporary_expression(result_type, id);
for (uint32_t i = 0; i < length; i++)
emit_array_copy(join(to_expression(id), "[", i, "]"), elems[i]);
}
else if (backend.use_initializer_list && composite)
{ {
// Only use this path if we are building composites. // Only use this path if we are building composites.
// This path cannot be used for arithmetic. // This path cannot be used for arithmetic.

View File

@ -502,6 +502,8 @@ protected:
SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id); SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id);
void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist); void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
std::string to_expression(uint32_t id, bool register_expression_read = true); std::string to_expression(uint32_t id, bool register_expression_read = true);
std::string to_composite_constructor_expression(uint32_t id);
std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true); 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_expression(uint32_t id, bool register_expression_read = true);
std::string to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read = true); std::string to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read = true);

View File

@ -8691,14 +8691,6 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o
return SPVFuncImplTextureSwizzle; return SPVFuncImplTextureSwizzle;
break; break;
case OpCompositeConstruct:
{
auto &type = compiler.get<SPIRType>(args[0]);
if (type.array.size() > 1) // We need to use copies to build the composite.
return static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + type.array.size() - 1);
break;
}
case OpExtInst: case OpExtInst:
{ {
uint32_t extension_set = args[2]; uint32_t extension_set = args[2];