Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions llvm/include/llvm/IR/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,14 @@ m_NSWAdd(const LHS &L, const RHS &R) {
R);
}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
OverflowingBinaryOperator::NoSignedWrap, true>
m_c_NSWAdd(const LHS &L, const RHS &R) {
return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
OverflowingBinaryOperator::NoSignedWrap,
true>(L, R);
}
template <typename LHS, typename RHS>
inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
OverflowingBinaryOperator::NoSignedWrap>
m_NSWSub(const LHS &L, const RHS &R) {
Expand Down
38 changes: 38 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2807,6 +2807,44 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
if (Instruction *Res = foldBinOpOfSelectAndCastOfSelectCondition(I))
return Res;

// (sub (sext (add nsw (X, Y)), sext (X))) --> (sext (Y))
if (match(Op1, m_SExt(m_Value(X))) &&
match(Op0, m_SExt(m_c_NSWAdd(m_Specific(X), m_Value(Y))))) {
Value *SExtY = Builder.CreateSExt(Y, I.getType());
return replaceInstUsesWith(I, SExtY);
}

// (sub[ nsw] (sext (add nsw (X, Y)), sext (add nsw (X, Z)))) -->
// --> (sub[ nsw] (sext (Y), sext(Z)))
{
Value *Z, *Add0, *Add1;
if (match(Op0, m_SExt(m_Value(Add0))) &&
match(Op1, m_SExt(m_Value(Add1))) &&
((match(Add0, m_NSWAdd(m_Value(X), m_Value(Y))) &&
match(Add1, m_c_NSWAdd(m_Specific(X), m_Value(Z)))) ||
(match(Add0, m_NSWAdd(m_Value(Y), m_Value(X))) &&
match(Add1, m_c_NSWAdd(m_Specific(X), m_Value(Z)))))) {
unsigned NumOfNewInstrs = 0;
// Non-constant Y, Z require new SExt.
NumOfNewInstrs += !isa<Constant>(Y) ? 1 : 0;
NumOfNewInstrs += !isa<Constant>(Z) ? 1 : 0;
// Check if we can trade some of the old instructions for the new ones.
unsigned NumOfDeadInstrs = 0;
NumOfDeadInstrs += Op0->hasOneUse() ? 1 : 0;
NumOfDeadInstrs += Op1->hasOneUse() ? 1 : 0;
NumOfDeadInstrs += Add0->hasOneUse() ? 1 : 0;
NumOfDeadInstrs += Add1->hasOneUse() ? 1 : 0;
if (NumOfDeadInstrs >= NumOfNewInstrs) {
Value *SExtY = Builder.CreateSExt(Y, I.getType());
Value *SExtZ = Builder.CreateSExt(Z, I.getType());
Value *Sub = Builder.CreateSub(SExtY, SExtZ, "",
/* HasNUW */ false,
/* HasNSW */ I.hasNoSignedWrap());
return replaceInstUsesWith(I, Sub);
}
}
}

return TryToNarrowDeduceFlags();
}

Expand Down
140 changes: 140 additions & 0 deletions llvm/test/Transforms/InstCombine/sub-sext-add.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

define i64 @src_2add_2sext_sub_1(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_1(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%add2 = add nsw i32 %x, %z
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_2add_2sext_sub_2(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_2(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%add2 = add nsw i32 %z, %x
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_2add_2sext_sub_3(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_3(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %y, %x
%add2 = add nsw i32 %z, %x
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_2add_2sext_sub_4(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_4(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %y, %x
%add2 = add nsw i32 %x, %z
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_2add_2sext_sub_nsw(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_nsw(
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%add2 = add nsw i32 %x, %z
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub nsw i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_2add_2sext_sub_nuw(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @src_2add_2sext_sub_nuw(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%add2 = add nsw i32 %x, %z
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %add2 to i64
%sub = sub nuw i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_x_add_2sext_sub_1(i32 %x, i32 %y) {
; CHECK-LABEL: @src_x_add_2sext_sub_1(
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %x to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_x_add_2sext_sub_2(i32 %x, i32 %y) {
; CHECK-LABEL: @src_x_add_2sext_sub_2(
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %y, %x
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %x to i64
%sub = sub i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_x_add_2sext_sub_nsw(i32 %x, i32 %y) {
; CHECK-LABEL: @src_x_add_2sext_sub_nsw(
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %x to i64
%sub = sub nsw i64 %sext1, %sext2
ret i64 %sub
}

define i64 @src_x_add_2sext_sub_nuw(i32 %x, i32 %y) {
; CHECK-LABEL: @src_x_add_2sext_sub_nuw(
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
; CHECK-NEXT: ret i64 [[SUB]]
;
%add1 = add nsw i32 %x, %y
%sext1 = sext i32 %add1 to i64
%sext2 = sext i32 %x to i64
%sub = sub nuw i64 %sext1, %sext2
ret i64 %sub
}