From 40233e38243e123da57adfec93ed2d4340a8d2a8 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Wed, 28 Oct 2026 13:23:17 -0400 Subject: [PATCH 1/6] Backport PR27137: Fix matchSelectPattern for bitwise-not of unsigned compares This backports https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996) which fixes PR27137. It corrects SPF_SMIN matching in matchSelectPattern where the previous code blindly assumed the predicate was ICMP_SGT, leading to incorrect MIN/MAX matching for other predicates. --- lib/Analysis/ValueTracking.cpp | 12 +++++++++--- test/Transforms/InstCombine/select.ll | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index d7612998ef23..a80f642aa8a1 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3386,9 +3386,15 @@ static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, if (C1->getType() == C2->getType() && ~C1->getValue() == C2->getValue() && (match(TrueVal, m_Not(m_Specific(CmpLHS))) || match(CmpLHS, m_Not(m_Specific(TrueVal))))) { - LHS = TrueVal; - RHS = FalseVal; - return SPF_SMIN; + +// HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. +// Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). + if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) { + LHS = TrueVal; + RHS = FalseVal; + return Pred == ICmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX; + } +// HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. } } } diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index fdf1199a66fb..66c18e753657 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -1562,3 +1562,20 @@ define i32 @PR23757(i32 %x) { %sel = select i1 %cmp, i32 -2147483648, i32 %add ret i32 %sel } + +; HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. +; Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). +define i32 @PR27137(i32 %a) { +; CHECK-LABEL: @PR27137( +; CHECK-NEXT: [[NOT_A:%[a-zA-Z0-9_]+]] = xor i32 %a, -1 +; CHECK-NEXT: [[C0:%[a-zA-Z0-9_]+]] = icmp slt i32 %a, 0 +; CHECK-NEXT: [[S0:%[a-zA-Z0-9_]+]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1 +; CHECK-NEXT: ret i32 [[S0]] + %not_a = xor i32 %a, -1 + %c0 = icmp slt i32 %a, 0 + %s0 = select i1 %c0, i32 %not_a, i32 -1 + %c1 = icmp sgt i32 %s0, -1 + %s1 = select i1 %c1, i32 %s0, i32 -1 + ret i32 %s1 +} +; HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. From 6459aca1bcf177952111803650a5a006cbbd296c Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Wed, 28 Oct 2026 14:23:21 -0400 Subject: [PATCH 2/6] formatting --- lib/Analysis/ValueTracking.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index a80f642aa8a1..7473a4caa852 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3387,14 +3387,14 @@ static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, (match(TrueVal, m_Not(m_Specific(CmpLHS))) || match(CmpLHS, m_Not(m_Specific(TrueVal))))) { -// HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. -// Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). + // HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. + // Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) { LHS = TrueVal; RHS = FalseVal; return Pred == ICmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX; } -// HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. + // HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. } } } From 60186f87f834dffbadd987de352bada57529ce2b Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Wed, 28 Oct 2026 14:52:09 -0400 Subject: [PATCH 3/6] format again --- lib/Analysis/ValueTracking.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 7473a4caa852..6fbd58eac57f 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3387,14 +3387,17 @@ static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, (match(TrueVal, m_Not(m_Specific(CmpLHS))) || match(CmpLHS, m_Not(m_Specific(TrueVal))))) { - // HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. - // Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). + // HLSL Change Begin - Fix matchSelectPattern for bitwise-not of + // unsigned compares. Backport of + // https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a + // (rL264996). if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) { LHS = TrueVal; RHS = FalseVal; return Pred == ICmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX; } - // HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. + // HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned + // compares. } } } From c60030d581030779b6426673754d33b16b00d5f1 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Wed, 28 Oct 2026 14:57:17 -0400 Subject: [PATCH 4/6] Move regression test and add release notes --- docs/ReleaseNotes.md | 2 ++ test/Transforms/InstCombine/select.ll | 18 ------------------ .../passes/llvm/instcombine/PR27137.ll | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index b48054bf2095..51ac7c0c541e 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -88,6 +88,8 @@ line upon naming the release. Refer to previous for appropriate section names. [#8526](https://github.com/microsoft/DirectXShaderCompiler/issues/8526). - Fixed incorrect shader results caused by stale overflow and exactness flags after bit-tracking dead code elimination. +- Fixed an optimizer miscompile where the compiler would incorrectly fold + bitwise-not of unsigned compares into an invalid signed min/max. ### Upcoming Preview Release diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index 66c18e753657..b62bfb0ec64a 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -1561,21 +1561,3 @@ define i32 @PR23757(i32 %x) { %add = add nsw i32 %x, 1 %sel = select i1 %cmp, i32 -2147483648, i32 %add ret i32 %sel -} - -; HLSL Change Begin - Fix matchSelectPattern for bitwise-not of unsigned compares. -; Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). -define i32 @PR27137(i32 %a) { -; CHECK-LABEL: @PR27137( -; CHECK-NEXT: [[NOT_A:%[a-zA-Z0-9_]+]] = xor i32 %a, -1 -; CHECK-NEXT: [[C0:%[a-zA-Z0-9_]+]] = icmp slt i32 %a, 0 -; CHECK-NEXT: [[S0:%[a-zA-Z0-9_]+]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1 -; CHECK-NEXT: ret i32 [[S0]] - %not_a = xor i32 %a, -1 - %c0 = icmp slt i32 %a, 0 - %s0 = select i1 %c0, i32 %not_a, i32 -1 - %c1 = icmp sgt i32 %s0, -1 - %s1 = select i1 %c1, i32 %s0, i32 -1 - ret i32 %s1 -} -; HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned compares. diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll new file mode 100644 index 000000000000..3c30b700d6bc --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll @@ -0,0 +1,16 @@ +; RUN: %opt %s -instcombine -S | FileCheck %s + +; Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). +define i32 @PR27137(i32 %a) { +; CHECK-LABEL: @PR27137( +; CHECK-NEXT: [[NOT_A:%[a-zA-Z0-9_]+]] = xor i32 %a, -1 +; CHECK-NEXT: [[C0:%[a-zA-Z0-9_]+]] = icmp slt i32 %a, 0 +; CHECK-NEXT: [[S0:%[a-zA-Z0-9_]+]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1 +; CHECK-NEXT: ret i32 [[S0]] + %not_a = xor i32 %a, -1 + %c0 = icmp slt i32 %a, 0 + %s0 = select i1 %c0, i32 %not_a, i32 -1 + %c1 = icmp sgt i32 %s0, -1 + %s1 = select i1 %c1, i32 %s0, i32 -1 + ret i32 %s1 +} From f32426372318a8ad895b972baa028177392ec16e Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Wed, 28 Oct 2026 15:20:07 -0400 Subject: [PATCH 5/6] fix eof/newlines --- lib/Analysis/ValueTracking.cpp | 1 - test/Transforms/InstCombine/select.ll | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 6fbd58eac57f..c846de886d7c 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3386,7 +3386,6 @@ static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, if (C1->getType() == C2->getType() && ~C1->getValue() == C2->getValue() && (match(TrueVal, m_Not(m_Specific(CmpLHS))) || match(CmpLHS, m_Not(m_Specific(TrueVal))))) { - // HLSL Change Begin - Fix matchSelectPattern for bitwise-not of // unsigned compares. Backport of // https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a diff --git a/test/Transforms/InstCombine/select.ll b/test/Transforms/InstCombine/select.ll index b62bfb0ec64a..fdf1199a66fb 100644 --- a/test/Transforms/InstCombine/select.ll +++ b/test/Transforms/InstCombine/select.ll @@ -1561,3 +1561,4 @@ define i32 @PR23757(i32 %x) { %add = add nsw i32 %x, 1 %sel = select i1 %cmp, i32 -2147483648, i32 %add ret i32 %sel +} From 8fcad80179e08c0b14ae62c3274d79a806794421 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Fri, 30 Oct 2026 12:55:49 -0400 Subject: [PATCH 6/6] simplify to straight backport --- docs/ReleaseNotes.md | 4 +-- lib/Analysis/ValueTracking.cpp | 19 +++++-------- .../instcombine-select-of-not-minmax.ll | 28 +++++++++++++++++++ .../passes/llvm/instcombine/PR27137.ll | 16 ----------- 4 files changed, 37 insertions(+), 30 deletions(-) create mode 100644 tools/clang/test/DXC/Passes/InstructionCombining/instcombine-select-of-not-minmax.ll delete mode 100644 tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 51ac7c0c541e..1edbc6921f98 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -88,8 +88,8 @@ line upon naming the release. Refer to previous for appropriate section names. [#8526](https://github.com/microsoft/DirectXShaderCompiler/issues/8526). - Fixed incorrect shader results caused by stale overflow and exactness flags after bit-tracking dead code elimination. -- Fixed an optimizer miscompile where the compiler would incorrectly fold - bitwise-not of unsigned compares into an invalid signed min/max. +- Fixed an optimizer miscompile where selects of bitwise-not values guarded by + signed less-than or unsigned compares were treated as a signed minimum. ### Upcoming Preview Release diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index c846de886d7c..f42bb0677c55 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -3383,20 +3383,15 @@ static SelectPatternFlavor matchSelectPattern(ICmpInst::Predicate Pred, // Y >s C ? ~Y : ~C == ~Y (FalseVal)) { - if (C1->getType() == C2->getType() && ~C1->getValue() == C2->getValue() && + // HLSL Change - Add missing sgt check. Backport of rL264996 (PR27137): + // https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a + if (Pred == ICmpInst::ICMP_SGT && C1->getType() == C2->getType() && + ~C1->getValue() == C2->getValue() && (match(TrueVal, m_Not(m_Specific(CmpLHS))) || match(CmpLHS, m_Not(m_Specific(TrueVal))))) { - // HLSL Change Begin - Fix matchSelectPattern for bitwise-not of - // unsigned compares. Backport of - // https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a - // (rL264996). - if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT) { - LHS = TrueVal; - RHS = FalseVal; - return Pred == ICmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX; - } - // HLSL Change End - Fix matchSelectPattern for bitwise-not of unsigned - // compares. + LHS = TrueVal; + RHS = FalseVal; + return SPF_SMIN; } } } diff --git a/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-select-of-not-minmax.ll b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-select-of-not-minmax.ll new file mode 100644 index 000000000000..48b00781b28a --- /dev/null +++ b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-select-of-not-minmax.ll @@ -0,0 +1,28 @@ +; RUN: %dxopt %s -instcombine -S | FileCheck %s + +; Regression test for the backport of +; https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a +; (rL264996), copied unchanged. matchSelectPattern matched (X pred C) ? ~X : ~C +; as smin(~X, ~C) regardless of the predicate, but that only holds for sgt. +; Before the fix, InstCombine folded @PR27137 to 'ret i32 -1', which is wrong +; for negative %a. + +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +define i32 @PR27137(i32 %a) { +; CHECK-LABEL: @PR27137( +; CHECK-NEXT: %not_a = xor i32 %a, -1 +; CHECK-NEXT: %c0 = icmp slt i32 %a, 0 +; CHECK-NEXT: %s0 = select i1 %c0, i32 %not_a, i32 -1 +; CHECK-NEXT: %c1 = icmp sgt i32 %s0, -1 +; CHECK-NEXT: %s1 = select i1 %c1, i32 %s0, i32 -1 +; CHECK-NEXT: ret i32 %s1 + + %not_a = xor i32 %a, -1 + %c0 = icmp slt i32 %a, 0 + %s0 = select i1 %c0, i32 %not_a, i32 -1 + %c1 = icmp sgt i32 %s0, -1 + %s1 = select i1 %c1, i32 %s0, i32 -1 + ret i32 %s1 +} diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll deleted file mode 100644 index 3c30b700d6bc..000000000000 --- a/tools/clang/test/HLSLFileCheck/passes/llvm/instcombine/PR27137.ll +++ /dev/null @@ -1,16 +0,0 @@ -; RUN: %opt %s -instcombine -S | FileCheck %s - -; Backport of https://github.com/llvm/llvm-project/commit/56df0ec61033a5bb49b3620e70cc6a61e26b3e7a (rL264996). -define i32 @PR27137(i32 %a) { -; CHECK-LABEL: @PR27137( -; CHECK-NEXT: [[NOT_A:%[a-zA-Z0-9_]+]] = xor i32 %a, -1 -; CHECK-NEXT: [[C0:%[a-zA-Z0-9_]+]] = icmp slt i32 %a, 0 -; CHECK-NEXT: [[S0:%[a-zA-Z0-9_]+]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1 -; CHECK-NEXT: ret i32 [[S0]] - %not_a = xor i32 %a, -1 - %c0 = icmp slt i32 %a, 0 - %s0 = select i1 %c0, i32 %not_a, i32 -1 - %c1 = icmp sgt i32 %s0, -1 - %s1 = select i1 %c1, i32 %s0, i32 -1 - ret i32 %s1 -}