diff --git a/reference/opt/shaders-msl/frag/modf-access-tracking-function.frag b/reference/opt/shaders-msl/frag/modf-access-tracking-function.frag new file mode 100644 index 00000000..612dd4e9 --- /dev/null +++ b/reference/opt/shaders-msl/frag/modf-access-tracking-function.frag @@ -0,0 +1,24 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 vo0 [[color(0)]]; + float4 vo1 [[color(1)]]; +}; + +struct main0_in +{ + float4 v [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + float4 _25 = modf(in.v, out.vo1); + out.vo0 = _25; + return out; +} + diff --git a/reference/opt/shaders/frag/modf-pointer-function-analysis.frag b/reference/opt/shaders/frag/modf-pointer-function-analysis.frag new file mode 100644 index 00000000..07160bbd --- /dev/null +++ b/reference/opt/shaders/frag/modf-pointer-function-analysis.frag @@ -0,0 +1,18 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 0) out vec4 vo0; +layout(location = 1) out vec4 vo1; + +void main() +{ + vec4 param; + vec4 _59 = modf(v, param); + vo0 = _59; + vo1 = param; + vec4 param_1 = param; + float _65 = modf(v.x, param_1.x); + vo0.x += _65; + vo1.x += param_1.x; +} + diff --git a/reference/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag b/reference/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag new file mode 100644 index 00000000..5ba57b3f --- /dev/null +++ b/reference/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 _GLF_color [[color(0)]]; +}; + +fragment main0_out main0() +{ + main0_out out = {}; + float4 _13 = modf(float4(1.0, 0.0, 0.0, 1.0), out._GLF_color); + return out; +} + diff --git a/reference/shaders-msl/frag/modf-access-tracking-function.frag b/reference/shaders-msl/frag/modf-access-tracking-function.frag new file mode 100644 index 00000000..934561e8 --- /dev/null +++ b/reference/shaders-msl/frag/modf-access-tracking-function.frag @@ -0,0 +1,33 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 vo0 [[color(0)]]; + float4 vo1 [[color(1)]]; +}; + +struct main0_in +{ + float4 v [[user(locn0)]]; +}; + +static inline __attribute__((always_inline)) +float4 modf_inner(thread float4& v, thread float4& vo1) +{ + float4 _16 = modf(v, vo1); + return _16; +} + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + float4 _20 = modf_inner(in.v, out.vo1); + out.vo0 = _20; + return out; +} + diff --git a/reference/shaders-no-opt/frag/modf-non-function-purity-analysis.frag b/reference/shaders-no-opt/frag/modf-non-function-purity-analysis.frag new file mode 100644 index 00000000..3a4e0866 --- /dev/null +++ b/reference/shaders-no-opt/frag/modf-non-function-purity-analysis.frag @@ -0,0 +1,18 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 1) out vec4 vo1; +layout(location = 0) out vec4 vo0; + +vec4 modf_inner() +{ + vec4 _16 = modf(v, vo1); + return _16; +} + +void main() +{ + vec4 _20 = modf_inner(); + vo0 = _20; +} + diff --git a/reference/shaders/frag/modf-pointer-function-analysis.frag b/reference/shaders/frag/modf-pointer-function-analysis.frag new file mode 100644 index 00000000..2ca0050b --- /dev/null +++ b/reference/shaders/frag/modf-pointer-function-analysis.frag @@ -0,0 +1,32 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 0) out vec4 vo0; +layout(location = 1) out vec4 vo1; + +vec4 modf_inner(out vec4 tmp) +{ + vec4 _20 = modf(v, tmp); + return _20; +} + +float modf_inner_partial(inout vec4 tmp) +{ + float _30 = modf(v.x, tmp.x); + return _30; +} + +void main() +{ + vec4 param; + vec4 _37 = modf_inner(param); + vec4 tmp = param; + vo0 = _37; + vo1 = tmp; + vec4 param_1 = tmp; + float _43 = modf_inner_partial(param_1); + tmp = param_1; + vo0.x += _43; + vo1.x += tmp.x; +} + diff --git a/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag b/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag new file mode 100644 index 00000000..702b826e --- /dev/null +++ b/shaders-msl-no-opt/asm/frag/usage-tracking-modf-io-pointer.asm.frag @@ -0,0 +1,28 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 14 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %_GLF_color "_GLF_color" + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %10 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpExtInst %v4float %1 Modf %10 %_GLF_color + OpReturn + OpFunctionEnd diff --git a/shaders-msl/frag/modf-access-tracking-function.frag b/shaders-msl/frag/modf-access-tracking-function.frag new file mode 100644 index 00000000..c1f1a126 --- /dev/null +++ b/shaders-msl/frag/modf-access-tracking-function.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 0) out vec4 vo0; +layout(location = 1) out vec4 vo1; + +vec4 modf_inner() +{ + return modf(v, vo1); +} + +void main() +{ + vo0 = modf_inner(); +} diff --git a/shaders-no-opt/frag/modf-non-function-purity-analysis.frag b/shaders-no-opt/frag/modf-non-function-purity-analysis.frag new file mode 100644 index 00000000..c1f1a126 --- /dev/null +++ b/shaders-no-opt/frag/modf-non-function-purity-analysis.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 0) out vec4 vo0; +layout(location = 1) out vec4 vo1; + +vec4 modf_inner() +{ + return modf(v, vo1); +} + +void main() +{ + vo0 = modf_inner(); +} diff --git a/shaders/frag/modf-pointer-function-analysis.frag b/shaders/frag/modf-pointer-function-analysis.frag new file mode 100644 index 00000000..21e51262 --- /dev/null +++ b/shaders/frag/modf-pointer-function-analysis.frag @@ -0,0 +1,25 @@ +#version 450 + +layout(location = 0) in vec4 v; +layout(location = 0) out vec4 vo0; +layout(location = 1) out vec4 vo1; + +vec4 modf_inner(out vec4 tmp) +{ + return modf(v, tmp); +} + +float modf_inner_partial(inout vec4 tmp) +{ + return modf(v.x, tmp.x); +} + +void main() +{ + vec4 tmp; + vo0 = modf_inner(tmp); + vo1 = tmp; + + vo0.x += modf_inner_partial(tmp); + vo1.x += tmp.x; +} diff --git a/spirv_cross.cpp b/spirv_cross.cpp index edcf8e7c..99b69ad9 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -181,6 +181,30 @@ bool Compiler::block_is_pure(const SPIRBlock &block) // This is a global side effect of the function. return false; + case OpExtInst: + { + uint32_t extension_set = ops[2]; + if (get(extension_set).ext == SPIRExtension::GLSL) + { + auto op_450 = static_cast(ops[3]); + switch (op_450) + { + case GLSLstd450Modf: + case GLSLstd450Frexp: + { + auto &type = expression_type(ops[5]); + if (type.storage != StorageClassFunction) + return false; + break; + } + + default: + break; + } + } + break; + } + default: break; } @@ -716,6 +740,15 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t break; } + case GLSLstd450Modf: + case GLSLstd450Fract: + { + auto *var = compiler.maybe_get(args[5]); + if (var && storage_class_is_interface(var->storage)) + variables.insert(args[5]); + break; + } + default: break; } @@ -3290,6 +3323,33 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 for (uint32_t i = 4; i < length; i++) notify_variable_access(args[i], current_block->self); notify_variable_access(args[1], current_block->self); + + uint32_t extension_set = args[2]; + if (compiler.get(extension_set).ext == SPIRExtension::GLSL) + { + auto op_450 = static_cast(args[3]); + switch (op_450) + { + case GLSLstd450Modf: + case GLSLstd450Frexp: + { + uint32_t ptr = args[5]; + auto *var = compiler.maybe_get_backing_variable(ptr); + if (var) + { + accessed_variables_to_block[var->self].insert(current_block->self); + if (var->self == ptr) + complete_write_variables_to_block[var->self].insert(current_block->self); + else + partial_write_variables_to_block[var->self].insert(current_block->self); + } + break; + } + + default: + break; + } + } break; } diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 9a154099..2c0fd3cd 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -1710,6 +1710,16 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: added_arg_ids.insert(stage_in_var_id); break; } + + case GLSLstd450Modf: + case GLSLstd450Frexp: + { + uint32_t base_id = ops[5]; + if (global_var_ids.find(base_id) != global_var_ids.end()) + added_arg_ids.insert(base_id); + break; + } + default: break; }