[llvm] [InstCombine] Simplify conditional round-up to power-of-2 alignment (PR #184989)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 00:40:35 PDT 2026


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/184989

>From 23f035b1847e51faa29c7a4b5223396a09e81ad3 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 6 Mar 2026 12:04:05 +0100
Subject: [PATCH 1/3] [InstCombine] Introduce tests (NFC)

---
 .../simple-round-up-pow2-alignment.ll         | 246 ++++++++++++++++++
 1 file changed, 246 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll

diff --git a/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll b/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll
new file mode 100644
index 0000000000000..253e124bee8de
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll
@@ -0,0 +1,246 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Simple round up to next multiple of power-of-2 pattern that may arise
+; from div_ceil(X, P) * P.
+
+define i32 @round_up_pow2_2(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = shl i32 [[X]], 1
+; CHECK-NEXT:    [[SEL:%.*]] = and i32 [[AND]], 2
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[ADD]], -2
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 1
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 2
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -2
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_64(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_64(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_add_commuted(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_add_commuted(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], [[SEL]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %x, %sel
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_icmp_ne(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_icmp_ne(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_NOT]], i32 0, i32 64
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp ne i32 %and, 0
+  %sel = select i1 %cond, i32 64, i32 0
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define <2 x i32> @round_up_pow2_vector(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i32> @round_up_pow2_vector(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X]], splat (i32 63)
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[COND]], <2 x i32> zeroinitializer, <2 x i32> splat (i32 64)
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and <2 x i32> [[TMP1]], splat (i32 -64)
+; CHECK-NEXT:    ret <2 x i32> [[RES]]
+;
+  %and = and <2 x i32> %x, <i32 63, i32 63>
+  %cond = icmp eq <2 x i32> %and, zeroinitializer
+  %sel = select <2 x i1> %cond, <2 x i32> zeroinitializer, <2 x i32> <i32 64, i32 64>
+  %add = add <2 x i32> %sel, %x
+  %res = and <2 x i32> %add, <i32 -64, i32 -64>
+  ret <2 x i32> %res
+}
+
+define <2 x i32> @round_up_pow2_vector_icmp_ne(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i32> @round_up_pow2_vector_icmp_ne(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X]], splat (i32 63)
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[COND_NOT]], <2 x i32> zeroinitializer, <2 x i32> splat (i32 64)
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and <2 x i32> [[ADD]], splat (i32 -64)
+; CHECK-NEXT:    ret <2 x i32> [[RES]]
+;
+  %and = and <2 x i32> %x, <i32 63, i32 63>
+  %cond = icmp ne <2 x i32> %and, zeroinitializer
+  %sel = select <2 x i1> %cond, <2 x i32> <i32 64, i32 64>, <2 x i32> zeroinitializer
+  %add = add <2 x i32> %sel, %x
+  %res = and <2 x i32> %add, <i32 -64, i32 -64>
+  ret <2 x i32> %res
+}
+
+define i32 @round_up_pow2_multiuse_and(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_multiuse_and(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    call void @use(i32 [[AND]])
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  call void @use(i32 %and)
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+; Negative tests.
+
+define i32 @round_up_pow2_multiuse_add(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_multiuse_add(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    call void @use(i32 [[ADD]])
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[ADD]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  call void @use(i32 %add)
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_wrong_mask(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_wrong_mask(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 31
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[ADD]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 31
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_wrong_negated_pow2(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_wrong_negated_pow2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[ADD]], -63
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp eq i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -63
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_wrong_select_arms(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_wrong_select_arms(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_NOT]], i32 64, i32 0
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[ADD]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp ne i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define i32 @round_up_pow2_wrong_predicate(i32 %x) {
+; CHECK-LABEL: define i32 @round_up_pow2_wrong_predicate(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_NOT]], i32 64, i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and = and i32 %x, 63
+  %cond = icmp sgt i32 %and, 0
+  %sel = select i1 %cond, i32 0, i32 64
+  %add = add i32 %sel, %x
+  %res = and i32 %add, -64
+  ret i32 %res
+}
+
+define <2 x i32> @round_up_pow2_vector_poison_lane(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i32> @round_up_pow2_vector_poison_lane(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X]], splat (i32 63)
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
+; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[COND]], <2 x i32> zeroinitializer, <2 x i32> <i32 64, i32 poison>
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[SEL]], [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = and <2 x i32> [[ADD]], splat (i32 -64)
+; CHECK-NEXT:    ret <2 x i32> [[RES]]
+;
+  %and = and <2 x i32> %x, <i32 63, i32 63>
+  %cond = icmp eq <2 x i32> %and, zeroinitializer
+  %sel = select <2 x i1> %cond, <2 x i32> zeroinitializer, <2 x i32> <i32 64, i32 poison>
+  %add = add <2 x i32> %sel, %x
+  %res = and <2 x i32> %add, <i32 -64, i32 -64>
+  ret <2 x i32> %res
+}
+
+declare void @use(i32)

>From f583f49a3a463ed8d81cb982c349344a0bd683bb Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 6 Mar 2026 12:04:30 +0100
Subject: [PATCH 2/3] [InstCombine] Simplify conditional round-up to power-of-2
 alignment

The pattern `(X + (X % P == 0 ? 0 : P)) & -P`, that may arise
when computing `div_ceil(V, P) * P`, can be canonicalized to
`(X + P-1) & -P`, with P being a power of 2.

Proof: https://alive2.llvm.org/ce/z/ehyiNf.

Fixes: https://github.com/llvm/llvm-project/issues/184762.
---
 .../InstCombine/InstCombineAndOrXor.cpp       | 41 +++++++++++++++++++
 .../simple-round-up-pow2-alignment.ll         | 29 +++----------
 2 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 073f094639fa0..a21e0a1b83421 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2382,6 +2382,44 @@ static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
   return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
 }
 
+// The pattern div_ceil(X, P) * P, where P is a power of 2, lowers to a
+// conditional round-up of the following kind: (X + select(X % Pow2 == 0, 0,
+// Pow2)) & -Pow2. This may be simplified to (X + (Pow2-1)) & -Pow2.
+static Instruction *
+foldRoundUpToPow2Alignment(BinaryOperator &I,
+                           InstCombiner::BuilderTy &Builder) {
+  const APInt *NegP;
+  Value *Add;
+  if (!match(&I, m_And(m_Value(Add), m_APInt(NegP))) ||
+      !NegP->isNegatedPowerOf2())
+    return nullptr;
+
+  Value *X, *Cond;
+  const APInt *T, *F;
+  if (!match(Add, m_c_Add(m_Value(X),
+                          m_Select(m_Value(Cond), m_APInt(T), m_APInt(F)))) ||
+      !Add->hasOneUse())
+    return nullptr;
+
+  CmpPredicate Pred;
+  const APInt &Pow2 = -*NegP;
+  const APInt &Mask = Pow2 - 1;
+  // icmp ne should have already been canonicalized to the eq form for this
+  // pattern.
+  if (!match(Cond, m_ICmp(Pred, m_And(m_Specific(X), m_SpecificInt(Mask)),
+                          m_Zero())) ||
+      Pred != ICmpInst::ICMP_EQ)
+    return nullptr;
+
+  // Ensure the true arm of the select is zero, and the false one is the Pow2.
+  if (!T->isZero() || *F != Pow2)
+    return nullptr;
+
+  Type *Ty = I.getType();
+  Value *NewAdd = Builder.CreateAdd(X, ConstantInt::get(Ty, Mask));
+  return BinaryOperator::CreateAnd(NewAdd, ConstantInt::get(Ty, *NegP));
+}
+
 /// Reassociate and/or expressions to see if we can fold the inner and/or ops.
 /// TODO: Make this recursive; it's a little tricky because an arbitrary
 /// number of and/or instructions might have to be created.
@@ -2898,6 +2936,9 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
                                       /*SimplifyOnly*/ false, *this))
     return BinaryOperator::CreateAnd(Op0, V);
 
+  if (Instruction *Res = foldRoundUpToPow2Alignment(I, Builder))
+    return Res;
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll b/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll
index 253e124bee8de..66dd468800197 100644
--- a/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll
+++ b/llvm/test/Transforms/InstCombine/simple-round-up-pow2-alignment.ll
@@ -24,10 +24,7 @@ define i32 @round_up_pow2_2(i32 %x) {
 define i32 @round_up_pow2_64(i32 %x) {
 ; CHECK-LABEL: define i32 @round_up_pow2_64(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
-; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], 63
 ; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;
@@ -42,10 +39,7 @@ define i32 @round_up_pow2_64(i32 %x) {
 define i32 @round_up_pow2_add_commuted(i32 %x) {
 ; CHECK-LABEL: define i32 @round_up_pow2_add_commuted(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
-; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], [[SEL]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], 63
 ; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;
@@ -60,10 +54,7 @@ define i32 @round_up_pow2_add_commuted(i32 %x) {
 define i32 @round_up_pow2_icmp_ne(i32 %x) {
 ; CHECK-LABEL: define i32 @round_up_pow2_icmp_ne(
 ; CHECK-SAME: i32 [[X:%.*]]) {
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
-; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND_NOT]], i32 0, i32 64
-; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], 63
 ; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;
@@ -78,10 +69,7 @@ define i32 @round_up_pow2_icmp_ne(i32 %x) {
 define <2 x i32> @round_up_pow2_vector(<2 x i32> %x) {
 ; CHECK-LABEL: define <2 x i32> @round_up_pow2_vector(
 ; CHECK-SAME: <2 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X]], splat (i32 63)
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
-; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[COND]], <2 x i32> zeroinitializer, <2 x i32> splat (i32 64)
-; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[SEL]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[X]], splat (i32 63)
 ; CHECK-NEXT:    [[RES:%.*]] = and <2 x i32> [[TMP1]], splat (i32 -64)
 ; CHECK-NEXT:    ret <2 x i32> [[RES]]
 ;
@@ -96,10 +84,7 @@ define <2 x i32> @round_up_pow2_vector(<2 x i32> %x) {
 define <2 x i32> @round_up_pow2_vector_icmp_ne(<2 x i32> %x) {
 ; CHECK-LABEL: define <2 x i32> @round_up_pow2_vector_icmp_ne(
 ; CHECK-SAME: <2 x i32> [[X:%.*]]) {
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X]], splat (i32 63)
-; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer
-; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[COND_NOT]], <2 x i32> zeroinitializer, <2 x i32> splat (i32 64)
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[SEL]], [[X]]
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[X]], splat (i32 63)
 ; CHECK-NEXT:    [[RES:%.*]] = and <2 x i32> [[ADD]], splat (i32 -64)
 ; CHECK-NEXT:    ret <2 x i32> [[RES]]
 ;
@@ -116,9 +101,7 @@ define i32 @round_up_pow2_multiuse_and(i32 %x) {
 ; CHECK-SAME: i32 [[X:%.*]]) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X]], 63
 ; CHECK-NEXT:    call void @use(i32 [[AND]])
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i32 0, i32 64
-; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[SEL]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], 63
 ; CHECK-NEXT:    [[RES:%.*]] = and i32 [[TMP1]], -64
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;

>From eaf853261427aef05021f4271f9814b7a1507586 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Mon, 8 Jun 2026 09:40:05 +0200
Subject: [PATCH 3/3] !fixup improve code, style

---
 .../InstCombine/InstCombineAndOrXor.cpp       | 33 ++++++++-----------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index a21e0a1b83421..8b2d88d1418a7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2382,37 +2382,32 @@ static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
   return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
 }
 
-// The pattern div_ceil(X, P) * P, where P is a power of 2, lowers to a
-// conditional round-up of the following kind: (X + select(X % Pow2 == 0, 0,
-// Pow2)) & -Pow2. This may be simplified to (X + (Pow2-1)) & -Pow2.
+/// The pattern div_ceil(X, P) * P, where P is a power of 2, lowers to the
+/// following conditional round-up: (X + select(C, 0, Pow2)) & -Pow2, where
+/// C is X % Pow2 == 0. This may be simplified to (X + (Pow2-1)) & -Pow2.
 static Instruction *
 foldRoundUpToPow2Alignment(BinaryOperator &I,
                            InstCombiner::BuilderTy &Builder) {
   const APInt *NegP;
   Value *Add;
-  if (!match(&I, m_And(m_Value(Add), m_APInt(NegP))) ||
-      !NegP->isNegatedPowerOf2())
+  if (!match(&I, m_And(m_Value(Add), m_NegatedPower2(NegP))))
     return nullptr;
 
   Value *X, *Cond;
-  const APInt *T, *F;
-  if (!match(Add, m_c_Add(m_Value(X),
-                          m_Select(m_Value(Cond), m_APInt(T), m_APInt(F)))) ||
-      !Add->hasOneUse())
+  APInt Mask = ~*NegP;
+
+  // Match the pattern. Ensure the true arm of the select is zero, and the false
+  // one is the Pow2.
+  if (!match(Add,
+             m_OneUse(m_c_Add(m_Value(X), m_Select(m_Value(Cond), m_ZeroInt(),
+                                                   m_SpecificInt(-*NegP))))))
     return nullptr;
 
-  CmpPredicate Pred;
-  const APInt &Pow2 = -*NegP;
-  const APInt &Mask = Pow2 - 1;
   // icmp ne should have already been canonicalized to the eq form for this
   // pattern.
-  if (!match(Cond, m_ICmp(Pred, m_And(m_Specific(X), m_SpecificInt(Mask)),
-                          m_Zero())) ||
-      Pred != ICmpInst::ICMP_EQ)
-    return nullptr;
-
-  // Ensure the true arm of the select is zero, and the false one is the Pow2.
-  if (!T->isZero() || *F != Pow2)
+  if (!match(Cond, m_SpecificICmp(ICmpInst::ICMP_EQ,
+                                  m_And(m_Specific(X), m_SpecificInt(Mask)),
+                                  m_Zero())))
     return nullptr;
 
   Type *Ty = I.getType();



More information about the llvm-commits mailing list