[InstCombine] Optimize subtract of selects into a select of a sub

This came up when examining some code generated by clang's IRGen for
certain member pointers.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240369 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2015-06-23 02:49:24 +00:00
parent 393bbf5c86
commit 3f2dc2455d
2 changed files with 48 additions and 0 deletions

View File

@ -1611,6 +1611,32 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
return BinaryOperator::CreateAnd(A, B);
}
// (sub (select (a, c, b)), (select (a, d, b))) -> (select (a, (sub c, d), 0))
// (sub (select (a, b, c)), (select (a, b, d))) -> (select (a, 0, (sub c, d)))
if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
if (auto *SI1 = dyn_cast<SelectInst>(Op1)) {
if (SI0->getCondition() == SI1->getCondition()) {
if (Value *V = SimplifySubInst(
SI0->getFalseValue(), SI1->getFalseValue(), I.hasNoSignedWrap(),
I.hasNoUnsignedWrap(), DL, TLI, DT, AC))
return SelectInst::Create(
SI0->getCondition(),
Builder->CreateSub(SI0->getTrueValue(), SI1->getTrueValue(), "",
/*HasNUW=*/I.hasNoUnsignedWrap(),
/*HasNSW=*/I.hasNoSignedWrap()),
V);
if (Value *V = SimplifySubInst(SI0->getTrueValue(), SI1->getTrueValue(),
I.hasNoSignedWrap(),
I.hasNoUnsignedWrap(), DL, TLI, DT, AC))
return SelectInst::Create(
SI0->getCondition(), V,
Builder->CreateSub(SI0->getFalseValue(), SI1->getFalseValue(), "",
/*HasNUW=*/I.hasNoUnsignedWrap(),
/*HasNSW=*/I.hasNoSignedWrap()));
}
}
}
if (Op0->hasOneUse()) {
Value *Y = nullptr;
// ((X | Y) - X) --> (~X & Y)

View File

@ -550,3 +550,25 @@ define i32 @test46(i32 %x, i32 %y) {
; CHECK-NEXT: %sub = and i32 %y, %x.not
; CHECK: ret i32 %sub
}
define i32 @test47(i1 %A, i32 %B, i32 %C, i32 %D) {
%sel0 = select i1 %A, i32 %D, i32 %B
%sel1 = select i1 %A, i32 %C, i32 %B
%sub = sub i32 %sel0, %sel1
ret i32 %sub
; CHECK-LABEL: @test47(
; CHECK-NEXT: %[[sub:.*]] = sub i32 %D, %C
; CHECK-NEXT: %[[sel:.*]] = select i1 %A, i32 %[[sub]], i32 0
; CHECK-NEXT: ret i32 %[[sel]]
}
define i32 @test48(i1 %A, i32 %B, i32 %C, i32 %D) {
%sel0 = select i1 %A, i32 %B, i32 %D
%sel1 = select i1 %A, i32 %B, i32 %C
%sub = sub i32 %sel0, %sel1
ret i32 %sub
; CHECK-LABEL: @test48(
; CHECK-NEXT: %[[sub:.*]] = sub i32 %D, %C
; CHECK-NEXT: %[[sel:.*]] = select i1 %A, i32 0, i32 %[[sub]]
; CHECK-NEXT: ret i32 %[[sel]]
}