mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-31 07:43:37 +00:00
Propagate ValueRanges across equality.
Add some more micro-optimizations: x * 0 = 0, a - x = a --> x = 0. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35138 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1cc6452181
commit
1eda0f60d7
@ -833,6 +833,10 @@ namespace {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool isCanonical(Value *V, ETNode *Subtree, VRPSolver *VRP);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
bool isRelatedBy(Value *V1, Value *V2, ETNode *Subtree, LatticeVal LV) {
|
||||
@ -893,10 +897,38 @@ namespace {
|
||||
void addToWorklist(Value *V, const APInt *I, ICmpInst::Predicate Pred,
|
||||
VRPSolver *VRP);
|
||||
|
||||
void mergeInto(Value **I, unsigned n, Value *New, ETNode *Subtree,
|
||||
VRPSolver *VRP) {
|
||||
assert(isCanonical(New, Subtree, VRP) && "Best choice not canonical?");
|
||||
|
||||
uint32_t W = widthOfValue(New);
|
||||
if (!W) return;
|
||||
|
||||
ConstantRange CR_New = rangeFromValue(New, Subtree, W);
|
||||
ConstantRange Merged = CR_New;
|
||||
|
||||
for (; n != 0; ++I, --n) {
|
||||
ConstantRange CR_Kill = rangeFromValue(*I, Subtree, W);
|
||||
if (CR_Kill.isFullSet()) continue;
|
||||
Merged = Merged.intersectWith(CR_Kill);
|
||||
}
|
||||
|
||||
if (Merged.isFullSet() || Merged == CR_New) return;
|
||||
|
||||
if (Merged.isSingleElement())
|
||||
addToWorklist(New, Merged.getSingleElement(),
|
||||
ICmpInst::ICMP_EQ, VRP);
|
||||
else
|
||||
update(New, Merged, Subtree);
|
||||
}
|
||||
|
||||
void addInequality(Value *V1, Value *V2, ETNode *Subtree, LatticeVal LV,
|
||||
VRPSolver *VRP) {
|
||||
assert(!isRelatedBy(V1, V2, Subtree, LV) && "Asked to do useless work.");
|
||||
|
||||
assert(isCanonical(V1, Subtree, VRP) && "Value not canonical.");
|
||||
assert(isCanonical(V2, Subtree, VRP) && "Value not canonical.");
|
||||
|
||||
if (LV == NE) return; // we can't represent those.
|
||||
// XXX: except in the case where isSingleElement and equal to either
|
||||
// Lower or Upper. That's probably not profitable. (Type::Int1Ty?)
|
||||
@ -1150,7 +1182,7 @@ namespace {
|
||||
// The first iteration through this loop operates on V2 before going
|
||||
// through the Remove list and operating on those too. If all of the
|
||||
// iterations performed simple replacements then we exit early.
|
||||
bool exitEarly = true;
|
||||
bool mergeIGNode = false;
|
||||
unsigned i = 0;
|
||||
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
||||
if (i) R = IG.node(Remove[i])->getValue(); // skip n2.
|
||||
@ -1206,64 +1238,98 @@ namespace {
|
||||
|
||||
// If we make it to here, then we will need to create a node for N1.
|
||||
// Otherwise, we can skip out early!
|
||||
exitEarly = false;
|
||||
mergeIGNode = true;
|
||||
}
|
||||
|
||||
if (exitEarly) return true;
|
||||
if (!isa<Constant>(V1)) {
|
||||
if (Remove.empty()) {
|
||||
VR.mergeInto(&V2, 1, V1, Top, this);
|
||||
} else {
|
||||
std::vector<Value*> RemoveVals;
|
||||
RemoveVals.reserve(Remove.size());
|
||||
|
||||
// Create N1.
|
||||
if (!n1) n1 = IG.newNode(V1);
|
||||
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
||||
E = Remove.end(); I != E; ++I) {
|
||||
Value *V = IG.node(*I)->getValue();
|
||||
if (!V->use_empty())
|
||||
RemoveVals.push_back(V);
|
||||
}
|
||||
VR.mergeInto(&RemoveVals[0], RemoveVals.size(), V1, Top, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate relationships from removed nodes to N1.
|
||||
Node *N1 = IG.node(n1);
|
||||
for (SetVector<unsigned>::iterator I = Remove.begin(), E = Remove.end();
|
||||
I != E; ++I) {
|
||||
unsigned n = *I;
|
||||
Node *N = IG.node(n);
|
||||
for (Node::iterator NI = N->begin(), NE = N->end(); NI != NE; ++NI) {
|
||||
if (NI->Subtree->DominatedBy(Top)) {
|
||||
if (NI->To == n1) {
|
||||
assert((NI->LV & EQ_BIT) && "Node inequal to itself.");
|
||||
continue;
|
||||
if (mergeIGNode) {
|
||||
// Create N1.
|
||||
if (!n1) n1 = IG.newNode(V1);
|
||||
|
||||
// Migrate relationships from removed nodes to N1.
|
||||
Node *N1 = IG.node(n1);
|
||||
for (SetVector<unsigned>::iterator I = Remove.begin(), E = Remove.end();
|
||||
I != E; ++I) {
|
||||
unsigned n = *I;
|
||||
Node *N = IG.node(n);
|
||||
for (Node::iterator NI = N->begin(), NE = N->end(); NI != NE; ++NI) {
|
||||
if (NI->Subtree->DominatedBy(Top)) {
|
||||
if (NI->To == n1) {
|
||||
assert((NI->LV & EQ_BIT) && "Node inequal to itself.");
|
||||
continue;
|
||||
}
|
||||
if (Remove.count(NI->To))
|
||||
continue;
|
||||
|
||||
IG.node(NI->To)->update(n1, reversePredicate(NI->LV), Top);
|
||||
N1->update(NI->To, NI->LV, Top);
|
||||
}
|
||||
if (Remove.count(NI->To))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
IG.node(NI->To)->update(n1, reversePredicate(NI->LV), Top);
|
||||
N1->update(NI->To, NI->LV, Top);
|
||||
// Point V2 (and all items in Remove) to N1.
|
||||
if (!n2)
|
||||
IG.addEquality(n1, V2, Top);
|
||||
else {
|
||||
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
||||
E = Remove.end(); I != E; ++I) {
|
||||
IG.addEquality(n1, IG.node(*I)->getValue(), Top);
|
||||
}
|
||||
}
|
||||
|
||||
// If !Remove.empty() then V2 = Remove[0]->getValue().
|
||||
// Even when Remove is empty, we still want to process V2.
|
||||
i = 0;
|
||||
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
||||
if (i) R = IG.node(Remove[i])->getValue(); // skip n2.
|
||||
|
||||
if (Instruction *I2 = dyn_cast<Instruction>(R)) {
|
||||
if (below(I2) ||
|
||||
Top->DominatedBy(Forest->getNodeForBlock(I2->getParent())))
|
||||
defToOps(I2);
|
||||
}
|
||||
for (Value::use_iterator UI = V2->use_begin(), UE = V2->use_end();
|
||||
UI != UE;) {
|
||||
Use &TheUse = UI.getUse();
|
||||
++UI;
|
||||
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
||||
if (below(I) ||
|
||||
Top->DominatedBy(Forest->getNodeForBlock(I->getParent())))
|
||||
opsToDef(I);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Point V2 (and all items in Remove) to N1.
|
||||
if (!n2)
|
||||
IG.addEquality(n1, V2, Top);
|
||||
else {
|
||||
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
||||
E = Remove.end(); I != E; ++I) {
|
||||
IG.addEquality(n1, IG.node(*I)->getValue(), Top);
|
||||
}
|
||||
}
|
||||
|
||||
// If !Remove.empty() then V2 = Remove[0]->getValue().
|
||||
// Even when Remove is empty, we still want to process V2.
|
||||
i = 0;
|
||||
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
||||
if (i) R = IG.node(Remove[i])->getValue(); // skip n2.
|
||||
|
||||
if (Instruction *I2 = dyn_cast<Instruction>(R)) {
|
||||
if (below(I2) ||
|
||||
Top->DominatedBy(Forest->getNodeForBlock(I2->getParent())))
|
||||
defToOps(I2);
|
||||
}
|
||||
for (Value::use_iterator UI = V2->use_begin(), UE = V2->use_end();
|
||||
// re-opsToDef all dominated users of V1.
|
||||
if (Instruction *I = dyn_cast<Instruction>(V1)) {
|
||||
for (Value::use_iterator UI = I->use_begin(), UE = I->use_end();
|
||||
UI != UE;) {
|
||||
Use &TheUse = UI.getUse();
|
||||
++UI;
|
||||
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
||||
if (below(I) ||
|
||||
Top->DominatedBy(Forest->getNodeForBlock(I->getParent())))
|
||||
opsToDef(I);
|
||||
Value *V = TheUse.getUser();
|
||||
if (!V->use_empty()) {
|
||||
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
||||
if (below(Inst) ||
|
||||
Top->DominatedBy(Forest->getNodeForBlock(Inst->getParent())))
|
||||
opsToDef(Inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1471,26 +1537,47 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
// "%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) {
|
||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
} else if (Op1 == Zero) {
|
||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
}
|
||||
} else if (BO->getOpcode() == Instruction::And) {
|
||||
Constant *AllOnes = ConstantInt::getAllOnesValue(BO->getType());
|
||||
if (Op0 == AllOnes) {
|
||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
} else if (Op1 == AllOnes) {
|
||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
}
|
||||
// "%y = and i1 true, %x" then %x EQ %y
|
||||
// "%y = or i1 false, %x" then %x EQ %y
|
||||
// "%x = add i32 %y, 0" then %x EQ %y
|
||||
// "%x = mul i32 %y, 0" then %x EQ 0
|
||||
|
||||
Instruction::BinaryOps Opcode = BO->getOpcode();
|
||||
|
||||
switch (Opcode) {
|
||||
default: break;
|
||||
case Instruction::Sub:
|
||||
case Instruction::Add:
|
||||
case Instruction::Or: {
|
||||
Constant *Zero = Constant::getNullValue(BO->getType());
|
||||
if (Op0 == Zero) {
|
||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
} else if (Op1 == Zero) {
|
||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
case Instruction::And: {
|
||||
Constant *AllOnes = ConstantInt::getAllOnesValue(BO->getType());
|
||||
if (Op0 == AllOnes) {
|
||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
} else if (Op1 == AllOnes) {
|
||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
case Instruction::Mul: {
|
||||
Constant *Zero = Constant::getNullValue(BO->getType());
|
||||
if (Op0 == Zero) {
|
||||
add(BO, Zero, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
} else if (Op1 == Zero) {
|
||||
add(BO, Zero, ICmpInst::ICMP_EQ, NewContext);
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// "%x = add i32 %y, %z" and %x EQ %y then %z EQ 0
|
||||
@ -1498,7 +1585,6 @@ 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!");
|
||||
|
||||
@ -1704,6 +1790,12 @@ namespace {
|
||||
VRP->add(V, ConstantInt::get(*I), Pred, VRP->TopInst);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool ValueRanges::isCanonical(Value *V, ETNode *Subtree, VRPSolver *VRP) {
|
||||
return V == VRP->IG.canonicalize(V, Subtree);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// PredicateSimplifier - This class is a simplifier that replaces
|
||||
/// one equivalent variable with another. It also tracks what
|
||||
/// can't be equal and will solve setcc instructions when possible.
|
||||
|
@ -0,0 +1,19 @@
|
||||
; RUN: llvm-as < %s | opt -predsimplify | llvm-dis | grep -v %c
|
||||
define void @foo(i8* %X, i8* %Y) {
|
||||
entry:
|
||||
%A = load i8* %X
|
||||
%B = load i8* %Y
|
||||
%a = icmp ult i8 %B, 10
|
||||
br i1 %a, label %cond_true, label %URB
|
||||
cond_true:
|
||||
%b = icmp eq i8 %A, %B
|
||||
br i1 %b, label %cond_true2, label %URB
|
||||
cond_true2:
|
||||
%c = icmp ult i8 %A, 11
|
||||
call i8 @bar(i1 %c)
|
||||
ret void
|
||||
URB:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i8 @bar(i1)
|
Loading…
x
Reference in New Issue
Block a user