https://github.com/Serosh-commits updated 
https://github.com/llvm/llvm-project/pull/176590

>From c01243bcbc79068bce0a3f7ad5a3779d53ea97c1 Mon Sep 17 00:00:00 2001
From: Serosh <[email protected]>
Date: Sat, 17 Jan 2026 16:46:46 +0530
Subject: [PATCH 1/3] [clang][bytecode] Fix stack corruption in pointer
 arithmetic discard

In VisitPointerArithBinOp, the result of pointer addition or subtraction
was always left on the stack, even if the result was intended to be
discarded (e.g. in a comma expression). This led to stack corruption
where subsequent operations would find an unexpected pointer on the
stack, causing an assertion failure in the InterpStack.

This patch ensures that we correctly respect the DiscardResult flag
for pointer arithmetic operations.

Fixes #176549
---
 clang/lib/AST/ByteCode/Compiler.cpp  | 20 +++++++++++---------
 clang/test/AST/ByteCode/gh176549.cpp |  8 ++++++++
 2 files changed, 19 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/gh176549.cpp

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index 21f8db06919ed..66b0cc4b5f6ab 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1083,20 +1083,22 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const 
BinaryOperator *E) {
   if (Op == BO_Add) {
     if (!this->emitAddOffset(OffsetType, E))
       return false;
-
-    if (classifyPrim(E) != PT_Ptr)
-      return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E);
-    return true;
-  }
-  if (Op == BO_Sub) {
+  } else if (Op == BO_Sub) {
     if (!this->emitSubOffset(OffsetType, E))
       return false;
+  } else {
+    return false;
+  }
 
-    if (classifyPrim(E) != PT_Ptr)
-      return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E);
-    return true;
+  if (classifyPrim(E) != PT_Ptr) {
+    if (!this->emitDecayPtr(PT_Ptr, classifyPrim(E), E))
+      return false;
   }
 
+  if (DiscardResult)
+    return this->emitPop(classifyPrim(E), E);
+  return true;
+
   return false;
 }
 
diff --git a/clang/test/AST/ByteCode/gh176549.cpp 
b/clang/test/AST/ByteCode/gh176549.cpp
new file mode 100644
index 0000000000000..b56f762b7ede4
--- /dev/null
+++ b/clang/test/AST/ByteCode/gh176549.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// expected-no-diagnostics
+
+const char a[4] = "abc";
+void foo() {
+  int i = 0;
+  i = 1 > (a + 1, sizeof(a));
+}

>From 59f33d9ed24e822f84283fa84fd72e6b25b440d2 Mon Sep 17 00:00:00 2001
From: Serosh <[email protected]>
Date: Sun, 18 Jan 2026 00:34:45 +0530
Subject: [PATCH 2/3] [AMDGPU] Fix assertion failure in SIPreEmitPeephole

Fixes #176578. Add check for register operand before calling getReg() in 
optimizeVccBranch to prevent assertion failure when operand is an immediate.
---
 llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp 
b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index 8785968569d92..d15f89fdc78fc 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -153,11 +153,12 @@ bool SIPreEmitPeephole::optimizeVccBranch(MachineInstr 
&MI) const {
 
   MachineOperand &Op1 = A->getOperand(1);
   MachineOperand &Op2 = A->getOperand(2);
-  if (Op1.getReg() != ExecReg && Op2.isReg() && Op2.getReg() == ExecReg) {
+  if ((!Op1.isReg() || Op1.getReg() != ExecReg) && Op2.isReg() &&
+      Op2.getReg() == ExecReg) {
     TII->commuteInstruction(*A);
     Changed = true;
   }
-  if (Op1.getReg() != ExecReg)
+  if (!Op1.isReg() || Op1.getReg() != ExecReg)
     return Changed;
   if (Op2.isImm() && !(Op2.getImm() == -1 || Op2.getImm() == 0))
     return Changed;

>From 24ddc97a809f819c46c0b03c5052626ee3495b04 Mon Sep 17 00:00:00 2001
From: Serosh <[email protected]>
Date: Sun, 18 Jan 2026 00:35:08 +0530
Subject: [PATCH 3/3] [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
+}
+

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to