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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool isCanonical(Value *V, ETNode *Subtree, VRPSolver *VRP);
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool isRelatedBy(Value *V1, Value *V2, ETNode *Subtree, LatticeVal LV) {
|
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,
|
void addToWorklist(Value *V, const APInt *I, ICmpInst::Predicate Pred,
|
||||||
VRPSolver *VRP);
|
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,
|
void addInequality(Value *V1, Value *V2, ETNode *Subtree, LatticeVal LV,
|
||||||
VRPSolver *VRP) {
|
VRPSolver *VRP) {
|
||||||
assert(!isRelatedBy(V1, V2, Subtree, LV) && "Asked to do useless work.");
|
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.
|
if (LV == NE) return; // we can't represent those.
|
||||||
// XXX: except in the case where isSingleElement and equal to either
|
// XXX: except in the case where isSingleElement and equal to either
|
||||||
// Lower or Upper. That's probably not profitable. (Type::Int1Ty?)
|
// 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
|
// The first iteration through this loop operates on V2 before going
|
||||||
// through the Remove list and operating on those too. If all of the
|
// through the Remove list and operating on those too. If all of the
|
||||||
// iterations performed simple replacements then we exit early.
|
// iterations performed simple replacements then we exit early.
|
||||||
bool exitEarly = true;
|
bool mergeIGNode = false;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
||||||
if (i) R = IG.node(Remove[i])->getValue(); // skip n2.
|
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.
|
// If we make it to here, then we will need to create a node for N1.
|
||||||
// Otherwise, we can skip out early!
|
// 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.
|
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
||||||
if (!n1) n1 = IG.newNode(V1);
|
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.
|
if (mergeIGNode) {
|
||||||
Node *N1 = IG.node(n1);
|
// Create N1.
|
||||||
for (SetVector<unsigned>::iterator I = Remove.begin(), E = Remove.end();
|
if (!n1) n1 = IG.newNode(V1);
|
||||||
I != E; ++I) {
|
|
||||||
unsigned n = *I;
|
// Migrate relationships from removed nodes to N1.
|
||||||
Node *N = IG.node(n);
|
Node *N1 = IG.node(n1);
|
||||||
for (Node::iterator NI = N->begin(), NE = N->end(); NI != NE; ++NI) {
|
for (SetVector<unsigned>::iterator I = Remove.begin(), E = Remove.end();
|
||||||
if (NI->Subtree->DominatedBy(Top)) {
|
I != E; ++I) {
|
||||||
if (NI->To == n1) {
|
unsigned n = *I;
|
||||||
assert((NI->LV & EQ_BIT) && "Node inequal to itself.");
|
Node *N = IG.node(n);
|
||||||
continue;
|
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);
|
// Point V2 (and all items in Remove) to N1.
|
||||||
N1->update(NI->To, NI->LV, Top);
|
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.
|
// re-opsToDef all dominated users of V1.
|
||||||
if (!n2)
|
if (Instruction *I = dyn_cast<Instruction>(V1)) {
|
||||||
IG.addEquality(n1, V2, Top);
|
for (Value::use_iterator UI = I->use_begin(), UE = I->use_end();
|
||||||
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;) {
|
UI != UE;) {
|
||||||
Use &TheUse = UI.getUse();
|
Use &TheUse = UI.getUse();
|
||||||
++UI;
|
++UI;
|
||||||
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
Value *V = TheUse.getUser();
|
||||||
if (below(I) ||
|
if (!V->use_empty()) {
|
||||||
Top->DominatedBy(Forest->getNodeForBlock(I->getParent())))
|
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
||||||
opsToDef(I);
|
if (below(Inst) ||
|
||||||
|
Top->DominatedBy(Forest->getNodeForBlock(Inst->getParent())))
|
||||||
|
opsToDef(Inst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1471,26 +1537,47 @@ namespace {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "%y = and i1 true, %x" then %x EQ %y.
|
// "%y = and i1 true, %x" then %x EQ %y
|
||||||
// "%y = or i1 false, %x" then %x EQ %y.
|
// "%y = or i1 false, %x" then %x EQ %y
|
||||||
if (BO->getOpcode() == Instruction::Or) {
|
// "%x = add i32 %y, 0" then %x EQ %y
|
||||||
Constant *Zero = Constant::getNullValue(BO->getType());
|
// "%x = mul i32 %y, 0" then %x EQ 0
|
||||||
if (Op0 == Zero) {
|
|
||||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
Instruction::BinaryOps Opcode = BO->getOpcode();
|
||||||
return;
|
|
||||||
} else if (Op1 == Zero) {
|
switch (Opcode) {
|
||||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
default: break;
|
||||||
return;
|
case Instruction::Sub:
|
||||||
}
|
case Instruction::Add:
|
||||||
} else if (BO->getOpcode() == Instruction::And) {
|
case Instruction::Or: {
|
||||||
Constant *AllOnes = ConstantInt::getAllOnesValue(BO->getType());
|
Constant *Zero = Constant::getNullValue(BO->getType());
|
||||||
if (Op0 == AllOnes) {
|
if (Op0 == Zero) {
|
||||||
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
||||||
return;
|
return;
|
||||||
} else if (Op1 == AllOnes) {
|
} else if (Op1 == Zero) {
|
||||||
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
||||||
return;
|
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
|
// "%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.
|
// 1. Repeat all of the above, with order of operands reversed.
|
||||||
// "%x = udiv i32 %y, %z" and %x EQ %y then %z EQ 1
|
// "%x = udiv i32 %y, %z" and %x EQ %y then %z EQ 1
|
||||||
|
|
||||||
Instruction::BinaryOps Opcode = BO->getOpcode();
|
|
||||||
const Type *Ty = BO->getType();
|
const Type *Ty = BO->getType();
|
||||||
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
||||||
|
|
||||||
@ -1704,6 +1790,12 @@ namespace {
|
|||||||
VRP->add(V, ConstantInt::get(*I), Pred, VRP->TopInst);
|
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
|
/// PredicateSimplifier - This class is a simplifier that replaces
|
||||||
/// one equivalent variable with another. It also tracks what
|
/// one equivalent variable with another. It also tracks what
|
||||||
/// can't be equal and will solve setcc instructions when possible.
|
/// 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