mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-07 21:20:18 +00:00
New instcombine rule: max(~a,~b) -> ~min(a, b)
This case is interesting because ScalarEvolutionExpander lowers min(a, b) as ~max(~a,~b). I think the profitability heuristics can be made more clever/aggressive, but this is a start. Differential Revision: http://reviews.llvm.org/D7821 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230285 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8d16a81c33
commit
f922d9cfe4
@ -22,30 +22,12 @@ using namespace PatternMatch;
|
|||||||
|
|
||||||
#define DEBUG_TYPE "instcombine"
|
#define DEBUG_TYPE "instcombine"
|
||||||
|
|
||||||
/// isFreeToInvert - Return true if the specified value is free to invert (apply
|
|
||||||
/// ~ to). This happens in cases where the ~ can be eliminated.
|
|
||||||
static inline bool isFreeToInvert(Value *V) {
|
|
||||||
// ~(~(X)) -> X.
|
|
||||||
if (BinaryOperator::isNot(V))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Constants can be considered to be not'ed values.
|
|
||||||
if (isa<ConstantInt>(V))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Compares can be inverted if they have a single use.
|
|
||||||
if (CmpInst *CI = dyn_cast<CmpInst>(V))
|
|
||||||
return CI->hasOneUse();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Value *dyn_castNotVal(Value *V) {
|
static inline Value *dyn_castNotVal(Value *V) {
|
||||||
// If this is not(not(x)) don't return that this is a not: we want the two
|
// If this is not(not(x)) don't return that this is a not: we want the two
|
||||||
// not's to be folded first.
|
// not's to be folded first.
|
||||||
if (BinaryOperator::isNot(V)) {
|
if (BinaryOperator::isNot(V)) {
|
||||||
Value *Operand = BinaryOperator::getNotArgument(V);
|
Value *Operand = BinaryOperator::getNotArgument(V);
|
||||||
if (!isFreeToInvert(Operand))
|
if (!IsFreeToInvert(Operand, Operand->hasOneUse()))
|
||||||
return Operand;
|
return Operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2585,8 +2567,10 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
|
|||||||
|
|
||||||
// ~(X & Y) --> (~X | ~Y) - De Morgan's Law
|
// ~(X & Y) --> (~X | ~Y) - De Morgan's Law
|
||||||
// ~(X | Y) === (~X & ~Y) - De Morgan's Law
|
// ~(X | Y) === (~X & ~Y) - De Morgan's Law
|
||||||
if (isFreeToInvert(Op0I->getOperand(0)) &&
|
if (IsFreeToInvert(Op0I->getOperand(0),
|
||||||
isFreeToInvert(Op0I->getOperand(1))) {
|
Op0I->getOperand(0)->hasOneUse()) &&
|
||||||
|
IsFreeToInvert(Op0I->getOperand(1),
|
||||||
|
Op0I->getOperand(1)->hasOneUse())) {
|
||||||
Value *NotX =
|
Value *NotX =
|
||||||
Builder->CreateNot(Op0I->getOperand(0), "notlhs");
|
Builder->CreateNot(Op0I->getOperand(0), "notlhs");
|
||||||
Value *NotY =
|
Value *NotY =
|
||||||
|
@ -80,6 +80,36 @@ static inline Constant *SubOne(Constant *C) {
|
|||||||
return ConstantExpr::getSub(C, ConstantInt::get(C->getType(), 1));
|
return ConstantExpr::getSub(C, ConstantInt::get(C->getType(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return true if the specified value is free to invert (apply ~ to).
|
||||||
|
/// This happens in cases where the ~ can be eliminated. If WillInvertAllUses
|
||||||
|
/// is true, work under the assumption that the caller intends to remove all
|
||||||
|
/// uses of V and only keep uses of ~V.
|
||||||
|
///
|
||||||
|
static inline bool IsFreeToInvert(Value *V, bool WillInvertAllUses) {
|
||||||
|
// ~(~(X)) -> X.
|
||||||
|
if (BinaryOperator::isNot(V))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Constants can be considered to be not'ed values.
|
||||||
|
if (isa<ConstantInt>(V))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Compares can be inverted if all of their uses are being modified to use the
|
||||||
|
// ~V.
|
||||||
|
if (isa<CmpInst>(V))
|
||||||
|
return WillInvertAllUses;
|
||||||
|
|
||||||
|
// If `V` is of the form `A + Constant` then `-1 - V` can be folded into `(-1
|
||||||
|
// - Constant) - A` if we are willing to invert all of the uses.
|
||||||
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V))
|
||||||
|
if (BO->getOpcode() == Instruction::Add ||
|
||||||
|
BO->getOpcode() == Instruction::Sub)
|
||||||
|
if (isa<Constant>(BO->getOperand(0)) || isa<Constant>(BO->getOperand(1)))
|
||||||
|
return WillInvertAllUses;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief An IRBuilder inserter that adds new instructions to the instcombine
|
/// \brief An IRBuilder inserter that adds new instructions to the instcombine
|
||||||
/// worklist.
|
/// worklist.
|
||||||
class LLVM_LIBRARY_VISIBILITY InstCombineIRInserter
|
class LLVM_LIBRARY_VISIBILITY InstCombineIRInserter
|
||||||
|
@ -1145,12 +1145,14 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
|||||||
if (Instruction *FoldI = FoldSelectIntoOp(SI, TrueVal, FalseVal))
|
if (Instruction *FoldI = FoldSelectIntoOp(SI, TrueVal, FalseVal))
|
||||||
return FoldI;
|
return FoldI;
|
||||||
|
|
||||||
|
Value *LHS, *RHS, *LHS2, *RHS2;
|
||||||
|
SelectPatternFlavor SPF = MatchSelectPattern(&SI, LHS, RHS);
|
||||||
|
|
||||||
// MAX(MAX(a, b), a) -> MAX(a, b)
|
// MAX(MAX(a, b), a) -> MAX(a, b)
|
||||||
// MIN(MIN(a, b), a) -> MIN(a, b)
|
// MIN(MIN(a, b), a) -> MIN(a, b)
|
||||||
// MAX(MIN(a, b), a) -> a
|
// MAX(MIN(a, b), a) -> a
|
||||||
// MIN(MAX(a, b), a) -> a
|
// MIN(MAX(a, b), a) -> a
|
||||||
Value *LHS, *RHS, *LHS2, *RHS2;
|
if (SPF) {
|
||||||
if (SelectPatternFlavor SPF = MatchSelectPattern(&SI, LHS, RHS)) {
|
|
||||||
if (SelectPatternFlavor SPF2 = MatchSelectPattern(LHS, LHS2, RHS2))
|
if (SelectPatternFlavor SPF2 = MatchSelectPattern(LHS, LHS2, RHS2))
|
||||||
if (Instruction *R = FoldSPFofSPF(cast<Instruction>(LHS),SPF2,LHS2,RHS2,
|
if (Instruction *R = FoldSPFofSPF(cast<Instruction>(LHS),SPF2,LHS2,RHS2,
|
||||||
SI, SPF, RHS))
|
SI, SPF, RHS))
|
||||||
@ -1161,6 +1163,33 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
|||||||
return R;
|
return R;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MAX(~a, ~b) -> ~MIN(a, b)
|
||||||
|
if (SPF == SPF_SMAX || SPF == SPF_UMAX) {
|
||||||
|
if (IsFreeToInvert(LHS, LHS->hasNUses(2)) &&
|
||||||
|
IsFreeToInvert(RHS, RHS->hasNUses(2))) {
|
||||||
|
|
||||||
|
// This transform adds a xor operation and that extra cost needs to be
|
||||||
|
// justified. We look for simplifications that will result from
|
||||||
|
// applying this rule:
|
||||||
|
|
||||||
|
bool Profitable =
|
||||||
|
(LHS->hasNUses(2) && match(LHS, m_Not(m_Value()))) ||
|
||||||
|
(RHS->hasNUses(2) && match(RHS, m_Not(m_Value()))) ||
|
||||||
|
(SI.hasOneUse() && match(*SI.user_begin(), m_Not(m_Value())));
|
||||||
|
|
||||||
|
if (Profitable) {
|
||||||
|
Value *NewLHS = Builder->CreateNot(LHS);
|
||||||
|
Value *NewRHS = Builder->CreateNot(RHS);
|
||||||
|
Value *NewCmp = SPF == SPF_SMAX
|
||||||
|
? Builder->CreateICmpSLT(NewLHS, NewRHS)
|
||||||
|
: Builder->CreateICmpULT(NewLHS, NewRHS);
|
||||||
|
Value *NewSI =
|
||||||
|
Builder->CreateNot(Builder->CreateSelect(NewCmp, NewLHS, NewRHS));
|
||||||
|
return ReplaceInstUsesWith(SI, NewSI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO.
|
// TODO.
|
||||||
// ABS(-X) -> ABS(X)
|
// ABS(-X) -> ABS(X)
|
||||||
}
|
}
|
||||||
|
68
test/Transforms/InstCombine/max-of-nots.ll
Normal file
68
test/Transforms/InstCombine/max-of-nots.ll
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
; RUN: opt -S -instcombine < %s | FileCheck %s
|
||||||
|
|
||||||
|
define i32 @compute_min_2(i32 %x, i32 %y) {
|
||||||
|
; CHECK-LABEL: compute_min_2
|
||||||
|
entry:
|
||||||
|
%not_x = sub i32 -1, %x
|
||||||
|
%not_y = sub i32 -1, %y
|
||||||
|
%cmp = icmp sgt i32 %not_x, %not_y
|
||||||
|
%not_min = select i1 %cmp, i32 %not_x, i32 %not_y
|
||||||
|
%min = sub i32 -1, %not_min
|
||||||
|
ret i32 %min
|
||||||
|
|
||||||
|
; CHECK: %0 = icmp slt i32 %x, %y
|
||||||
|
; CHECK-NEXT: %1 = select i1 %0, i32 %x, i32 %y
|
||||||
|
; CHECK-NEXT: ret i32 %1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @compute_min_3(i32 %x, i32 %y, i32 %z) {
|
||||||
|
; CHECK-LABEL: compute_min_3
|
||||||
|
entry:
|
||||||
|
%not_x = sub i32 -1, %x
|
||||||
|
%not_y = sub i32 -1, %y
|
||||||
|
%not_z = sub i32 -1, %z
|
||||||
|
%cmp_1 = icmp sgt i32 %not_x, %not_y
|
||||||
|
%not_min_1 = select i1 %cmp_1, i32 %not_x, i32 %not_y
|
||||||
|
%cmp_2 = icmp sgt i32 %not_min_1, %not_z
|
||||||
|
%not_min_2 = select i1 %cmp_2, i32 %not_min_1, i32 %not_z
|
||||||
|
%min = sub i32 -1, %not_min_2
|
||||||
|
ret i32 %min
|
||||||
|
|
||||||
|
; CHECK: %0 = icmp slt i32 %x, %y
|
||||||
|
; CHECK-NEXT: %1 = select i1 %0, i32 %x, i32 %y
|
||||||
|
; CHECK-NEXT: %2 = icmp slt i32 %1, %z
|
||||||
|
; CHECK-NEXT: %3 = select i1 %2, i32 %1, i32 %z
|
||||||
|
; CHECK-NEXT: ret i32 %3
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @compute_min_arithmetic(i32 %x, i32 %y) {
|
||||||
|
; CHECK-LABEL: compute_min_arithmetic
|
||||||
|
entry:
|
||||||
|
%not_value = sub i32 3, %x
|
||||||
|
%not_y = sub i32 -1, %y
|
||||||
|
%cmp = icmp sgt i32 %not_value, %not_y
|
||||||
|
%not_min = select i1 %cmp, i32 %not_value, i32 %not_y
|
||||||
|
ret i32 %not_min
|
||||||
|
|
||||||
|
; CHECK: %0 = add i32 %x, -4
|
||||||
|
; CHECK-NEXT: %1 = icmp slt i32 %0, %y
|
||||||
|
; CHECK-NEXT: %2 = select i1 %1, i32 %0, i32 %y
|
||||||
|
; CHECK-NEXT: %3 = xor i32 %2, -1
|
||||||
|
; CHECK-NEXT: ret i32 %3
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @fake_use(i32)
|
||||||
|
|
||||||
|
define i32 @compute_min_pessimization(i32 %x, i32 %y) {
|
||||||
|
; CHECK-LABEL: compute_min_pessimization
|
||||||
|
entry:
|
||||||
|
%not_value = sub i32 3, %x
|
||||||
|
call void @fake_use(i32 %not_value)
|
||||||
|
%not_y = sub i32 -1, %y
|
||||||
|
%cmp = icmp sgt i32 %not_value, %not_y
|
||||||
|
; CHECK: %not_value = sub i32 3, %x
|
||||||
|
; CHECK: %cmp = icmp sgt i32 %not_value, %not_y
|
||||||
|
%not_min = select i1 %cmp, i32 %not_value, i32 %not_y
|
||||||
|
%min = sub i32 -1, %not_min
|
||||||
|
ret i32 %min
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user