MSL: Fix OpLoad of array which is forced to a temporary.

This commit is contained in:
Hans-Kristian Arntzen 2019-04-09 11:50:45 +02:00
parent b7aa0d4e08
commit bf07e5fa7b
4 changed files with 153 additions and 24 deletions

View File

@ -0,0 +1,37 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
constant float _21 = {};
struct main0_out
{
float4 gl_Position [[position]];
};
vertex main0_out main0()
{
main0_out out = {};
float _23[2];
for (int _25 = 0; _25 < 2; )
{
_23[_25] = 0.0;
_25++;
continue;
}
float _31[2];
spvArrayCopyFromStack1(_31, _23);
float _37;
if (as_type<uint>(3.0) != 0u)
{
_37 = _31[0];
}
else
{
_37 = _21;
}
out.gl_Position = float4(0.0, 0.0, 0.0, _37);
return out;
}

View File

@ -0,0 +1,60 @@
; SPIR-V
; Version: 1.0
; Generator: Google spiregg; 0
; Bound: 39
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %vs_main "main" %gl_Position
OpSource HLSL 600
OpName %vs_main "vs_main"
OpDecorate %gl_Position BuiltIn Position
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
%float = OpTypeFloat 32
%float_0 = OpConstant %float 0
%int_1 = OpConstant %int 1
%float_3 = OpConstant %float 3
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%void = OpTypeVoid
%15 = OpTypeFunction %void
%uint_2 = OpConstant %uint 2
%_arr_float_uint_2 = OpTypeArray %float %uint_2
%_ptr_Function__arr_float_uint_2 = OpTypePointer Function %_arr_float_uint_2
%_ptr_Function_float = OpTypePointer Function %float
%bool = OpTypeBool
%gl_Position = OpVariable %_ptr_Output_v4float Output
%21 = OpUndef %float
%vs_main = OpFunction %void None %15
%22 = OpLabel
%23 = OpVariable %_ptr_Function__arr_float_uint_2 Function
OpBranch %24
%24 = OpLabel
%25 = OpPhi %int %int_0 %22 %26 %27
%28 = OpSLessThan %bool %25 %int_2
OpLoopMerge %29 %27 None
OpBranchConditional %28 %27 %29
%27 = OpLabel
%30 = OpAccessChain %_ptr_Function_float %23 %25
OpStore %30 %float_0
%26 = OpIAdd %int %25 %int_1
OpBranch %24
%29 = OpLabel
%31 = OpLoad %_arr_float_uint_2 %23
%32 = OpBitcast %uint %float_3
%33 = OpINotEqual %bool %32 %uint_0
OpSelectionMerge %34 None
OpBranchConditional %33 %35 %34
%35 = OpLabel
%36 = OpCompositeExtract %float %31 0
OpBranch %34
%34 = OpLabel
%37 = OpPhi %float %21 %29 %36 %35
%38 = OpCompositeConstruct %v4float %float_0 %float_0 %float_0 %37
OpStore %gl_Position %38
OpReturn
OpFunctionEnd

View File

@ -3581,6 +3581,41 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
return res;
}
SPIRExpression &CompilerGLSL::emit_uninitialized_temporary_expression(uint32_t type, uint32_t id)
{
forced_temporaries.insert(id);
emit_uninitialized_temporary(type, id);
return set<SPIRExpression>(id, to_name(id), type, true);
}
void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t result_id)
{
// If we're declaring temporaries inside continue blocks,
// we must declare the temporary in the loop header so that the continue block can avoid declaring new variables.
if (current_continue_block && !hoisted_temporaries.count(result_id))
{
auto &header = get<SPIRBlock>(current_continue_block->loop_dominator);
if (find_if(begin(header.declare_temporary), end(header.declare_temporary),
[result_type, result_id](const pair<uint32_t, uint32_t> &tmp) {
return tmp.first == result_type && tmp.second == result_id;
}) == end(header.declare_temporary))
{
header.declare_temporary.emplace_back(result_type, result_id);
hoisted_temporaries.insert(result_id);
force_recompile();
}
}
else if (hoisted_temporaries.count(result_id) == 0)
{
auto &type = get<SPIRType>(result_type);
auto &flags = ir.meta[result_id].decoration.decoration_flags;
// The result_id has not been made into an expression yet, so use flags interface.
add_local_variable_name(result_id);
statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";");
}
}
string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
{
auto &type = get<SPIRType>(result_type);
@ -4841,10 +4876,7 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
{
forced_temporaries.insert(id);
auto &type = get<SPIRType>(result_type);
auto &flags = ir.meta[id].decoration.decoration_flags;
statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
set<SPIRExpression>(id, to_name(id), result_type, true);
emit_uninitialized_temporary_expression(result_type, id);
statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
to_expression(id), ".", to_member_name(type, 1), ");");
break;
@ -4984,10 +5016,7 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
{
forced_temporaries.insert(id);
auto &type = get<SPIRType>(result_type);
auto &flags = ir.meta[id].decoration.decoration_flags;
statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(id)), ";");
set<SPIRExpression>(id, to_name(id), result_type, true);
emit_uninitialized_temporary_expression(result_type, id);
statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ",
to_expression(id), ".", to_member_name(type, 1), ");");
break;
@ -7169,8 +7198,19 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
bool usage_tracking = ptr_expression && flattened_buffer_blocks.count(ptr_expression->loaded_from) != 0 &&
(type.basetype == SPIRType::Struct || (type.columns > 1));
auto &e = emit_op(result_type, id, expr, forward, !usage_tracking);
e.need_transpose = need_transpose;
SPIRExpression *e = nullptr;
if (!backend.array_is_value_type && !type.array.empty() && !forward)
{
// Complicated load case where we need to make a copy of ptr, but we cannot, because
// 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), ptr);
}
else
e = &emit_op(result_type, id, expr, forward, !usage_tracking);
e->need_transpose = need_transpose;
register_read(id, ptr, forward);
// Pass through whether the result is of a packed type.
@ -7183,7 +7223,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
inherit_expression_dependencies(id, ptr);
if (forward)
add_implied_read_expression(e, ptr);
add_implied_read_expression(*e, ptr);
break;
}
@ -7430,10 +7470,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
// 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.
forced_temporaries.insert(id);
auto &flags = ir.meta[id].decoration.decoration_flags;
statement(flags_to_precision_qualifiers_glsl(out_type, flags), variable_decl(out_type, to_name(id)), ";");
set<SPIRExpression>(id, to_name(id), result_type, true);
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]);
}
@ -7832,12 +7869,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t result_id = ops[1];
uint32_t op0 = ops[2];
uint32_t op1 = ops[3];
forced_temporaries.insert(result_id);
auto &type = get<SPIRType>(result_type);
auto &flags = ir.meta[result_id].decoration.decoration_flags;
statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";");
set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
emit_uninitialized_temporary_expression(result_type, result_id);
const char *op = opcode == OpIAddCarry ? "uaddCarry" : "usubBorrow";
statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", op, "(", to_expression(op0), ", ",
@ -7859,10 +7892,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t op1 = ops[3];
forced_temporaries.insert(result_id);
auto &type = get<SPIRType>(result_type);
auto &flags = ir.meta[result_id].decoration.decoration_flags;
statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";");
set<SPIRExpression>(result_id, to_name(result_id), result_type, true);
emit_uninitialized_temporary_expression(result_type, result_id);
const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended";
statement(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(result_id), ".",

View File

@ -484,6 +484,8 @@ protected:
const char *index_to_swizzle(uint32_t index);
std::string remap_swizzle(const SPIRType &result_type, uint32_t input_components, const std::string &expr);
std::string declare_temporary(uint32_t type, uint32_t id);
void emit_uninitialized_temporary(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, std::vector<std::string> &arglist);
std::string to_expression(uint32_t id, bool register_expression_read = true);
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);