From abb345d0b3b781843912de74f26a7b6e6ac56f6b Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 26 Jul 2019 11:02:38 +0200 Subject: [PATCH] MSL: Deal with Modf/Frexp where output is access chain to scalar. This is not allowed as we cannot take mutable reference to a vec.{x,y,z,w}. We only care about scalar since entire vectors are fine. --- ...-frexp-scalar-access-chain-output.asm.frag | 17 +++++++++ ...-frexp-scalar-access-chain-output.asm.frag | 36 +++++++++++++++++++ spirv_msl.cpp | 26 ++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag create mode 100644 shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag diff --git a/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag b/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag new file mode 100644 index 00000000..910c8fa7 --- /dev/null +++ b/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +fragment void main0() +{ + float3 col; + int2 _18; + float _23; + float _21 = modf(0.1500000059604644775390625, _23); + col.x = _23; + int _24; + float _22 = frexp(0.1500000059604644775390625, _24); + _18.y = _24; +} + diff --git a/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag b/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag new file mode 100644 index 00000000..707fa550 --- /dev/null +++ b/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag @@ -0,0 +1,36 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 17 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %col "col" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_0_150000006 = OpConstant %float 0.150000006 + %v3float = OpTypeVector %float 3 +%_ptr_Function_v3float = OpTypePointer Function %v3float + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %v2int = OpTypeVector %int 2 +%_ptr_Function_v2int = OpTypePointer Function %v2int +%_ptr_Function_int = OpTypePointer Function %int + %main = OpFunction %void None %3 + %5 = OpLabel + %col = OpVariable %_ptr_Function_v3float Function + %icol = OpVariable %_ptr_Function_v2int Function + %ptr_x = OpAccessChain %_ptr_Function_float %col %int_0 + %ptr_y = OpAccessChain %_ptr_Function_int %icol %int_1 + %16 = OpExtInst %float %1 Modf %float_0_150000006 %ptr_x + %17 = OpExtInst %float %1 Frexp %float_0_150000006 %ptr_y + OpReturn + OpFunctionEnd diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 1805e12a..a4f911c3 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -5260,6 +5260,32 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); break; + case GLSLstd450Modf: + case GLSLstd450Frexp: + { + // Special case. If the variable is a scalar access chain, we cannot use it directly. We have to emit a temporary. + auto *ptr = maybe_get(args[1]); + if (ptr && ptr->access_chain && is_scalar(expression_type(args[1]))) + { + register_call_out_argument(args[1]); + forced_temporaries.insert(id); + + // Need to create temporaries and copy over to access chain after. + // We cannot directly take the reference of a vector swizzle in MSL, even if it's scalar ... + uint32_t &tmp_id = extra_sub_expressions[id]; + if (!tmp_id) + tmp_id = ir.increase_bound_by(1); + + uint32_t tmp_type_id = get_pointee_type_id(ptr->expression_type); + emit_uninitialized_temporary_expression(tmp_type_id, tmp_id); + emit_binary_func_op(result_type, id, args[0], tmp_id, eop == GLSLstd450Modf ? "modf" : "frexp"); + statement(to_expression(args[1]), " = ", to_expression(tmp_id), ";"); + } + else + CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); + break; + } + default: CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); break;