From: Chris Lattner Date: Mon, 12 Jan 2004 03:57:30 +0000 (+0000) Subject: Implement SCCP/phitest.ll X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1daee8b010003e8578824877f0dbe407b554b52d;p=oota-llvm.git Implement SCCP/phitest.ll git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10763 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index ee6a175278e..2d8171dd8dd 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -75,7 +75,10 @@ public: inline bool isConstant() const { return LatticeValue == constant; } inline bool isOverdefined() const { return LatticeValue == overdefined; } - inline Constant *getConstant() const { return ConstantVal; } + inline Constant *getConstant() const { + assert(isConstant() && "Cannot get the constant of a non-constant!"); + return ConstantVal; + } }; } // end anonymous namespace @@ -94,6 +97,10 @@ class SCCP : public FunctionPass, public InstVisitor { std::vector InstWorkList;// The instruction work list std::vector BBWorkList; // The BasicBlock work list + /// UsersOfOverdefinedPHIs - Keep track of any users of PHI nodes that are not + /// overdefined, despite the fact that the PHI node is overdefined. + std::multimap UsersOfOverdefinedPHIs; + /// KnownFeasibleEdges - Entries in this set are edges which have already had /// PHI nodes retriggered. typedef std::pair Edge; @@ -463,7 +470,23 @@ bool SCCP::isEdgeFeasible(BasicBlock *From, BasicBlock *To) { // void SCCP::visitPHINode(PHINode &PN) { InstVal &PNIV = getValueState(&PN); - if (PNIV.isOverdefined()) return; // Quick exit + if (PNIV.isOverdefined()) { + // 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 + // changed. + std::multimap::iterator I, E; + tie(I, E) = UsersOfOverdefinedPHIs.equal_range(&PN); + if (I != E) { + std::vector Users; + Users.reserve(std::distance(I, E)); + for (; I != E; ++I) Users.push_back(I->second); + while (!Users.empty()) { + visit(Users.back()); + Users.pop_back(); + } + } + return; // Quick exit + } // 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 @@ -540,24 +563,102 @@ void SCCP::visitCastInst(CastInst &I) { // Handle BinaryOperators and Shift Instructions... void SCCP::visitBinaryOperator(Instruction &I) { + InstVal &IV = ValueState[&I]; + if (IV.isOverdefined()) return; + InstVal &V1State = getValueState(I.getOperand(0)); InstVal &V2State = getValueState(I.getOperand(1)); + if (V1State.isOverdefined() || V2State.isOverdefined()) { - markOverdefined(&I); + // 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 + // this condition now. + if (PHINode *PN1 = dyn_cast(I.getOperand(0))) + if (PHINode *PN2 = dyn_cast(I.getOperand(1))) + if (PN1->getParent() == PN2->getParent()) { + // Since the two PHI nodes are in the same basic block, they must have + // entries for the same predecessors. Walk the predecessor list, and + // if all of the incoming values are constants, and the result of + // evaluating this expression with all incoming value pairs is the + // same, then this expression is a constant even though the PHI node + // is not a constant! + InstVal Result; + for (unsigned i = 0, e = PN1->getNumIncomingValues(); i != e; ++i) { + InstVal &In1 = getValueState(PN1->getIncomingValue(i)); + BasicBlock *InBlock = PN1->getIncomingBlock(i); + InstVal &In2 =getValueState(PN2->getIncomingValueForBlock(InBlock)); + + if (In1.isOverdefined() || In2.isOverdefined()) { + Result.markOverdefined(); + break; // Cannot fold this operation over the PHI nodes! + } else if (In1.isConstant() && In2.isConstant()) { + Constant *Val = 0; + if (isa(I)) + Val = ConstantExpr::get(I.getOpcode(), In1.getConstant(), + In2.getConstant()); + else { + assert(isa(I) && + "Can only handle binops and shifts here!"); + Val = ConstantExpr::getShift(I.getOpcode(), In1.getConstant(), + In2.getConstant()); + } + if (Result.isUndefined()) + Result.markConstant(Val); + else if (Result.isConstant() && Result.getConstant() != Val) { + Result.markOverdefined(); + break; + } + } + } + + // If we found a constant value here, then we know the instruction is + // constant despite the fact that the PHI nodes are overdefined. + if (Result.isConstant()) { + markConstant(IV, &I, Result.getConstant()); + // Remember that this instruction is virtually using the PHI node + // operands. + UsersOfOverdefinedPHIs.insert(std::make_pair(PN1, &I)); + UsersOfOverdefinedPHIs.insert(std::make_pair(PN2, &I)); + return; + } else if (Result.isUndefined()) { + return; + } + + // Okay, this really is overdefined now. Since we might have + // speculatively thought that this was not overdefined before, and + // added ourselves to the UsersOfOverdefinedPHIs list for the PHIs, + // make sure to clean out any entries that we put there, for + // efficiency. + std::multimap::iterator It, E; + tie(It, E) = UsersOfOverdefinedPHIs.equal_range(PN1); + 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); } else if (V1State.isConstant() && V2State.isConstant()) { Constant *Result = 0; if (isa(I)) - Result = ConstantFoldBinaryInstruction(I.getOpcode(), - V1State.getConstant(), - V2State.getConstant()); - else if (isa(I)) - Result = ConstantFoldShiftInstruction(I.getOpcode(), - V1State.getConstant(), - V2State.getConstant()); - if (Result) - markConstant(&I, Result); // This instruction constant folds! - else - markOverdefined(&I); // Don't know how to fold this instruction. :( + Result = ConstantExpr::get(I.getOpcode(), V1State.getConstant(), + V2State.getConstant()); + else { + assert (isa(I) && "Can only handle binops and shifts here!"); + Result = ConstantExpr::getShift(I.getOpcode(), V1State.getConstant(), + V2State.getConstant()); + } + + markConstant(IV, &I, Result); // This instruction constant folds! } }