From 74a523f19d4bbefed46b8fb46690abd485b07e72 Mon Sep 17 00:00:00 2001 From: Joel Kiptoo Date: Tue, 29 Sep 2026 19:38:36 +0300 Subject: [PATCH] Fix constant folding of frac for negative values The DXIL constant folder evaluated Frc as fabs(modf(x)), which is |x - trunc(x)|, so frac(-1.75) folded to 0.75 instead of 0.25. Scalars are folded earlier with x - floor(x), but matrix arguments reach the DXIL folder. Use x - floor(x) there as well. The existing frac_literal.hlsl expectations for the negative matrix elements encoded the old result; update them and add the case from the issue. Fixes #8937 --- docs/ReleaseNotes.md | 3 +++ lib/Analysis/DxilConstantFolding.cpp | 7 +++---- .../HLSLFileCheck/hlsl/intrinsics/basic/frac_literal.hlsl | 7 ++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 4da2a4f644..f66c336e46 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -67,6 +67,9 @@ line upon naming the release. Refer to previous for appropriate section names. - Fixed an optimizer crash when scalarizing an out-of-bounds vector access [#8940](https://github.com/microsoft/DirectXShaderCompiler/issues/8940). +- Fixed constant folding of `frac` returning `abs(x - trunc(x))` instead of + `x - floor(x)` for negative values, such as matrix arguments + [#8937](https://github.com/microsoft/DirectXShaderCompiler/issues/8937). ### Upcoming Preview Release diff --git a/lib/Analysis/DxilConstantFolding.cpp b/lib/Analysis/DxilConstantFolding.cpp index d30595e6a3..050b1fadb3 100644 --- a/lib/Analysis/DxilConstantFolding.cpp +++ b/lib/Analysis/DxilConstantFolding.cpp @@ -192,10 +192,9 @@ static Constant *ConstantFoldUnaryFPIntrinsic(OP::OpCode opcode, Type *Ty, case OP::OpCode::Exp: return DxilConstantFoldFP(exp2, Op, Ty); case OP::OpCode::Frc: { - NativeFPUnaryOp f = [](double x) { - double unused; - return fabs(modf(x, &unused)); - }; + // frac(x) = x - floor(x), so negative inputs also give a result in + // [+0, 1), the same as the front end's folding of the frac intrinsic + NativeFPUnaryOp f = [](double x) { return x - floor(x); }; return DxilConstantFoldFP(f, Op, Ty); } case OP::OpCode::Log: diff --git a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/frac_literal.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/frac_literal.hlsl index 1962d4dde6..30ff6512e4 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/frac_literal.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/intrinsics/basic/frac_literal.hlsl @@ -56,8 +56,13 @@ void main() { f4buf[2] = float4(fmat_splat[0][0], fmat_splat[0][1], fmat_splat[1][0], fmat_splat[1][1]) ; // matrix non-splat - // CHECK: float 0x3F2A400000000000, float 0x3F53A92A40000000, float 0x3FCD710000000000, float 0.000000e+00 + // CHECK: float 0x3FEFFE5C00000000, float 0x3FEFF62B60000000, float 0x3FCD710000000000, float 0.000000e+00 float2x2 fmat = { -21.0002, -0.0012, 421.23, 1 }; fmat = frac(fmat); f4buf[3] = float4(fmat[0][0], fmat[0][1], fmat[1][0], fmat[1][1]) ; + + // matrix with negative values: frac(x) = x - floor(x) + // CHECK: float 2.500000e-01, float 7.500000e-01, float 7.500000e-01, float 2.500000e-01 + float2x2 fmat_neg = frac(float2x2(-1.75, -0.25, 0.75, 1.25)); + f4buf[4] = float4(fmat_neg[0][0], fmat_neg[0][1], fmat_neg[1][0], fmat_neg[1][1]); }