From 8b24477c586f67b142f65c5c7912284f06c40dbb Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 30 Nov 2023 13:41:01 -0800 Subject: [PATCH] Propagate precise from formal parameter to actual parameter (#6058) It is unclear what should happen if an input parameter on a function is marked as precise. I am choosing to propagate it to the actual parameters. Note that it is not wrong to propagate precise more than we should since it will only stop some optimizations. --- tools/clang/lib/SPIRV/PreciseVisitor.cpp | 14 +++++++++++++ tools/clang/lib/SPIRV/PreciseVisitor.h | 1 + .../decoration.no-contraction.hlsl | 10 +++++++++- .../decoration.no-contraction.parameters.hlsl | 20 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tools/clang/test/CodeGenSPIRV/decoration.no-contraction.parameters.hlsl diff --git a/tools/clang/lib/SPIRV/PreciseVisitor.cpp b/tools/clang/lib/SPIRV/PreciseVisitor.cpp index 1ec27f6161..e34a93cd6d 100644 --- a/tools/clang/lib/SPIRV/PreciseVisitor.cpp +++ b/tools/clang/lib/SPIRV/PreciseVisitor.cpp @@ -251,5 +251,19 @@ bool PreciseVisitor::visit(SpirvExtInst *inst) { return true; } +bool PreciseVisitor::visit(SpirvFunctionCall *call) { + // If a formal parameter for the function is precise, then the corresponding + // actual parameter should be marked as precise. + auto function = call->getFunction(); + for (uint32_t i = 0; i < call->getArgs().size(); ++i) { + auto formalParameter = function->getParameters()[i]; + if (!formalParameter->isPrecise()) { + continue; + } + call->getArgs()[i]->setPrecise(); + } + return true; +} + } // end namespace spirv } // end namespace clang diff --git a/tools/clang/lib/SPIRV/PreciseVisitor.h b/tools/clang/lib/SPIRV/PreciseVisitor.h index 41fc4fd11f..0704aede40 100644 --- a/tools/clang/lib/SPIRV/PreciseVisitor.h +++ b/tools/clang/lib/SPIRV/PreciseVisitor.h @@ -39,6 +39,7 @@ class PreciseVisitor : public Visitor { bool visit(SpirvNonUniformBinaryOp *) override; bool visit(SpirvNonUniformUnaryOp *) override; bool visit(SpirvExtInst *) override; + bool visit(SpirvFunctionCall *) override; using Visitor::visit; diff --git a/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.hlsl b/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.hlsl index 436532cb38..f56f02dc4c 100644 --- a/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.hlsl +++ b/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.hlsl @@ -13,6 +13,8 @@ float func4(float i, float j, precise out float k); // CHECK-NEXT: OpDecorate [[aw_mul_bw:%[0-9]+]] NoContraction // CHECK-NEXT: OpDecorate [[cw_mul_dw:%[0-9]+]] NoContraction // CHECK-NEXT: OpDecorate [[awbw_plus_cwdw:%[0-9]+]] NoContraction +// CHECK-NEXT: OpDecorate [[func_ax_mul_bx:%[0-9]+]] NoContraction +// CHECK-NEXT: OpDecorate [[func_cx_mul_dx:%[0-9]+]] NoContraction // CHECK-NEXT: OpDecorate [[func2_e_mul_f:%[0-9]+]] NoContraction // CHECK-NEXT: OpDecorate [[func2_g_mul_h:%[0-9]+]] NoContraction // CHECK-NEXT: OpDecorate [[func2_ef_plus_gh:%[0-9]+]] NoContraction @@ -63,7 +65,13 @@ void main() { // Even though v.x is precise, values computed inside func4 are not forced to // be precise. Meaning, precise-ness does not cross function boundary. v.x = func3(a.x, b.x, c.x, d.x); - + +// Because the precise keyword is on the output parameter in func4, the formal input parameters will get marked as precise as well. This should propagate to the actual parameters. +// CHECK: [[func_ax_mul_bx]] = OpFMul +// CHECK: OpStore %param_var_i [[func_ax_mul_bx]] +// CHECK: [[func_cx_mul_dx]] = OpFMul +// CHECK: OpStore %param_var_j [[func_cx_mul_dx]] +// CHECK: OpFunctionCall %float %func4 %param_var_i %param_var_j func4(a.x * b.x, c.x * d.x, v.x); } diff --git a/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.parameters.hlsl b/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.parameters.hlsl new file mode 100644 index 0000000000..e051a16143 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/decoration.no-contraction.parameters.hlsl @@ -0,0 +1,20 @@ +// RUN: %dxc -T vs_6_0 -E VSMain %s -fcgl -spirv | FileCheck %s + +struct VSInput +{ + float4 pos : ATTRIBUTE0; +}; + +float4x4 Proj; + +precise float4 MakePrecise(precise float4 v) { return v; } + +// CHECK: OpDecorate [[mul:%[0-9]+]] NoContraction + +void VSMain(VSInput input, out precise float4 OutputPos : SV_Position) +{ + // CHECK: [[mul]] = OpMatrixTimesVector + // CHECK: OpStore %param_var_v [[mul]] + // CHECK: OpFunctionCall %v4float %MakePrecise %param_var_v + OutputPos = MakePrecise(mul(input.pos, Proj)); +}