[llvm] 3ee35ae - [InstCombine] support zext in ceiling division fold (#216470)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 15 03:18:55 PDT 2026
Author: Andreas Jonson
Date: 2026-08-15T12:18:50+02:00
New Revision: 3ee35aec0bc1d98dd724b95b7eb5d69109c40ca1
URL: https://github.com/llvm/llvm-project/commit/3ee35aec0bc1d98dd724b95b7eb5d69109c40ca1
DIFF: https://github.com/llvm/llvm-project/commit/3ee35aec0bc1d98dd724b95b7eb5d69109c40ca1.diff
LOG: [InstCombine] support zext in ceiling division fold (#216470)
Proof https://alive2.llvm.org/ce/z/vxRGV7
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/add.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 30812cafd2f80..5aa83f787d479 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1919,20 +1919,26 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
// Match: (X >> C) + zext((X & Mask) != 0)
// or: zext((X & Mask) != 0) + (X >> C)
- if (match(&I, m_c_Add(m_OneUse(m_LShr(m_Value(X), m_APInt(ShiftAmt))),
- m_ZExt(m_SpecificICmp(
- ICmpInst::ICMP_NE,
- m_And(m_Deferred(X), m_LowBitMask(Mask)),
- m_ZeroInt())))) &&
+ if (match(&I,
+ m_c_Add(m_ZExt(m_SpecificICmp(
+ ICmpInst::ICMP_NE,
+ m_And(m_Value(X), m_LowBitMask(Mask)), m_ZeroInt())),
+ m_OneUse(m_ZExtOrSelf(m_OneUse(
+ m_LShr(m_Deferred(X), m_APInt(ShiftAmt))))))) &&
Mask->popcount() == *ShiftAmt) {
// Check if X + Mask doesn't overflow
- Constant *MaskC = ConstantInt::get(X->getType(), *Mask);
- if (willNotOverflowUnsignedAdd(X, MaskC, I)) {
+ unsigned Xbits = X->getType()->getScalarSizeInBits();
+ unsigned Ibits = Ty->getScalarSizeInBits();
+ bool NeedZext = Ibits > Xbits;
+ Constant *MaskC = ConstantInt::get(Ty, Mask->zext(Ibits));
+ if (NeedZext || willNotOverflowUnsignedAdd(X, MaskC, I)) {
+ if (NeedZext)
+ X = Builder.CreateZExt(X, Ty);
// (X + Mask) >> ShiftAmt
Value *Add = Builder.CreateNUWAdd(X, MaskC);
return BinaryOperator::CreateLShr(
- Add, ConstantInt::get(X->getType(), *ShiftAmt));
+ Add, ConstantInt::get(Ty, ShiftAmt->zext(Ibits)));
}
}
}
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 1b84ecaf5eeeb..22472b0114fd7 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -4992,6 +4992,22 @@ define i32 @ceil_div_by_8_known_range(i32 range(i32 0, 100) %x) {
ret i32 %r
}
+define i32 @ceil_div_by_8_zext(i8 %x) {
+; CHECK-LABEL: @ceil_div_by_8_zext(
+; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i32 [[TMP1]], 7
+; CHECK-NEXT: [[R:%.*]] = lshr i32 [[TMP2]], 3
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %shr = lshr i8 %x, 3
+ %zext = zext i8 %shr to i32
+ %and = and i8 %x, 7
+ %cmp = icmp ne i8 %and, 0
+ %ext = zext i1 %cmp to i32
+ %r = add i32 %zext, %ext
+ ret i32 %r
+}
+
; Test with the exact IR from the original testcase
define i32 @ceil_div_from_clz(i32 %v) {
; CHECK-LABEL: @ceil_div_from_clz(
@@ -5154,6 +5170,33 @@ define i32 @ceil_div_multi_use(i32 range(i32 0, 100) %x) {
ret i32 %r
}
+define i32 @ceil_div_by_8_zext_multi_use(i8 %x) {
+; CHECK-LABEL: @ceil_div_by_8_zext_multi_use(
+; CHECK-NEXT: [[SHR:%.*]] = lshr i8 [[X:%.*]], 3
+; CHECK-NEXT: call void @use_i8(i8 [[SHR]])
+; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[SHR]] to i32
+; CHECK-NEXT: call void @use_i32(i32 [[ZEXT]])
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], 7
+; CHECK-NEXT: call void @use_i8(i8 [[AND]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[AND]], 0
+; CHECK-NEXT: [[EXT:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT: call void @use_i32(i32 [[EXT]])
+; CHECK-NEXT: [[R:%.*]] = add nuw nsw i32 [[ZEXT]], [[EXT]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %shr = lshr i8 %x, 3
+ call void @use_i8(i8 %shr)
+ %zext = zext i8 %shr to i32
+ call void @use_i32(i32 %zext)
+ %and = and i8 %x, 7
+ call void @use_i8(i8 %and)
+ %cmp = icmp ne i8 %and, 0
+ %ext = zext i1 %cmp to i32
+ call void @use_i32(i32 %ext)
+ %r = add i32 %zext, %ext
+ ret i32 %r
+}
+
; Commuted test: add operands are swapped
define i32 @ceil_div_commuted(i32 range(i32 0, 100) %x) {
; CHECK-LABEL: @ceil_div_commuted(
@@ -5231,6 +5274,7 @@ define <2 x i32> @ceil_div_vec_multi_use(<2 x i32> range(i32 0, 1000) %x) {
ret <2 x i32> %r
}
+declare void @use_i8(i8)
declare void @use_i32(i32)
declare void @use_vec(<2 x i32>)
declare void @fake_func(i32)
More information about the llvm-commits
mailing list