mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-04 09:37:20 +00:00
Add more comments and update to new asm syntax.
Add new micro-optimizations. Add icmp predicate snuggling. Given %x ULT 4, "icmp ugt %x, 2" becomes "icmp eq %x, 3". This doesn't apply in any non-trivial cases yet due to missing support for NE values in ValueRanges. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35119 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
74027e98f1
commit
4c70875774
@ -22,9 +22,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass focusses on four properties; equals, not equals, less-than
|
||||
// and less-than-or-equals-to. The greater-than forms are also held just
|
||||
// to allow walking from a lesser node to a greater one. These properties
|
||||
// The InequalityGraph focusses on four properties; equals, not equals,
|
||||
// less-than and less-than-or-equals-to. The greater-than forms are also held
|
||||
// just to allow walking from a lesser node to a greater one. These properties
|
||||
// are stored in a lattice; LE can become LT or EQ, NE can become LT or GT.
|
||||
//
|
||||
// These relationships define a graph between values of the same type. Each
|
||||
@ -67,6 +67,17 @@
|
||||
// that the dividend is not equal to zero.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The ValueRanges class stores the known integer bounds of a Value. When we
|
||||
// encounter i8 %a u< %b, the ValueRanges stores that %a = [1, 255] and
|
||||
// %b = [0, 254]. Because we store these by Value*, you should always
|
||||
// canonicalize through the InequalityGraph first.
|
||||
//
|
||||
// It never stores an empty range, because that means that the code is
|
||||
// unreachable. It never stores a single-element range since that's an equality
|
||||
// relationship and better stored in the InequalityGraph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "predsimplify"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
@ -96,6 +107,7 @@ STATISTIC(NumVarsReplaced, "Number of argument substitutions");
|
||||
STATISTIC(NumInstruction , "Number of instructions removed");
|
||||
STATISTIC(NumSimple , "Number of simple replacements");
|
||||
STATISTIC(NumBlocks , "Number of blocks marked unreachable");
|
||||
STATISTIC(NumSnuggle , "Number of comparisons snuggled");
|
||||
|
||||
namespace {
|
||||
// SLT SGT ULT UGT EQ
|
||||
@ -155,6 +167,7 @@ namespace {
|
||||
/// reversePredicate - reverse the direction of the inequality
|
||||
static LatticeVal reversePredicate(LatticeVal LV) {
|
||||
unsigned reverse = LV ^ (SLT_BIT|SGT_BIT|ULT_BIT|UGT_BIT); //preserve EQ_BIT
|
||||
|
||||
if ((reverse & (SLT_BIT|SGT_BIT)) == 0)
|
||||
reverse |= (SLT_BIT|SGT_BIT);
|
||||
|
||||
@ -167,10 +180,10 @@ namespace {
|
||||
}
|
||||
|
||||
/// This is a StrictWeakOrdering predicate that sorts ETNodes by how many
|
||||
/// children they have. With this, you can iterate through a list sorted by
|
||||
/// this operation and the first matching entry is the most specific match
|
||||
/// for your basic block. The order provided is total; ETNodes with the
|
||||
/// same number of children are sorted by pointer address.
|
||||
/// descendants they have. With this, you can iterate through a list sorted
|
||||
/// by this operation and the first matching entry is the most specific
|
||||
/// match for your basic block. The order provided is stable; ETNodes with
|
||||
/// the same number of children are sorted by pointer address.
|
||||
struct VISIBILITY_HIDDEN OrderByDominance {
|
||||
bool operator()(const ETNode *LHS, const ETNode *RHS) const {
|
||||
unsigned LHS_spread = LHS->getDFSNumOut() - LHS->getDFSNumIn();
|
||||
@ -830,7 +843,7 @@ namespace {
|
||||
ConstantRange CR2 = rangeFromValue(V2, Subtree, W);
|
||||
|
||||
// True iff all values in CR1 are LV to all values in CR2.
|
||||
switch(LV) {
|
||||
switch (LV) {
|
||||
default: assert(!"Impossible lattice value!");
|
||||
case NE:
|
||||
return CR1.intersectWith(CR2).isEmptySet();
|
||||
@ -919,7 +932,6 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// UnreachableBlocks keeps tracks of blocks that are for one reason or
|
||||
/// another discovered to be unreachable. This is used to cull the graph when
|
||||
/// analyzing instructions, and to mark blocks with the "unreachable"
|
||||
@ -1366,7 +1378,7 @@ namespace {
|
||||
|
||||
switch (BO->getOpcode()) {
|
||||
case Instruction::And: {
|
||||
// "and i32 %a, %b" EQ -1 then %a EQ -1 and %b EQ -1
|
||||
// "and i32 %a, %b" EQ -1 then %a EQ -1 and %b EQ -1
|
||||
ConstantInt *CI = ConstantInt::getAllOnesValue(Ty);
|
||||
if (Canonical == CI) {
|
||||
add(CI, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||
@ -1459,8 +1471,8 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
// "%y = and bool true, %x" then %x EQ %y.
|
||||
// "%y = or bool false, %x" then %x EQ %y.
|
||||
// "%y = and i1 true, %x" then %x EQ %y.
|
||||
// "%y = or i1 false, %x" then %x EQ %y.
|
||||
if (BO->getOpcode() == Instruction::Or) {
|
||||
Constant *Zero = Constant::getNullValue(BO->getType());
|
||||
if (Op0 == Zero) {
|
||||
@ -1486,16 +1498,16 @@ namespace {
|
||||
// 1. Repeat all of the above, with order of operands reversed.
|
||||
// "%x = udiv i32 %y, %z" and %x EQ %y then %z EQ 1
|
||||
|
||||
Instruction::BinaryOps Opcode = BO->getOpcode();
|
||||
const Type *Ty = BO->getType();
|
||||
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
||||
|
||||
Value *Known = Op0, *Unknown = Op1;
|
||||
if (Known != BO) std::swap(Known, Unknown);
|
||||
if (Known == BO) {
|
||||
const Type *Ty = BO->getType();
|
||||
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
||||
|
||||
switch (BO->getOpcode()) {
|
||||
switch (Opcode) {
|
||||
default: break;
|
||||
case Instruction::Xor:
|
||||
case Instruction::Or:
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
add(Unknown, Constant::getNullValue(Ty), ICmpInst::ICMP_EQ,
|
||||
@ -1504,7 +1516,6 @@ namespace {
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SDiv:
|
||||
if (Unknown == Op0) break; // otherwise, fallthrough
|
||||
case Instruction::And:
|
||||
case Instruction::Mul:
|
||||
if (isa<ConstantInt>(Unknown)) {
|
||||
Constant *One = ConstantInt::get(Ty, 1);
|
||||
@ -1517,7 +1528,7 @@ namespace {
|
||||
// TODO: "%a = add i32 %b, 1" and %b > %z then %a >= %z.
|
||||
|
||||
} else if (ICmpInst *IC = dyn_cast<ICmpInst>(I)) {
|
||||
// "%a = icmp ult i32 %b, %c" and %b u< %c then %a EQ true
|
||||
// "%a = icmp ult i32 %b, %c" and %b u< %c then %a EQ true
|
||||
// "%a = icmp ult i32 %b, %c" and %b u>= %c then %a EQ false
|
||||
// etc.
|
||||
|
||||
@ -1531,12 +1542,8 @@ namespace {
|
||||
add(IC, ConstantInt::getFalse(), ICmpInst::ICMP_EQ, NewContext);
|
||||
}
|
||||
|
||||
// TODO: "i1 %x s<u> %y" implies %x = true and %y = false.
|
||||
|
||||
// TODO: make the predicate more strict, if possible.
|
||||
|
||||
} else if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
|
||||
// Given: "%a = select bool %x, int %b, int %c"
|
||||
// Given: "%a = select i1 %x, i32 %b, i32 %c"
|
||||
// %x EQ true then %a EQ %b
|
||||
// %x EQ false then %a EQ %c
|
||||
// %b EQ %c then %a EQ %b
|
||||
@ -1752,6 +1759,7 @@ namespace {
|
||||
void visitZExtInst(ZExtInst &ZI);
|
||||
|
||||
void visitBinaryOperator(BinaryOperator &BO);
|
||||
void visitICmpInst(ICmpInst &IC);
|
||||
};
|
||||
|
||||
// Used by terminator instructions to proceed from the current basic
|
||||
@ -1823,10 +1831,11 @@ namespace {
|
||||
}
|
||||
#endif
|
||||
|
||||
DOUT << "push (%" << I->getParent()->getName() << ")\n";
|
||||
std::string name = I->getParent()->getName();
|
||||
DOUT << "push (%" << name << ")\n";
|
||||
Forwards visit(this, DT);
|
||||
visit.visit(*I);
|
||||
DOUT << "pop (%" << I->getParent()->getName() << ")\n";
|
||||
DOUT << "pop (%" << name << ")\n";
|
||||
}
|
||||
};
|
||||
|
||||
@ -1979,6 +1988,7 @@ namespace {
|
||||
Instruction::BinaryOps ops = BO.getOpcode();
|
||||
|
||||
switch (ops) {
|
||||
default: break;
|
||||
case Instruction::URem:
|
||||
case Instruction::SRem:
|
||||
case Instruction::UDiv:
|
||||
@ -1990,8 +2000,100 @@ namespace {
|
||||
VRP.solve();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ops) {
|
||||
default: break;
|
||||
case Instruction::Shl: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_UGE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
case Instruction::AShr: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_SLE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
case Instruction::LShr:
|
||||
case Instruction::UDiv: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_ULE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
case Instruction::URem: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_ULE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
case Instruction::And: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_ULE);
|
||||
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_ULE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
case Instruction::Or: {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &BO);
|
||||
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_UGE);
|
||||
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_UGE);
|
||||
VRP.solve();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void PredicateSimplifier::Forwards::visitICmpInst(ICmpInst &IC) {
|
||||
// If possible, squeeze the ICmp predicate into something simpler.
|
||||
// Eg., if x = [0, 4) and we're being asked icmp uge %x, 3 then change
|
||||
// the predicate to eq.
|
||||
|
||||
ICmpInst::Predicate Pred = IC.getPredicate();
|
||||
|
||||
if (ConstantInt *Op1 = dyn_cast<ConstantInt>(IC.getOperand(1))) {
|
||||
ConstantInt *NextVal = 0;
|
||||
switch(Pred) {
|
||||
default: break;
|
||||
case ICmpInst::ICMP_SLT:
|
||||
case ICmpInst::ICMP_ULT:
|
||||
if (Op1->getValue() != 0)
|
||||
NextVal = cast<ConstantInt>(ConstantExpr::getAdd(
|
||||
Op1, ConstantInt::get(Op1->getType(), -1)));
|
||||
break;
|
||||
case ICmpInst::ICMP_SGT:
|
||||
case ICmpInst::ICMP_UGT:
|
||||
if (!Op1->getValue().isAllOnesValue())
|
||||
NextVal = cast<ConstantInt>(ConstantExpr::getAdd(
|
||||
Op1, ConstantInt::get(Op1->getType(), 1)));
|
||||
break;
|
||||
|
||||
}
|
||||
if (NextVal) {
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &IC);
|
||||
if (VRP.isRelatedBy(IC.getOperand(0), NextVal,
|
||||
ICmpInst::getInversePredicate(Pred))) {
|
||||
ICmpInst *NewIC = new ICmpInst(ICmpInst::ICMP_EQ, IC.getOperand(0),
|
||||
NextVal, "", &IC);
|
||||
NewIC->takeName(&IC);
|
||||
IC.replaceAllUsesWith(NewIC);
|
||||
IG.remove(&IC); // XXX: prove this isn't necessary
|
||||
IC.eraseFromParent();
|
||||
++NumSnuggle;
|
||||
PS->modified = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(Pred) {
|
||||
default: return;
|
||||
case ICmpInst::ICMP_ULE: Pred = ICmpInst::ICMP_ULT; break;
|
||||
case ICmpInst::ICMP_UGE: Pred = ICmpInst::ICMP_UGT; break;
|
||||
case ICmpInst::ICMP_SLE: Pred = ICmpInst::ICMP_SLT; break;
|
||||
case ICmpInst::ICMP_SGE: Pred = ICmpInst::ICMP_SGT; break;
|
||||
}
|
||||
VRPSolver VRP(IG, UB, VR, PS->Forest, PS->modified, &IC);
|
||||
if (VRP.isRelatedBy(IC.getOperand(1), IC.getOperand(0), Pred)) {
|
||||
++NumSnuggle;
|
||||
PS->modified = true;
|
||||
IC.setPredicate(Pred);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user