[llvm] goldsteinn/nwaddlike (PR #86082)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 20 22:05:40 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: None (goldsteinn)
<details>
<summary>Changes</summary>
- **[IR] Add helpers for `NUWAddLike` and `NSWAddLike` to also match `or disjoint`; NFC**
- **[InstCombine] Add tests for integrating `N{U,S}WAddLike`; NFC**
- **[InstCombine] integrate `N{U,S}WAddLike` into existing folds**
---
Full diff: https://github.com/llvm/llvm-project/pull/86082.diff
10 Files Affected:
- (modified) llvm/include/llvm/IR/PatternMatch.h (+22)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp (+5-3)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+3-2)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (+4-4)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp (+1-1)
- (modified) llvm/test/Transforms/InstCombine/add.ll (+76)
- (modified) llvm/test/Transforms/InstCombine/div.ll (+22)
- (modified) llvm/test/Transforms/InstCombine/sadd-with-overflow.ll (+32)
- (modified) llvm/test/Transforms/InstCombine/shift-add.ll (+29)
- (modified) llvm/test/Transforms/InstCombine/uadd-with-overflow.ll (+23)
``````````diff
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 382009d9df785d..3e298eff9b56ea 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -1202,6 +1202,7 @@ m_NSWAdd(const LHS &L, const RHS &R) {
OverflowingBinaryOperator::NoSignedWrap>(L,
R);
}
+
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
OverflowingBinaryOperator::NoSignedWrap>
@@ -1235,6 +1236,7 @@ m_NUWAdd(const LHS &L, const RHS &R) {
OverflowingBinaryOperator::NoUnsignedWrap>(
L, R);
}
+
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
OverflowingBinaryOperator::NoUnsignedWrap>
@@ -1319,6 +1321,26 @@ m_AddLike(const LHS &L, const RHS &R) {
return m_CombineOr(m_Add(L, R), m_DisjointOr(L, R));
}
+/// Match either "add nsw" or "or disjoint"
+template <typename LHS, typename RHS>
+inline match_combine_or<
+ OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoSignedWrap>,
+ DisjointOr_match<LHS, RHS>>
+m_NSWAddLike(const LHS &L, const RHS &R) {
+ return m_CombineOr(m_NSWAdd(L, R), m_DisjointOr(L, R));
+}
+
+/// Match either "add nuw" or "or disjoint"
+template <typename LHS, typename RHS>
+inline match_combine_or<
+ OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
+ OverflowingBinaryOperator::NoUnsignedWrap>,
+ DisjointOr_match<LHS, RHS>>
+m_NUWAddLike(const LHS &L, const RHS &R) {
+ return m_CombineOr(m_NUWAdd(L, R), m_DisjointOr(L, R));
+}
+
//===----------------------------------------------------------------------===//
// Class that matches a group of binary opcodes.
//
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index aaf7184a5562cd..a978e9a643f5e9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -819,7 +819,7 @@ static Instruction *foldNoWrapAdd(BinaryOperator &Add,
Value *X;
const APInt *C1, *C2;
if (match(Op1, m_APInt(C1)) &&
- match(Op0, m_OneUse(m_ZExt(m_NUWAdd(m_Value(X), m_APInt(C2))))) &&
+ match(Op0, m_OneUse(m_ZExt(m_NUWAddLike(m_Value(X), m_APInt(C2))))) &&
C1->isNegative() && C1->sge(-C2->sext(C1->getBitWidth()))) {
Constant *NewC =
ConstantInt::get(X->getType(), *C2 + C1->trunc(C2->getBitWidth()));
@@ -829,14 +829,16 @@ static Instruction *foldNoWrapAdd(BinaryOperator &Add,
// More general combining of constants in the wide type.
// (sext (X +nsw NarrowC)) + C --> (sext X) + (sext(NarrowC) + C)
Constant *NarrowC;
- if (match(Op0, m_OneUse(m_SExt(m_NSWAdd(m_Value(X), m_Constant(NarrowC)))))) {
+ if (match(Op0,
+ m_OneUse(m_SExt(m_NSWAddLike(m_Value(X), m_Constant(NarrowC)))))) {
Value *WideC = Builder.CreateSExt(NarrowC, Ty);
Value *NewC = Builder.CreateAdd(WideC, Op1C);
Value *WideX = Builder.CreateSExt(X, Ty);
return BinaryOperator::CreateAdd(WideX, NewC);
}
// (zext (X +nuw NarrowC)) + C --> (zext X) + (zext(NarrowC) + C)
- if (match(Op0, m_OneUse(m_ZExt(m_NUWAdd(m_Value(X), m_Constant(NarrowC)))))) {
+ if (match(Op0,
+ m_OneUse(m_ZExt(m_NUWAddLike(m_Value(X), m_Constant(NarrowC)))))) {
Value *WideC = Builder.CreateZExt(NarrowC, Ty);
Value *NewC = Builder.CreateAdd(WideC, Op1C);
Value *WideX = Builder.CreateZExt(X, Ty);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 426b548c074adf..526fe5d080599f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2093,8 +2093,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
Value *Arg0 = II->getArgOperand(0);
Value *Arg1 = II->getArgOperand(1);
bool IsSigned = IID == Intrinsic::sadd_with_overflow;
- bool HasNWAdd = IsSigned ? match(Arg0, m_NSWAdd(m_Value(X), m_APInt(C0)))
- : match(Arg0, m_NUWAdd(m_Value(X), m_APInt(C0)));
+ bool HasNWAdd = IsSigned
+ ? match(Arg0, m_NSWAddLike(m_Value(X), m_APInt(C0)))
+ : match(Arg0, m_NUWAddLike(m_Value(X), m_APInt(C0)));
if (HasNWAdd && match(Arg1, m_APInt(C1))) {
bool Overflow;
APInt NewC =
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 9d4c271f990d19..345feeedc2707c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1160,14 +1160,14 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
// We need a multiple of the divisor for a signed add constant, but
// unsigned is fine with any constant pair.
if (IsSigned &&
- match(Op0, m_NSWAdd(m_NSWMul(m_Value(X), m_SpecificInt(*C2)),
- m_APInt(C1))) &&
+ match(Op0, m_NSWAddLike(m_NSWMul(m_Value(X), m_SpecificInt(*C2)),
+ m_APInt(C1))) &&
isMultiple(*C1, *C2, Quotient, IsSigned)) {
return BinaryOperator::CreateNSWAdd(X, ConstantInt::get(Ty, Quotient));
}
if (!IsSigned &&
- match(Op0, m_NUWAdd(m_NUWMul(m_Value(X), m_SpecificInt(*C2)),
- m_APInt(C1)))) {
+ match(Op0, m_NUWAddLike(m_NUWMul(m_Value(X), m_SpecificInt(*C2)),
+ m_APInt(C1)))) {
return BinaryOperator::CreateNUWAdd(X,
ConstantInt::get(Ty, C1->udiv(*C2)));
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index eafd2889ec50bd..95aa2119e2d88b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -437,7 +437,7 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
Value *A;
Constant *C, *C1;
if (match(Op0, m_Constant(C)) &&
- match(Op1, m_NUWAdd(m_Value(A), m_Constant(C1)))) {
+ match(Op1, m_NUWAddLike(m_Value(A), m_Constant(C1)))) {
Value *NewC = Builder.CreateBinOp(I.getOpcode(), C, C1);
BinaryOperator *NewShiftOp = BinaryOperator::Create(I.getOpcode(), NewC, A);
if (I.getOpcode() == Instruction::Shl) {
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 522dcf8db27f42..ec3aca26514caf 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -3986,5 +3986,81 @@ define i32 @add_reduce_sqr_sum_varC_invalid2(i32 %a, i32 %b) {
ret i32 %ab2
}
+define i32 @fold_sext_addition_or_disjoint(i8 %x) {
+; CHECK-LABEL: @fold_sext_addition_or_disjoint(
+; CHECK-NEXT: [[SE:%.*]] = sext i8 [[XX:%.*]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[SE]], 1246
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %xx = or disjoint i8 %x, 12
+ %se = sext i8 %xx to i32
+ %r = add i32 %se, 1234
+ ret i32 %r
+}
+
+define i32 @fold_sext_addition_fail(i8 %x) {
+; CHECK-LABEL: @fold_sext_addition_fail(
+; CHECK-NEXT: [[XX:%.*]] = or i8 [[X:%.*]], 12
+; CHECK-NEXT: [[SE:%.*]] = sext i8 [[XX]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[SE]], 1234
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %xx = or i8 %x, 12
+ %se = sext i8 %xx to i32
+ %r = add i32 %se, 1234
+ ret i32 %r
+}
+
+define i32 @fold_zext_addition_or_disjoint(i8 %x) {
+; CHECK-LABEL: @fold_zext_addition_or_disjoint(
+; CHECK-NEXT: [[SE:%.*]] = zext i8 [[XX:%.*]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nuw nsw i32 [[SE]], 1246
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %xx = or disjoint i8 %x, 12
+ %se = zext i8 %xx to i32
+ %r = add i32 %se, 1234
+ ret i32 %r
+}
+
+define i32 @fold_zext_addition_or_disjoint2(i8 %x) {
+; CHECK-LABEL: @fold_zext_addition_or_disjoint2(
+; CHECK-NEXT: [[XX:%.*]] = add nuw i8 [[X:%.*]], 4
+; CHECK-NEXT: [[SE:%.*]] = zext i8 [[XX]] to i32
+; CHECK-NEXT: ret i32 [[SE]]
+;
+ %xx = or disjoint i8 %x, 18
+ %se = zext i8 %xx to i32
+ %r = add i32 %se, -14
+ ret i32 %r
+}
+
+define i32 @fold_zext_addition_fail(i8 %x) {
+; CHECK-LABEL: @fold_zext_addition_fail(
+; CHECK-NEXT: [[XX:%.*]] = or i8 [[X:%.*]], 12
+; CHECK-NEXT: [[SE:%.*]] = zext i8 [[XX]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nuw nsw i32 [[SE]], 1234
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %xx = or i8 %x, 12
+ %se = zext i8 %xx to i32
+ %r = add i32 %se, 1234
+ ret i32 %r
+}
+
+define i32 @fold_zext_addition_fail2(i8 %x) {
+; CHECK-LABEL: @fold_zext_addition_fail2(
+; CHECK-NEXT: [[XX:%.*]] = or i8 [[X:%.*]], 18
+; CHECK-NEXT: [[SE:%.*]] = zext i8 [[XX]] to i32
+; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[SE]], -14
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %xx = or i8 %x, 18
+ %se = zext i8 %xx to i32
+ %r = add i32 %se, -14
+ ret i32 %r
+}
+
+
declare void @llvm.assume(i1)
declare void @fake_func(i32)
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 1309dee817cf65..e8a25ff44d0296 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1810,3 +1810,25 @@ define i6 @udiv_distribute_mul_nsw_add_nuw(i6 %x) {
%div = udiv i6 %add, 3
ret i6 %div
}
+
+define i32 @fold_disjoint_or_over_sdiv(i32 %x) {
+; CHECK-LABEL: @fold_disjoint_or_over_sdiv(
+; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[X:%.*]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %mul = mul nsw i32 %x, 9
+ %or = or disjoint i32 %mul, 81
+ %r = sdiv i32 %or, 9
+ ret i32 %r
+}
+
+define i32 @fold_disjoint_or_over_udiv(i32 %x) {
+; CHECK-LABEL: @fold_disjoint_or_over_udiv(
+; CHECK-NEXT: [[R:%.*]] = add nuw i32 [[X:%.*]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %mul = mul nuw i32 %x, 9
+ %or = or disjoint i32 %mul, 81
+ %r = udiv i32 %or, 9
+ ret i32 %r
+}
diff --git a/llvm/test/Transforms/InstCombine/sadd-with-overflow.ll b/llvm/test/Transforms/InstCombine/sadd-with-overflow.ll
index 4b37ccbe3370b6..729ca03ddfd150 100644
--- a/llvm/test/Transforms/InstCombine/sadd-with-overflow.ll
+++ b/llvm/test/Transforms/InstCombine/sadd-with-overflow.ll
@@ -122,3 +122,35 @@ define { i32, i1 } @fold_sub_simple(i32 %x) {
%b = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 30)
ret { i32, i1 } %b
}
+
+define { i32, i1 } @fold_with_distjoin_or(i32 %x) {
+; CHECK-LABEL: @fold_with_distjoin_or(
+; CHECK-NEXT: [[B:%.*]] = add i32 [[X:%.*]], 6
+; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 poison, i1 false }, i32 [[B]], 0
+; CHECK-NEXT: ret { i32, i1 } [[TMP1]]
+;
+ %a = or disjoint i32 %x, 13
+ %b = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 -7)
+ ret { i32, i1 } %b
+}
+
+define { i32, i1 } @fold_with_disjoint_or2(i32 %x) {
+; CHECK-LABEL: @fold_with_disjoint_or2(
+; CHECK-NEXT: [[B:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X:%.*]], i32 127)
+; CHECK-NEXT: ret { i32, i1 } [[B]]
+;
+ %a = or disjoint i32 %x, 100
+ %b = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 27)
+ ret { i32, i1 } %b
+}
+
+define { i32, i1 } @fold_with_or_fail(i32 %x) {
+; CHECK-LABEL: @fold_with_or_fail(
+; CHECK-NEXT: [[A:%.*]] = or i32 [[X:%.*]], 100
+; CHECK-NEXT: [[B:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[A]], i32 27)
+; CHECK-NEXT: ret { i32, i1 } [[B]]
+;
+ %a = or i32 %x, 100
+ %b = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 27)
+ ret { i32, i1 } %b
+}
diff --git a/llvm/test/Transforms/InstCombine/shift-add.ll b/llvm/test/Transforms/InstCombine/shift-add.ll
index 1b25675059930b..aa3a238e0949ce 100644
--- a/llvm/test/Transforms/InstCombine/shift-add.ll
+++ b/llvm/test/Transforms/InstCombine/shift-add.ll
@@ -775,3 +775,32 @@ define <3 x i32> @add3_i96(<3 x i32> %0, <3 x i32> %1) {
%25 = insertelement <3 x i32> %24, i32 %20, i32 2
ret <3 x i32> %25
}
+
+define i8 @shl_fold_or_disjoint_cnt(i8 %x) {
+; CHECK-LABEL: @shl_fold_or_disjoint_cnt(
+; CHECK-NEXT: [[R:%.*]] = shl i8 16, [[X:%.*]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %a = or disjoint i8 %x, 3
+ %r = shl i8 2, %a
+ ret i8 %r
+}
+
+define <2 x i8> @ashr_fold_or_disjoint_cnt(<2 x i8> %x) {
+; CHECK-LABEL: @ashr_fold_or_disjoint_cnt(
+; CHECK-NEXT: [[R:%.*]] = lshr <2 x i8> <i8 0, i8 1>, [[X:%.*]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %a = or disjoint <2 x i8> %x, <i8 3, i8 1>
+ %r = ashr <2 x i8> <i8 2, i8 3>, %a
+ ret <2 x i8> %r
+}
+
+define <2 x i8> @lshr_fold_or_disjoint_cnt_out_of_bounds(<2 x i8> %x) {
+; CHECK-LABEL: @lshr_fold_or_disjoint_cnt_out_of_bounds(
+; CHECK-NEXT: ret <2 x i8> zeroinitializer
+;
+ %a = or disjoint <2 x i8> %x, <i8 3, i8 8>
+ %r = lshr <2 x i8> <i8 2, i8 3>, %a
+ ret <2 x i8> %r
+}
diff --git a/llvm/test/Transforms/InstCombine/uadd-with-overflow.ll b/llvm/test/Transforms/InstCombine/uadd-with-overflow.ll
index 28d309baaa41d3..fd5d38bb38ddc7 100644
--- a/llvm/test/Transforms/InstCombine/uadd-with-overflow.ll
+++ b/llvm/test/Transforms/InstCombine/uadd-with-overflow.ll
@@ -124,3 +124,26 @@ define { i32, i1 } @no_fold_wrapped_add(i32 %x) {
%b = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 30, i32 %a)
ret { i32, i1 } %b
}
+
+
+define { <2 x i32>, <2 x i1> } @fold_simple_splat_with_disjoint_or_constant(<2 x i32> %x) {
+; CHECK-LABEL: @fold_simple_splat_with_disjoint_or_constant(
+; CHECK-NEXT: [[B:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[X:%.*]], <2 x i32> <i32 42, i32 42>)
+; CHECK-NEXT: ret { <2 x i32>, <2 x i1> } [[B]]
+;
+ %a = or disjoint <2 x i32> %x, <i32 12, i32 12>
+ %b = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+ ret { <2 x i32>, <2 x i1> } %b
+}
+
+
+define { <2 x i32>, <2 x i1> } @fold_simple_splat_constant_with_or_fail(<2 x i32> %x) {
+; CHECK-LABEL: @fold_simple_splat_constant_with_or_fail(
+; CHECK-NEXT: [[A:%.*]] = or <2 x i32> [[X:%.*]], <i32 12, i32 12>
+; CHECK-NEXT: [[B:%.*]] = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[A]], <2 x i32> <i32 30, i32 30>)
+; CHECK-NEXT: ret { <2 x i32>, <2 x i1> } [[B]]
+;
+ %a = or <2 x i32> %x, <i32 12, i32 12>
+ %b = tail call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 30, i32 30>)
+ ret { <2 x i32>, <2 x i1> } %b
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/86082
More information about the llvm-commits
mailing list