Skip to content

Commit

Permalink
[InstCombine] Add select simplifications
Browse files Browse the repository at this point in the history
In these cases, two selects have constant selectable operands for
both the true and false components and have the same conditional
expression.
We then create two arithmetic operations of the same type and feed a
final select operation using the result of the true arithmetic for the true
operand and the result of the false arithmetic for the false operand and reuse
the original conditionl expression.
The arithmetic operations are naturally folded as a consequence, leaving
only the newly formed select to replace the old arithmetic operation.

Patch by: Michael Berg <michael_c_berg@apple.com>
Differential Revision: https://reviews.llvm.org/D37019

llvm-svn: 313774
  • Loading branch information
Quentin Colombet committed Sep 20, 2017
1 parent d0320d5 commit aa103b3
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 52 deletions.
31 changes: 7 additions & 24 deletions llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
Expand Up @@ -1387,30 +1387,9 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
}
}

// select C, 0, B + select C, A, 0 -> select C, A, B
{
Value *A1, *B1, *C1, *A2, *B2, *C2;
if (match(LHS, m_Select(m_Value(C1), m_Value(A1), m_Value(B1))) &&
match(RHS, m_Select(m_Value(C2), m_Value(A2), m_Value(B2)))) {
if (C1 == C2) {
Constant *Z1=nullptr, *Z2=nullptr;
Value *A, *B, *C=C1;
if (match(A1, m_AnyZero()) && match(B2, m_AnyZero())) {
Z1 = dyn_cast<Constant>(A1); A = A2;
Z2 = dyn_cast<Constant>(B2); B = B1;
} else if (match(B1, m_AnyZero()) && match(A2, m_AnyZero())) {
Z1 = dyn_cast<Constant>(B1); B = B2;
Z2 = dyn_cast<Constant>(A2); A = A1;
}

if (Z1 && Z2 &&
(I.hasNoSignedZeros() ||
(Z1->isNegativeZeroValue() && Z2->isNegativeZeroValue()))) {
return SelectInst::Create(C, A, B);
}
}
}
}
// Handle specials cases for FAdd with selects feeding the operation
if (Value *V = SimplifySelectsFeedingBinaryOp(I, LHS, RHS))
return replaceInstUsesWith(I, V);

if (I.hasUnsafeAlgebra()) {
if (Value *V = FAddCombine(Builder).simplify(&I))
Expand Down Expand Up @@ -1760,6 +1739,10 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) {
}
}

// Handle specials cases for FSub with selects feeding the operation
if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1))
return replaceInstUsesWith(I, V);

if (I.hasUnsafeAlgebra()) {
if (Value *V = FAddCombine(Builder).simplify(&I))
return replaceInstUsesWith(I, V);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Expand Up @@ -600,6 +600,11 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
/// value, or null if it didn't simplify.
Value *SimplifyUsingDistributiveLaws(BinaryOperator &I);

// Binary Op helper for select operations where the expression can be
// efficiently reorganized.
Value *SimplifySelectsFeedingBinaryOp(BinaryOperator &I, Value *LHS,
Value *RHS);

/// This tries to simplify binary operations by factorizing out common terms
/// (e. g. "(A*B)+(A*C)" -> "A*(B+C)").
Value *tryFactorization(BinaryOperator &, Instruction::BinaryOps, Value *,
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
Expand Up @@ -736,6 +736,10 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
}
}

// Handle specials cases for FMul with selects feeding the operation
if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1))
return replaceInstUsesWith(I, V);

// (X*Y) * X => (X*X) * Y where Y != X
// The purpose is two-fold:
// 1) to form a power expression (of X).
Expand Down
56 changes: 28 additions & 28 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Expand Up @@ -719,36 +719,36 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) {
}
}

// (op (select (a, c, b)), (select (a, d, b))) -> (select (a, (op c, d), 0))
// (op (select (a, b, c)), (select (a, b, d))) -> (select (a, 0, (op c, d)))
if (auto *SI0 = dyn_cast<SelectInst>(LHS)) {
if (auto *SI1 = dyn_cast<SelectInst>(RHS)) {
if (SI0->getCondition() == SI1->getCondition()) {
Value *SI = nullptr;
if (Value *V =
SimplifyBinOp(TopLevelOpcode, SI0->getFalseValue(),
SI1->getFalseValue(), SQ.getWithInstruction(&I)))
SI = Builder.CreateSelect(SI0->getCondition(),
Builder.CreateBinOp(TopLevelOpcode,
SI0->getTrueValue(),
SI1->getTrueValue()),
V);
if (Value *V =
SimplifyBinOp(TopLevelOpcode, SI0->getTrueValue(),
SI1->getTrueValue(), SQ.getWithInstruction(&I)))
SI = Builder.CreateSelect(
SI0->getCondition(), V,
Builder.CreateBinOp(TopLevelOpcode, SI0->getFalseValue(),
SI1->getFalseValue()));
if (SI) {
SI->takeName(&I);
return SI;
}
}
}
return SimplifySelectsFeedingBinaryOp(I, LHS, RHS);
}

Value *InstCombiner::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
Value *LHS, Value *RHS) {
Instruction::BinaryOps Opcode = I.getOpcode();
// (op (select (a, b, c)), (select (a, d, e))) -> (select (a, (op b, d), (op
// c, e)))
Value *A, *B, *C, *D, *E;
Value *SI = nullptr;
if (match(LHS, m_Select(m_Value(A), m_Value(B), m_Value(C))) &&
match(RHS, m_Select(m_Specific(A), m_Value(D), m_Value(E)))) {
BuilderTy::FastMathFlagGuard Guard(Builder);
if (isa<FPMathOperator>(&I))
Builder.setFastMathFlags(I.getFastMathFlags());

Value *V1 = SimplifyBinOp(Opcode, C, E, SQ.getWithInstruction(&I));
Value *V2 = SimplifyBinOp(Opcode, B, D, SQ.getWithInstruction(&I));
if (V1 && V2)
SI = Builder.CreateSelect(A, V2, V1);
else if (V2)
SI = Builder.CreateSelect(A, V2, Builder.CreateBinOp(Opcode, C, E));
else if (V1)
SI = Builder.CreateSelect(A, Builder.CreateBinOp(Opcode, B, D), V1);

if (SI)
SI->takeName(&I);
}

return nullptr;
return SI;
}

/// Given a 'sub' instruction, return the RHS of the instruction if the LHS is a
Expand Down
40 changes: 40 additions & 0 deletions llvm/test/Transforms/InstCombine/select_arithmetic.ll
@@ -0,0 +1,40 @@
; RUN: opt < %s -instcombine -S | FileCheck %s

target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"

; Tests folding constants from two similar selects that feed a add
define float @test1(i1 zeroext %arg) #0 {
%tmp = select i1 %arg, float 5.000000e+00, float 6.000000e+00
%tmp1 = select i1 %arg, float 1.000000e+00, float 9.000000e+00
%tmp2 = fadd float %tmp, %tmp1
ret float %tmp2
; CHECK-LABEL: @test1(
; CHECK: %tmp2 = select i1 %arg, float 6.000000e+00, float 1.500000e+01
; CHECK-NOT: fadd
; CHECK: ret float %tmp2
}

; Tests folding constants from two similar selects that feed a sub
define float @test2(i1 zeroext %arg) #0 {
%tmp = select i1 %arg, float 5.000000e+00, float 6.000000e+00
%tmp1 = select i1 %arg, float 1.000000e+00, float 9.000000e+00
%tmp2 = fsub float %tmp, %tmp1
ret float %tmp2
; CHECK-LABEL: @test2(
; CHECK: %tmp2 = select i1 %arg, float 4.000000e+00, float -3.000000e+00
; CHECK-NOT: fsub
; CHECK: ret float %tmp2
}

; Tests folding constants from two similar selects that feed a mul
define float @test3(i1 zeroext %arg) #0 {
%tmp = select i1 %arg, float 5.000000e+00, float 6.000000e+00
%tmp1 = select i1 %arg, float 1.000000e+00, float 9.000000e+00
%tmp2 = fmul float %tmp, %tmp1
ret float %tmp2
; CHECK-LABEL: @test3(
; CHECK: %tmp2 = select i1 %arg, float 5.000000e+00, float 5.400000e+01
; CHECK-NOT: fmul
; CHECK: ret float %tmp2
}

0 comments on commit aa103b3

Please sign in to comment.