[llvm] [AMDGPU] Fix assertion failure isReg() in SIPreEmitPeephole (PR #176590)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 18 03:02:29 PST 2026
https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/176590
>From 386d02c0da8151f8b1326ba3378b4d09c1d2c2e8 Mon Sep 17 00:00:00 2001
From: Serosh <janmejayapanda400 at gmail.com>
Date: Sun, 18 Jan 2026 00:35:08 +0530
Subject: [PATCH] [InstCombine] Fold range comparisons for logical-and/or with
bitwise forms
This patch extends the folding of range comparisons to handle cases where logical-and/or is expressed using bitwise 'and'/'or' instead of the canonical 'select' form.
Fixes GitHub issue #176554.
---
.../InstCombine/InstCombineAndOrXor.cpp | 34 +++++
.../InstCombine/range-check-and-form.ll | 121 ++++++++++++++++++
2 files changed, 155 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/range-check-and-form.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index aacb2e2a91c57..f28cf3ffa64a2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3612,6 +3612,40 @@ Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
return Res;
+ auto TryFold = [&](Value *L, Value *R) -> Value * {
+ Value *A, *B;
+ Instruction::BinaryOps Opcode = IsAnd ? Instruction::And : Instruction::Or;
+
+ if (match(L, m_BinOp(Opcode, m_Value(A), m_Value(B))) ||
+ (IsLogical && (IsAnd ? match(L, m_LogicalAnd(m_Value(A), m_Value(B)))
+ : match(L, m_LogicalOr(m_Value(A), m_Value(B)))))) {
+ for (int i = 0; i < 2; ++i) {
+ Value *Inner = i == 0 ? A : B;
+ Value *Other = i == 0 ? B : A;
+ auto *ICmpInner = dyn_cast<ICmpInst>(Inner);
+ auto *ICmpR = dyn_cast<ICmpInst>(R);
+ if (!ICmpInner || !ICmpR)
+ continue;
+
+ Value *Res = foldAndOrOfICmps(ICmpInner, ICmpR, I, IsAnd, IsLogical);
+ if (!Res)
+ continue;
+
+ if (IsLogical)
+ return IsAnd ? Builder.CreateSelect(Other, Res, Builder.getFalse())
+ : Builder.CreateSelect(Other, Builder.getTrue(), Res);
+
+ return Builder.CreateBinOp(Opcode, Other, Res);
+ }
+ }
+ return nullptr;
+ };
+
+ if (Value *V = TryFold(LHS, RHS))
+ return V;
+ if (Value *V = TryFold(RHS, LHS))
+ return V;
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/range-check-and-form.ll b/llvm/test/Transforms/InstCombine/range-check-and-form.ll
new file mode 100644
index 0000000000000..cab76141a3f97
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/range-check-and-form.ll
@@ -0,0 +1,121 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Test for GitHub issue #176554
+; InstCombine should fold range comparisons even when the logical-and
+; uses bitwise 'and' instead of 'select' form.
+
+; This is the buggy pattern that was not being optimized:
+; %cmp1 = icmp ugt i32 %y, 65535
+; %sel11 = and i1 %cond, %cmp1 ; <-- and instead of select
+; %cmp2 = icmp ult i32 %y, 1114112
+; %sel2 = select i1 %sel11, i1 %cmp2, i1 false
+;
+; Should be optimized to a single range check.
+
+define i1 @test_and_form(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_and_form(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -65536
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 1048576
+; CHECK-NEXT: [[SEL2:%.*]] = and i1 [[COND:%.*]], [[TMP2]]
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 65535
+ %sel11 = and i1 %cond, %cmp1
+ %cmp2 = icmp ult i32 %y, 1114112
+ %sel2 = select i1 %sel11, i1 %cmp2, i1 false
+ ret i1 %sel2
+}
+
+; Reference: the canonical select form that already works
+define i1 @test_select_form(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_select_form(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -65536
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 1048576
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND:%.*]], i1 [[TMP2]], i1 false
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 65535
+ %sel1 = select i1 %cond, i1 %cmp1, i1 false
+ %cmp2 = icmp ult i32 %y, 1114112
+ %sel2 = select i1 %sel1, i1 %cmp2, i1 false
+ ret i1 %sel2
+}
+
+; Test with the icmp on the other side of the and
+define i1 @test_and_form_swapped(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_and_form_swapped(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -65536
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 1048576
+; CHECK-NEXT: [[SEL2:%.*]] = and i1 [[TMP2]], [[COND:%.*]]
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 65535
+ %sel11 = and i1 %cmp1, %cond ; swapped operands
+ %cmp2 = icmp ult i32 %y, 1114112
+ %sel2 = select i1 %sel11, i1 %cmp2, i1 false
+ ret i1 %sel2
+}
+
+; Test logical-or form: select (or A, cmp1), true, cmp2
+define i1 @test_or_form(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_or_form(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -1114112
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -1048576
+; CHECK-NEXT: [[SEL2:%.*]] = or i1 [[COND:%.*]], [[TMP2]]
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 1114111
+ %sel11 = or i1 %cond, %cmp1
+ %cmp2 = icmp ult i32 %y, 65536
+ %sel2 = select i1 %sel11, i1 true, i1 %cmp2
+ ret i1 %sel2
+}
+
+; Test bitwise and reassociation: (cond & cmp1) & cmp2
+define i1 @test_bitwise_and(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_bitwise_and(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -65536
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 1048576
+; CHECK-NEXT: [[SEL2:%.*]] = and i1 [[COND:%.*]], [[TMP2]]
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 65535
+ %sel11 = and i1 %cond, %cmp1
+ %cmp2 = icmp ult i32 %y, 1114112
+ %sel2 = and i1 %sel11, %cmp2
+ ret i1 %sel2
+}
+
+; Test bitwise or reassociation: (cond | cmp1) | cmp2
+define i1 @test_bitwise_or(i1 %cond, i32 %y) {
+; CHECK-LABEL: @test_bitwise_or(
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[Y:%.*]], -1114112
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], -1048576
+; CHECK-NEXT: [[SEL2:%.*]] = or i1 [[COND:%.*]], [[TMP2]]
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 1114111
+ %sel11 = or i1 %cond, %cmp1
+ %cmp2 = icmp ult i32 %y, 65536
+ %sel2 = or i1 %sel11, %cmp2
+ ret i1 %sel2
+}
+
+
+; Negative test: different values in the icmps should not be folded
+define i1 @test_and_form_different_values(i1 %cond, i32 %y, i32 %z) {
+; CHECK-LABEL: @test_and_form_different_values(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[Y:%.*]], 65535
+; CHECK-NEXT: [[SEL11:%.*]] = and i1 [[COND:%.*]], [[CMP1]]
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Z:%.*]], 1114112
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[SEL11]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: ret i1 [[SEL2]]
+;
+ %cmp1 = icmp ugt i32 %y, 65535
+ %sel11 = and i1 %cond, %cmp1
+ %cmp2 = icmp ult i32 %z, 1114112 ; different value!
+ %sel2 = select i1 %sel11, i1 %cmp2, i1 false
+ ret i1 %sel2
+}
+
More information about the llvm-commits
mailing list