switch the main 'ValueState' map from being an std::map to being

a DenseMap.  Doing this required being aware of subtle iterator
invalidation issues, but it provides a big speedup.  In a 
release-asserts build, this sped up optimizing 403.gcc from
1.34s -> 0.79s (IPSCCP) and 1.11s -> 0.44s (SCCP).

This commit also conflates in a bunch of general cleanups, sorry.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85788 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2009-11-02 05:55:40 +00:00
parent 7baae87d8f
commit 2a0433beea

View File

@ -155,7 +155,7 @@ namespace {
/// ///
class SCCPSolver : public InstVisitor<SCCPSolver> { class SCCPSolver : public InstVisitor<SCCPSolver> {
DenseSet<BasicBlock*> BBExecutable;// The basic blocks that are executable DenseSet<BasicBlock*> BBExecutable;// The basic blocks that are executable
std::map<Value*, LatticeVal> ValueState; // The state each value is in. DenseMap<Value*, LatticeVal> ValueState; // The state each value is in.
/// GlobalValue - If we are tracking any values for the contents of a global /// GlobalValue - If we are tracking any values for the contents of a global
/// variable, we keep a mapping from the constant accessor to the element of /// variable, we keep a mapping from the constant accessor to the element of
@ -246,7 +246,7 @@ public:
} }
LatticeVal getLatticeValueFor(Value *V) const { LatticeVal getLatticeValueFor(Value *V) const {
std::map<Value*, LatticeVal>::const_iterator I = ValueState.find(V); DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
assert(I != ValueState.end() && "V is not in valuemap!"); assert(I != ValueState.end() && "V is not in valuemap!");
return I->second; return I->second;
} }
@ -278,15 +278,16 @@ private:
InstWorkList.push_back(V); InstWorkList.push_back(V);
} }
void markForcedConstant(LatticeVal &IV, Value *V, Constant *C) { void markConstant(Value *V, Constant *C) {
IV.markForcedConstant(C); markConstant(ValueState[V], V, C);
}
void markForcedConstant(Value *V, Constant *C) {
ValueState[V].markForcedConstant(C);
DEBUG(errs() << "markForcedConstant: " << *C << ": " << *V << '\n'); DEBUG(errs() << "markForcedConstant: " << *C << ": " << *V << '\n');
InstWorkList.push_back(V); InstWorkList.push_back(V);
} }
void markConstant(Value *V, Constant *C) {
markConstant(ValueState[V], V, C);
}
// markOverdefined - Make a value be marked as "overdefined". If the // markOverdefined - Make a value be marked as "overdefined". If the
// value is not already overdefined, add it to the overdefined instruction // value is not already overdefined, add it to the overdefined instruction
@ -303,7 +304,7 @@ private:
OverdefinedInstWorkList.push_back(V); OverdefinedInstWorkList.push_back(V);
} }
void mergeInValue(LatticeVal &IV, Value *V, LatticeVal &MergeWithV) { void mergeInValue(LatticeVal &IV, Value *V, LatticeVal MergeWithV) {
if (IV.isOverdefined() || MergeWithV.isUndefined()) if (IV.isOverdefined() || MergeWithV.isUndefined())
return; // Noop. return; // Noop.
if (MergeWithV.isOverdefined()) if (MergeWithV.isOverdefined())
@ -314,19 +315,16 @@ private:
markOverdefined(IV, V); markOverdefined(IV, V);
} }
void mergeInValue(Value *V, LatticeVal &MergeWithV) { void mergeInValue(Value *V, LatticeVal MergeWithV) {
mergeInValue(ValueState[V], V, MergeWithV); mergeInValue(ValueState[V], V, MergeWithV);
} }
// getValueState - Return the LatticeVal object that corresponds to the value. /// getValueState - Return the LatticeVal object that corresponds to the
// This function is necessary because not all values should start out in the /// value. This function handles the case when the value hasn't been seen yet
// underdefined state. Argument's should be overdefined, and /// by properly seeding constants etc.
// constants should be marked as constants. If a value is not known to be an
// Instruction object, then use this accessor to get its value from the map.
//
LatticeVal &getValueState(Value *V) { LatticeVal &getValueState(Value *V) {
std::map<Value*, LatticeVal>::iterator I = ValueState.find(V); DenseMap<Value*, LatticeVal>::iterator I = ValueState.find(V);
if (I != ValueState.end()) return I->second; // Common case, in the map if (I != ValueState.end()) return I->second; // Common case, in the map
LatticeVal &LV = ValueState[V]; LatticeVal &LV = ValueState[V];
@ -341,9 +339,8 @@ private:
return LV; return LV;
} }
// markEdgeExecutable - Mark a basic block as executable, adding it to the BB /// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
// work list if it is not already executable. /// work list if it is not already executable.
//
void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) { void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) {
if (!KnownFeasibleEdges.insert(Edge(Source, Dest)).second) if (!KnownFeasibleEdges.insert(Edge(Source, Dest)).second)
return; // This edge is already known to be executable! return; // This edge is already known to be executable!
@ -407,7 +404,7 @@ private:
void visitInsertValueInst(InsertValueInst &IVI); void visitInsertValueInst(InsertValueInst &IVI);
// Instructions that cannot be folded away. // Instructions that cannot be folded away.
void visitStoreInst (Instruction &I); void visitStoreInst (StoreInst &I);
void visitLoadInst (LoadInst &I); void visitLoadInst (LoadInst &I);
void visitGetElementPtrInst(GetElementPtrInst &I); void visitGetElementPtrInst(GetElementPtrInst &I);
void visitCallInst (CallInst &I) { void visitCallInst (CallInst &I) {
@ -448,7 +445,7 @@ void SCCPSolver::getFeasibleSuccessors(TerminatorInst &TI,
return; return;
} }
LatticeVal &BCValue = getValueState(BI->getCondition()); LatticeVal BCValue = getValueState(BI->getCondition());
ConstantInt *CI = BCValue.getConstantInt(); ConstantInt *CI = BCValue.getConstantInt();
if (CI == 0) { if (CI == 0) {
// Overdefined condition variables, and branches on unfoldable constant // Overdefined condition variables, and branches on unfoldable constant
@ -470,7 +467,7 @@ void SCCPSolver::getFeasibleSuccessors(TerminatorInst &TI,
} }
if (SwitchInst *SI = dyn_cast<SwitchInst>(&TI)) { if (SwitchInst *SI = dyn_cast<SwitchInst>(&TI)) {
LatticeVal &SCValue = getValueState(SI->getCondition()); LatticeVal SCValue = getValueState(SI->getCondition());
ConstantInt *CI = SCValue.getConstantInt(); ConstantInt *CI = SCValue.getConstantInt();
if (CI == 0) { // Overdefined or undefined condition? if (CI == 0) { // Overdefined or undefined condition?
@ -513,7 +510,7 @@ bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) {
if (BI->isUnconditional()) if (BI->isUnconditional())
return true; return true;
LatticeVal &BCValue = getValueState(BI->getCondition()); LatticeVal BCValue = getValueState(BI->getCondition());
// Overdefined condition variables mean the branch could go either way, // Overdefined condition variables mean the branch could go either way,
// undef conditions mean that neither edge is feasible yet. // undef conditions mean that neither edge is feasible yet.
@ -530,7 +527,7 @@ bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) {
return true; return true;
if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) { if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
LatticeVal &SCValue = getValueState(SI->getCondition()); LatticeVal SCValue = getValueState(SI->getCondition());
ConstantInt *CI = SCValue.getConstantInt(); ConstantInt *CI = SCValue.getConstantInt();
if (CI == 0) if (CI == 0)
@ -576,28 +573,27 @@ bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) {
// successors executable. // successors executable.
// //
void SCCPSolver::visitPHINode(PHINode &PN) { void SCCPSolver::visitPHINode(PHINode &PN) {
LatticeVal &PNIV = getValueState(&PN); if (getValueState(&PN).isOverdefined()) {
if (PNIV.isOverdefined()) {
// There may be instructions using this PHI node that are not overdefined // There may be instructions using this PHI node that are not overdefined
// themselves. If so, make sure that they know that the PHI node operand // themselves. If so, make sure that they know that the PHI node operand
// changed. // changed.
std::multimap<PHINode*, Instruction*>::iterator I, E; std::multimap<PHINode*, Instruction*>::iterator I, E;
tie(I, E) = UsersOfOverdefinedPHIs.equal_range(&PN); tie(I, E) = UsersOfOverdefinedPHIs.equal_range(&PN);
if (I != E) { if (I == E)
return;
SmallVector<Instruction*, 16> Users; SmallVector<Instruction*, 16> Users;
for (; I != E; ++I) Users.push_back(I->second); for (; I != E; ++I)
while (!Users.empty()) { Users.push_back(I->second);
visit(Users.back()); while (!Users.empty())
Users.pop_back(); visit(Users.pop_back_val());
}
}
return; // Quick exit return; // Quick exit
} }
// Super-extra-high-degree PHI nodes are unlikely to ever be marked constant, // Super-extra-high-degree PHI nodes are unlikely to ever be marked constant,
// and slow us down a lot. Just mark them overdefined. // and slow us down a lot. Just mark them overdefined.
if (PN.getNumIncomingValues() > 64) if (PN.getNumIncomingValues() > 64)
return markOverdefined(PNIV, &PN); return markOverdefined(&PN);
// Look at all of the executable operands of the PHI node. If any of them // Look at all of the executable operands of the PHI node. If any of them
// are overdefined, the PHI becomes overdefined as well. If they are all // are overdefined, the PHI becomes overdefined as well. If they are all
@ -607,7 +603,7 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
// //
Constant *OperandVal = 0; Constant *OperandVal = 0;
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
LatticeVal &IV = getValueState(PN.getIncomingValue(i)); LatticeVal IV = getValueState(PN.getIncomingValue(i));
if (IV.isUndefined()) continue; // Doesn't influence PHI node. if (IV.isUndefined()) continue; // Doesn't influence PHI node.
if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent())) if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent()))
@ -641,26 +637,25 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
} }
void SCCPSolver::visitReturnInst(ReturnInst &I) { void SCCPSolver::visitReturnInst(ReturnInst &I) {
if (I.getNumOperands() == 0) return; // Ret void if (I.getNumOperands() == 0) return; // ret void
Function *F = I.getParent()->getParent(); Function *F = I.getParent()->getParent();
// If we are tracking the return value of this function, merge it in. // If we are tracking the return value of this function, merge it in.
if (!F->hasLocalLinkage()) if (!F->hasLocalLinkage())
return; return;
if (!TrackedRetVals.empty() && I.getNumOperands() == 1) { if (!TrackedRetVals.empty()) {
DenseMap<Function*, LatticeVal>::iterator TFRVI = DenseMap<Function*, LatticeVal>::iterator TFRVI =
TrackedRetVals.find(F); TrackedRetVals.find(F);
if (TFRVI != TrackedRetVals.end() && if (TFRVI != TrackedRetVals.end() &&
!TFRVI->second.isOverdefined()) { !TFRVI->second.isOverdefined()) {
LatticeVal &IV = getValueState(I.getOperand(0)); mergeInValue(TFRVI->second, F, getValueState(I.getOperand(0)));
mergeInValue(TFRVI->second, F, IV);
return; return;
} }
} }
// Handle functions that return multiple values. // Handle functions that return multiple values.
if (!TrackedMultipleRetVals.empty() && I.getNumOperands() > 1) { if (0 && !TrackedMultipleRetVals.empty() && I.getNumOperands() > 1) {
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
DenseMap<std::pair<Function*, unsigned>, LatticeVal>::iterator DenseMap<std::pair<Function*, unsigned>, LatticeVal>::iterator
It = TrackedMultipleRetVals.find(std::make_pair(F, i)); It = TrackedMultipleRetVals.find(std::make_pair(F, i));
@ -668,7 +663,7 @@ void SCCPSolver::visitReturnInst(ReturnInst &I) {
mergeInValue(It->second, F, getValueState(I.getOperand(i))); mergeInValue(It->second, F, getValueState(I.getOperand(i)));
} }
} else if (!TrackedMultipleRetVals.empty() && } else if (!TrackedMultipleRetVals.empty() &&
I.getNumOperands() == 1 && /*I.getNumOperands() == 1 &&*/
isa<StructType>(I.getOperand(0)->getType())) { isa<StructType>(I.getOperand(0)->getType())) {
for (unsigned i = 0, e = I.getOperand(0)->getType()->getNumContainedTypes(); for (unsigned i = 0, e = I.getOperand(0)->getType()->getNumContainedTypes();
i != e; ++i) { i != e; ++i) {
@ -694,13 +689,12 @@ void SCCPSolver::visitTerminatorInst(TerminatorInst &TI) {
} }
void SCCPSolver::visitCastInst(CastInst &I) { void SCCPSolver::visitCastInst(CastInst &I) {
Value *V = I.getOperand(0); LatticeVal OpSt = getValueState(I.getOperand(0));
LatticeVal &VState = getValueState(V); if (OpSt.isOverdefined()) // Inherit overdefinedness of operand
if (VState.isOverdefined()) // Inherit overdefinedness of operand
markOverdefined(&I); markOverdefined(&I);
else if (VState.isConstant()) // Propagate constant value else if (OpSt.isConstant()) // Propagate constant value
markConstant(&I, ConstantExpr::getCast(I.getOpcode(), markConstant(&I, ConstantExpr::getCast(I.getOpcode(),
VState.getConstant(), I.getType())); OpSt.getConstant(), I.getType()));
} }
void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) { void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
@ -775,54 +769,62 @@ void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
} }
void SCCPSolver::visitSelectInst(SelectInst &I) { void SCCPSolver::visitSelectInst(SelectInst &I) {
LatticeVal &CondValue = getValueState(I.getCondition()); LatticeVal CondValue = getValueState(I.getCondition());
if (CondValue.isUndefined()) if (CondValue.isUndefined())
return; return;
if (ConstantInt *CondCB = CondValue.getConstantInt()) { if (ConstantInt *CondCB = CondValue.getConstantInt()) {
mergeInValue(&I, getValueState(CondCB->getZExtValue() ? I.getTrueValue() Value *OpVal = CondCB->isZero() ? I.getFalseValue() : I.getTrueValue();
: I.getFalseValue())); mergeInValue(&I, getValueState(OpVal));
return; return;
} }
// Otherwise, the condition is overdefined or a constant we can't evaluate. // Otherwise, the condition is overdefined or a constant we can't evaluate.
// See if we can produce something better than overdefined based on the T/F // See if we can produce something better than overdefined based on the T/F
// value. // value.
LatticeVal &TVal = getValueState(I.getTrueValue()); LatticeVal TVal = getValueState(I.getTrueValue());
LatticeVal &FVal = getValueState(I.getFalseValue()); LatticeVal FVal = getValueState(I.getFalseValue());
// select ?, C, C -> C. // select ?, C, C -> C.
if (TVal.isConstant() && FVal.isConstant() && if (TVal.isConstant() && FVal.isConstant() &&
TVal.getConstant() == FVal.getConstant()) TVal.getConstant() == FVal.getConstant())
return markConstant(&I, FVal.getConstant()); return markConstant(&I, FVal.getConstant());
if (TVal.isUndefined()) { // select ?, undef, X -> X. if (TVal.isUndefined()) // select ?, undef, X -> X.
mergeInValue(&I, FVal); return mergeInValue(&I, FVal);
} else if (FVal.isUndefined()) { // select ?, X, undef -> X. if (FVal.isUndefined()) // select ?, X, undef -> X.
mergeInValue(&I, TVal); return mergeInValue(&I, TVal);
} else {
markOverdefined(&I); markOverdefined(&I);
} }
}
// Handle BinaryOperators and Shift Instructions. // Handle Binary Operators.
void SCCPSolver::visitBinaryOperator(Instruction &I) { void SCCPSolver::visitBinaryOperator(Instruction &I) {
LatticeVal V1State = getValueState(I.getOperand(0));
LatticeVal V2State = getValueState(I.getOperand(1));
LatticeVal &IV = ValueState[&I]; LatticeVal &IV = ValueState[&I];
if (IV.isOverdefined()) return; if (IV.isOverdefined()) return;
LatticeVal &V1State = getValueState(I.getOperand(0)); if (V1State.isConstant() && V2State.isConstant())
LatticeVal &V2State = getValueState(I.getOperand(1)); return markConstant(IV, &I,
ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
V2State.getConstant()));
// If something is undef, wait for it to resolve.
if (!V1State.isOverdefined() && !V2State.isOverdefined())
return;
// Otherwise, one of our operands is overdefined. Try to produce something
// better than overdefined with some tricks.
if (V1State.isOverdefined() || V2State.isOverdefined()) {
// If this is an AND or OR with 0 or -1, it doesn't matter that the other // If this is an AND or OR with 0 or -1, it doesn't matter that the other
// operand is overdefined. // operand is overdefined.
if (I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Or) { if (I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Or) {
LatticeVal *NonOverdefVal = 0; LatticeVal *NonOverdefVal = 0;
if (!V1State.isOverdefined()) { if (!V1State.isOverdefined())
NonOverdefVal = &V1State; NonOverdefVal = &V1State;
} else if (!V2State.isOverdefined()) { else if (!V2State.isOverdefined())
NonOverdefVal = &V2State; NonOverdefVal = &V2State;
}
if (NonOverdefVal) { if (NonOverdefVal) {
if (NonOverdefVal->isUndefined()) { if (NonOverdefVal->isUndefined()) {
@ -835,7 +837,8 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
markConstant(IV, &I, markConstant(IV, &I,
Constant::getAllOnesValue(I.getType())); Constant::getAllOnesValue(I.getType()));
return; return;
} else { }
if (I.getOpcode() == Instruction::And) { if (I.getOpcode() == Instruction::And) {
// X and 0 = 0 // X and 0 = 0
if (NonOverdefVal->getConstant()->isNullValue()) if (NonOverdefVal->getConstant()->isNullValue())
@ -847,7 +850,6 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
} }
} }
} }
}
// If both operands are PHI nodes, it is possible that this instruction has // If both operands are PHI nodes, it is possible that this instruction has
@ -864,10 +866,9 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
// is not a constant! // is not a constant!
LatticeVal Result; LatticeVal Result;
for (unsigned i = 0, e = PN1->getNumIncomingValues(); i != e; ++i) { for (unsigned i = 0, e = PN1->getNumIncomingValues(); i != e; ++i) {
LatticeVal &In1 = getValueState(PN1->getIncomingValue(i)); LatticeVal In1 = getValueState(PN1->getIncomingValue(i));
BasicBlock *InBlock = PN1->getIncomingBlock(i); BasicBlock *InBlock = PN1->getIncomingBlock(i);
LatticeVal &In2 = LatticeVal In2 =getValueState(PN2->getIncomingValueForBlock(InBlock));
getValueState(PN2->getIncomingValueForBlock(InBlock));
if (In1.isOverdefined() || In2.isOverdefined()) { if (In1.isOverdefined() || In2.isOverdefined()) {
Result.markOverdefined(); Result.markOverdefined();
@ -875,8 +876,7 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
} }
if (In1.isConstant() && In2.isConstant()) { if (In1.isConstant() && In2.isConstant()) {
Constant *V = Constant *V = ConstantExpr::get(I.getOpcode(), In1.getConstant(),
ConstantExpr::get(I.getOpcode(), In1.getConstant(),
In2.getConstant()); In2.getConstant());
if (Result.isUndefined()) if (Result.isUndefined())
Result.markConstant(V); Result.markConstant(V);
@ -896,49 +896,43 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
UsersOfOverdefinedPHIs.insert(std::make_pair(PN1, &I)); UsersOfOverdefinedPHIs.insert(std::make_pair(PN1, &I));
UsersOfOverdefinedPHIs.insert(std::make_pair(PN2, &I)); UsersOfOverdefinedPHIs.insert(std::make_pair(PN2, &I));
return; return;
} else if (Result.isUndefined()) {
return;
} }
if (Result.isUndefined())
return;
// Okay, this really is overdefined now. Since we might have // Okay, this really is overdefined now. Since we might have
// speculatively thought that this was not overdefined before, and // speculatively thought that this was not overdefined before, and
// added ourselves to the UsersOfOverdefinedPHIs list for the PHIs, // added ourselves to the UsersOfOverdefinedPHIs list for the PHIs,
// make sure to clean out any entries that we put there, for // make sure to clean out any entries that we put there, for
// efficiency. // efficiency.
std::multimap<PHINode*, Instruction*>::iterator It, E; UsersOfOverdefinedPHIs.erase(PN1);
tie(It, E) = UsersOfOverdefinedPHIs.equal_range(PN1); UsersOfOverdefinedPHIs.erase(PN2);
while (It != E) {
if (It->second == &I) {
UsersOfOverdefinedPHIs.erase(It++);
} else
++It;
}
tie(It, E) = UsersOfOverdefinedPHIs.equal_range(PN2);
while (It != E) {
if (It->second == &I) {
UsersOfOverdefinedPHIs.erase(It++);
} else
++It;
}
} }
markOverdefined(IV, &I); markOverdefined(&I);
} else if (V1State.isConstant() && V2State.isConstant()) {
markConstant(IV, &I,
ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
V2State.getConstant()));
}
} }
// Handle ICmpInst instruction. // Handle ICmpInst instruction.
void SCCPSolver::visitCmpInst(CmpInst &I) { void SCCPSolver::visitCmpInst(CmpInst &I) {
LatticeVal V1State = getValueState(I.getOperand(0));
LatticeVal V2State = getValueState(I.getOperand(1));
LatticeVal &IV = ValueState[&I]; LatticeVal &IV = ValueState[&I];
if (IV.isOverdefined()) return; if (IV.isOverdefined()) return;
LatticeVal &V1State = getValueState(I.getOperand(0)); if (V1State.isConstant() && V2State.isConstant())
LatticeVal &V2State = getValueState(I.getOperand(1)); return markConstant(IV, &I, ConstantExpr::getCompare(I.getPredicate(),
V1State.getConstant(),
V2State.getConstant()));
// If operands are still undefined, wait for it to resolve.
if (!V1State.isOverdefined() && !V2State.isOverdefined())
return;
// If something is overdefined, use some tricks to avoid ending up and over
// defined if we can.
if (V1State.isOverdefined() || V2State.isOverdefined()) {
// If both operands are PHI nodes, it is possible that this instruction has // If both operands are PHI nodes, it is possible that this instruction has
// a constant value, despite the fact that the PHI node doesn't. Check for // a constant value, despite the fact that the PHI node doesn't. Check for
// this condition now. // this condition now.
@ -953,15 +947,16 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
// is not a constant! // is not a constant!
LatticeVal Result; LatticeVal Result;
for (unsigned i = 0, e = PN1->getNumIncomingValues(); i != e; ++i) { for (unsigned i = 0, e = PN1->getNumIncomingValues(); i != e; ++i) {
LatticeVal &In1 = getValueState(PN1->getIncomingValue(i)); LatticeVal In1 = getValueState(PN1->getIncomingValue(i));
BasicBlock *InBlock = PN1->getIncomingBlock(i); BasicBlock *InBlock = PN1->getIncomingBlock(i);
LatticeVal &In2 = LatticeVal In2 =getValueState(PN2->getIncomingValueForBlock(InBlock));
getValueState(PN2->getIncomingValueForBlock(InBlock));
if (In1.isOverdefined() || In2.isOverdefined()) { if (In1.isOverdefined() || In2.isOverdefined()) {
Result.markOverdefined(); Result.markOverdefined();
break; // Cannot fold this operation over the PHI nodes! break; // Cannot fold this operation over the PHI nodes!
} else if (In1.isConstant() && In2.isConstant()) { }
if (In1.isConstant() && In2.isConstant()) {
Constant *V = ConstantExpr::getCompare(I.getPredicate(), Constant *V = ConstantExpr::getCompare(I.getPredicate(),
In1.getConstant(), In1.getConstant(),
In2.getConstant()); In2.getConstant());
@ -977,44 +972,27 @@ void SCCPSolver::visitCmpInst(CmpInst &I) {
// If we found a constant value here, then we know the instruction is // If we found a constant value here, then we know the instruction is
// constant despite the fact that the PHI nodes are overdefined. // constant despite the fact that the PHI nodes are overdefined.
if (Result.isConstant()) { if (Result.isConstant()) {
markConstant(IV, &I, Result.getConstant()); markConstant(&I, Result.getConstant());
// Remember that this instruction is virtually using the PHI node // Remember that this instruction is virtually using the PHI node
// operands. // operands.
UsersOfOverdefinedPHIs.insert(std::make_pair(PN1, &I)); UsersOfOverdefinedPHIs.insert(std::make_pair(PN1, &I));
UsersOfOverdefinedPHIs.insert(std::make_pair(PN2, &I)); UsersOfOverdefinedPHIs.insert(std::make_pair(PN2, &I));
return; return;
} else if (Result.isUndefined()) {
return;
} }
if (Result.isUndefined())
return;
// Okay, this really is overdefined now. Since we might have // Okay, this really is overdefined now. Since we might have
// speculatively thought that this was not overdefined before, and // speculatively thought that this was not overdefined before, and
// added ourselves to the UsersOfOverdefinedPHIs list for the PHIs, // added ourselves to the UsersOfOverdefinedPHIs list for the PHIs,
// make sure to clean out any entries that we put there, for // make sure to clean out any entries that we put there, for
// efficiency. // efficiency.
std::multimap<PHINode*, Instruction*>::iterator It, E; UsersOfOverdefinedPHIs.erase(PN1);
tie(It, E) = UsersOfOverdefinedPHIs.equal_range(PN1); UsersOfOverdefinedPHIs.erase(PN2);
while (It != E) {
if (It->second == &I) {
UsersOfOverdefinedPHIs.erase(It++);
} else
++It;
}
tie(It, E) = UsersOfOverdefinedPHIs.equal_range(PN2);
while (It != E) {
if (It->second == &I) {
UsersOfOverdefinedPHIs.erase(It++);
} else
++It;
}
} }
markOverdefined(IV, &I); markOverdefined(&I);
} else if (V1State.isConstant() && V2State.isConstant()) {
markConstant(IV, &I, ConstantExpr::getCompare(I.getPredicate(),
V1State.getConstant(),
V2State.getConstant()));
}
} }
void SCCPSolver::visitExtractElementInst(ExtractElementInst &I) { void SCCPSolver::visitExtractElementInst(ExtractElementInst &I) {
@ -1096,7 +1074,7 @@ void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
Operands.reserve(I.getNumOperands()); Operands.reserve(I.getNumOperands());
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) { for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
LatticeVal &State = getValueState(I.getOperand(i)); LatticeVal State = getValueState(I.getOperand(i));
if (State.isUndefined()) if (State.isUndefined())
return; // Operands are not resolved yet. return; // Operands are not resolved yet.
@ -1108,23 +1086,20 @@ void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
} }
Constant *Ptr = Operands[0]; Constant *Ptr = Operands[0];
Operands.erase(Operands.begin()); // Erase the pointer from idx list. markConstant(&I, ConstantExpr::getGetElementPtr(Ptr, &Operands[0]+1,
Operands.size()-1));
markConstant(IV, &I, ConstantExpr::getGetElementPtr(Ptr, &Operands[0],
Operands.size()));
} }
void SCCPSolver::visitStoreInst(Instruction &SI) { void SCCPSolver::visitStoreInst(StoreInst &SI) {
if (TrackedGlobals.empty() || !isa<GlobalVariable>(SI.getOperand(1))) if (TrackedGlobals.empty() || !isa<GlobalVariable>(SI.getOperand(1)))
return; return;
GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1)); GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1));
DenseMap<GlobalVariable*, LatticeVal>::iterator I = TrackedGlobals.find(GV); DenseMap<GlobalVariable*, LatticeVal>::iterator I = TrackedGlobals.find(GV);
if (I == TrackedGlobals.end() || I->second.isOverdefined()) return; if (I == TrackedGlobals.end() || I->second.isOverdefined()) return;
// Get the value we are storing into the global. // Get the value we are storing into the global, then merge it.
LatticeVal &PtrVal = getValueState(SI.getOperand(0)); mergeInValue(I->second, GV, getValueState(SI.getOperand(0)));
mergeInValue(I->second, GV, PtrVal);
if (I->second.isOverdefined()) if (I->second.isOverdefined())
TrackedGlobals.erase(I); // No need to keep tracking this! TrackedGlobals.erase(I); // No need to keep tracking this!
} }
@ -1133,18 +1108,21 @@ void SCCPSolver::visitStoreInst(Instruction &SI) {
// Handle load instructions. If the operand is a constant pointer to a constant // Handle load instructions. If the operand is a constant pointer to a constant
// global, we can replace the load with the loaded constant value! // global, we can replace the load with the loaded constant value!
void SCCPSolver::visitLoadInst(LoadInst &I) { void SCCPSolver::visitLoadInst(LoadInst &I) {
LatticeVal PtrVal = getValueState(I.getOperand(0));
LatticeVal &IV = ValueState[&I]; LatticeVal &IV = ValueState[&I];
if (IV.isOverdefined()) return; if (IV.isOverdefined()) return;
LatticeVal &PtrVal = getValueState(I.getOperand(0));
if (PtrVal.isUndefined()) return; // The pointer is not resolved yet! if (PtrVal.isUndefined()) return; // The pointer is not resolved yet!
if (PtrVal.isConstant() && !I.isVolatile()) {
if (!PtrVal.isConstant() || I.isVolatile())
return markOverdefined(IV, &I);
Value *Ptr = PtrVal.getConstant(); Value *Ptr = PtrVal.getConstant();
// TODO: Consider a target hook for valid address spaces for this xform.
if (isa<ConstantPointerNull>(Ptr) && I.getPointerAddressSpace() == 0) {
// load null -> null // load null -> null
if (isa<ConstantPointerNull>(Ptr) && I.getPointerAddressSpace() == 0)
return markConstant(IV, &I, Constant::getNullValue(I.getType())); return markConstant(IV, &I, Constant::getNullValue(I.getType()));
}
// Transform load (constant global) into the value loaded. // Transform load (constant global) into the value loaded.
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) { if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
@ -1171,7 +1149,6 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
if (Constant *V = if (Constant *V =
ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE))
return markConstant(IV, &I, V); return markConstant(IV, &I, V);
}
// Otherwise we cannot say for certain what value this load will produce. // Otherwise we cannot say for certain what value this load will produce.
// Bail out. // Bail out.
@ -1198,7 +1175,7 @@ CallOverdefined:
SmallVector<Constant*, 8> Operands; SmallVector<Constant*, 8> Operands;
for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
AI != E; ++AI) { AI != E; ++AI) {
LatticeVal &State = getValueState(*AI); LatticeVal State = getValueState(*AI);
if (State.isUndefined()) if (State.isUndefined())
return; // Operands are not resolved yet. return; // Operands are not resolved yet.
@ -1266,13 +1243,12 @@ CallOverdefined:
CallSite::arg_iterator CAI = CS.arg_begin(); CallSite::arg_iterator CAI = CS.arg_begin();
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI, ++CAI) { AI != E; ++AI, ++CAI) {
LatticeVal &IV = ValueState[AI];
if (AI->hasByValAttr() && !F->onlyReadsMemory()) { if (AI->hasByValAttr() && !F->onlyReadsMemory()) {
IV.markOverdefined(); markOverdefined(AI);
continue; continue;
} }
if (!IV.isOverdefined())
mergeInValue(IV, AI, getValueState(*CAI)); mergeInValue(AI, getValueState(*CAI));
} }
} }
@ -1280,10 +1256,10 @@ void SCCPSolver::Solve() {
// Process the work lists until they are empty! // Process the work lists until they are empty!
while (!BBWorkList.empty() || !InstWorkList.empty() || while (!BBWorkList.empty() || !InstWorkList.empty() ||
!OverdefinedInstWorkList.empty()) { !OverdefinedInstWorkList.empty()) {
// Process the instruction work list. // Process the overdefined instruction's work list first, which drives other
// things to overdefined more quickly.
while (!OverdefinedInstWorkList.empty()) { while (!OverdefinedInstWorkList.empty()) {
Value *I = OverdefinedInstWorkList.back(); Value *I = OverdefinedInstWorkList.pop_back_val();
OverdefinedInstWorkList.pop_back();
DEBUG(errs() << "\nPopped off OI-WL: " << *I << '\n'); DEBUG(errs() << "\nPopped off OI-WL: " << *I << '\n');
@ -1301,13 +1277,12 @@ void SCCPSolver::Solve() {
// Process the instruction work list. // Process the instruction work list.
while (!InstWorkList.empty()) { while (!InstWorkList.empty()) {
Value *I = InstWorkList.back(); Value *I = InstWorkList.pop_back_val();
InstWorkList.pop_back();
DEBUG(errs() << "\nPopped off I-WL: " << *I << '\n'); DEBUG(errs() << "\nPopped off I-WL: " << *I << '\n');
// "I" got into the work list because it either made the transition from // "I" got into the work list because it made the transition from undef to
// bottom to constant // constant.
// //
// Anything on this worklist that is overdefined need not be visited // Anything on this worklist that is overdefined need not be visited
// since all of its users will have already been marked as overdefined. // since all of its users will have already been marked as overdefined.
@ -1364,7 +1339,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
if (!LV.isUndefined()) continue; if (!LV.isUndefined()) continue;
// Get the lattice values of the first two operands for use below. // Get the lattice values of the first two operands for use below.
LatticeVal &Op0LV = getValueState(I->getOperand(0)); LatticeVal Op0LV = getValueState(I->getOperand(0));
LatticeVal Op1LV; LatticeVal Op1LV;
if (I->getNumOperands() == 2) { if (I->getNumOperands() == 2) {
// If this is a two-operand instruction, and if both operands are // If this is a two-operand instruction, and if both operands are
@ -1383,23 +1358,18 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
// After a zero extend, we know the top part is zero. SExt doesn't have // After a zero extend, we know the top part is zero. SExt doesn't have
// to be handled here, because we don't know whether the top part is 1's // to be handled here, because we don't know whether the top part is 1's
// or 0's. // or 0's.
assert(Op0LV.isUndefined()); markForcedConstant(I, Constant::getNullValue(ITy));
markForcedConstant(LV, I, Constant::getNullValue(ITy));
return true; return true;
case Instruction::Mul: case Instruction::Mul:
case Instruction::And: case Instruction::And:
// undef * X -> 0. X could be zero. // undef * X -> 0. X could be zero.
// undef & X -> 0. X could be zero. // undef & X -> 0. X could be zero.
markForcedConstant(LV, I, Constant::getNullValue(ITy)); markForcedConstant(I, Constant::getNullValue(ITy));
return true; return true;
case Instruction::Or: case Instruction::Or:
// undef | X -> -1. X could be -1. // undef | X -> -1. X could be -1.
if (const VectorType *PTy = dyn_cast<VectorType>(ITy)) markForcedConstant(I, Constant::getAllOnesValue(ITy));
markForcedConstant(LV, I,
Constant::getAllOnesValue(PTy));
else
markForcedConstant(LV, I, Constant::getAllOnesValue(ITy));
return true; return true;
case Instruction::SDiv: case Instruction::SDiv:
@ -1412,7 +1382,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
// undef / X -> 0. X could be maxint. // undef / X -> 0. X could be maxint.
// undef % X -> 0. X could be 1. // undef % X -> 0. X could be 1.
markForcedConstant(LV, I, Constant::getNullValue(ITy)); markForcedConstant(I, Constant::getNullValue(ITy));
return true; return true;
case Instruction::AShr: case Instruction::AShr:
@ -1421,9 +1391,9 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
// X >>s undef -> X. X could be 0, X could have the high-bit known set. // X >>s undef -> X. X could be 0, X could have the high-bit known set.
if (Op0LV.isConstant()) if (Op0LV.isConstant())
markForcedConstant(LV, I, Op0LV.getConstant()); markForcedConstant(I, Op0LV.getConstant());
else else
markOverdefined(LV, I); markOverdefined(I);
return true; return true;
case Instruction::LShr: case Instruction::LShr:
case Instruction::Shl: case Instruction::Shl:
@ -1433,7 +1403,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
// X >> undef -> 0. X could be 0. // X >> undef -> 0. X could be 0.
// X << undef -> 0. X could be 0. // X << undef -> 0. X could be 0.
markForcedConstant(LV, I, Constant::getNullValue(ITy)); markForcedConstant(I, Constant::getNullValue(ITy));
return true; return true;
case Instruction::Select: case Instruction::Select:
// undef ? X : Y -> X or Y. There could be commonality between X/Y. // undef ? X : Y -> X or Y. There could be commonality between X/Y.
@ -1451,15 +1421,15 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
} }
if (Op1LV.isConstant()) if (Op1LV.isConstant())
markForcedConstant(LV, I, Op1LV.getConstant()); markForcedConstant(I, Op1LV.getConstant());
else else
markOverdefined(LV, I); markOverdefined(I);
return true; return true;
case Instruction::Call: case Instruction::Call:
// If a call has an undef result, it is because it is constant foldable // If a call has an undef result, it is because it is constant foldable
// but one of the inputs was undef. Just force the result to // but one of the inputs was undef. Just force the result to
// overdefined. // overdefined.
markOverdefined(LV, I); markOverdefined(I);
return true; return true;
} }
} }