One mundane change: Change ReplaceAllUsesOfValueWith to *optionally*

take a deleted nodes vector, instead of requiring it.

One more significant change:  Implement the start of a legalizer that
just works on types.  This legalizer is designed to run before the 
operation legalizer and ensure just that the input dag is transformed
into an output dag whose operand and result types are all legal, even
if the operations on those types are not.

This design/impl has the following advantages:

1. When finished, this will *significantly* reduce the amount of code in
   LegalizeDAG.cpp.  It will remove all the code related to promotion and
   expansion as well as splitting and scalarizing vectors.
2. The new code is very simple, idiomatic, and modular: unlike 
   LegalizeDAG.cpp, it has no 3000 line long functions. :)
3. The implementation is completely iterative instead of recursive, good
   for hacking on large dags without blowing out your stack.
4. The implementation updates nodes in place when possible instead of 
   deallocating and reallocating the entire graph that points to some 
   mutated node.
5. The code nicely separates out handling of operations with invalid 
   results from operations with invalid operands, making some cases
   simpler and easier to understand.
6. The new -debug-only=legalize-types option is very very handy :), 
   allowing you to easily understand what legalize types is doing.

This is not yet done.  Until the ifdef added to SelectionDAGISel.cpp is
enabled, this does nothing.  However, this code is sufficient to legalize
all of the code in 186.crafty, olden and freebench on an x86 machine.  The
biggest issues are:

1. Vectors aren't implemented at all yet
2. SoftFP is a mess, I need to talk to Evan about it.
3. No lowering to libcalls is implemented yet.
4. Various operations are missing etc.
5. There are FIXME's for stuff I hax0r'd out, like softfp.

Hey, at least it is a step in the right direction :).  If you'd like to help,
just enable the #ifdef in SelectionDAGISel.cpp and compile code with it.  If
this explodes it will tell you what needs to be implemented.  Help is 
certainly appreciated.

Once this goes in, we can do three things:

1. Add a new pass of dag combine between the "type legalizer" and "operation
   legalizer" passes.  This will let us catch some long-standing isel issues
   that we miss because operation legalization often obfuscates the dag with
   target-specific nodes.
2. We can rip out all of the type legalization code from LegalizeDAG.cpp,
   making it much smaller and simpler.  When that happens we can then 
   reimplement the core functionality left in it in a much more efficient and
   non-recursive way.
3. Once the whole legalizer is non-recursive, we can implement whole-function
   selectiondags maybe...



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42981 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2007-10-15 06:10:22 +00:00
parent 3cb9351e8a
commit 01d029b82c
7 changed files with 1605 additions and 61 deletions

View File

@ -120,6 +120,13 @@ public:
/// generate any nodes that will be illegal on the target.
void Combine(bool AfterLegalize, AliasAnalysis &AA);
/// LegalizeTypes - This transforms the SelectionDAG into a SelectionDAG that
/// only uses types natively supported by the target.
///
/// Note that this is an involved process that may invalidate pointers into
/// the graph.
void LegalizeTypes();
/// Legalize - This transforms the SelectionDAG into a SelectionDAG that is
/// compatible with the target instruction selector, as indicated by the
/// TargetLowering object.
@ -451,7 +458,7 @@ public:
/// handled the same was as for ReplaceAllUsesWith, but it is required for
/// this method.
void ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
std::vector<SDNode*> &Deleted);
std::vector<SDNode*> *Deleted = 0);
/// AssignNodeIds - Assign a unique node id for each node in the DAG based on
/// their allnodes order. It returns the maximum id.

View File

@ -173,7 +173,7 @@ namespace {
DOUT << '\n';
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, NowDead);
DAG.ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, &NowDead);
// Push the new node and any (possibly new) users onto the worklist.
AddToWorkList(TLO.New.Val);
@ -1414,8 +1414,6 @@ SDOperand DAGCombiner::visitMULHU(SDNode *N) {
///
bool DAGCombiner::SimplifyNodeWithTwoResults(SDNode *N,
unsigned LoOp, unsigned HiOp) {
std::vector<SDNode*> NowDead;
// If the high half is not needed, just compute the low half.
if (!N->hasAnyUseOfValue(1) &&
(!AfterLegalize ||
@ -1423,8 +1421,7 @@ bool DAGCombiner::SimplifyNodeWithTwoResults(SDNode *N,
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0),
DAG.getNode(LoOp, N->getValueType(0),
N->op_begin(),
N->getNumOperands()),
NowDead);
N->getNumOperands()));
return true;
}
@ -1435,8 +1432,7 @@ bool DAGCombiner::SimplifyNodeWithTwoResults(SDNode *N,
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1),
DAG.getNode(HiOp, N->getValueType(1),
N->op_begin(),
N->getNumOperands()),
NowDead);
N->getNumOperands()));
return true;
}
@ -1464,8 +1460,8 @@ bool DAGCombiner::SimplifyNodeWithTwoResults(SDNode *N,
(HiExists || HiOpt != Hi) &&
TLI.isOperationLegal(LoOpt.getOpcode(), LoOpt.getValueType()) &&
TLI.isOperationLegal(HiOpt.getOpcode(), HiOpt.getValueType())) {
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), LoOpt, NowDead);
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), HiOpt, NowDead);
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), LoOpt);
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), HiOpt);
return true;
}
@ -2891,8 +2887,7 @@ SDOperand DAGCombiner::ReduceLoadWidth(SDNode *N) {
LN0->isVolatile(), LN0->getAlignment());
AddToWorkList(N);
if (CombineSRL) {
std::vector<SDNode*> NowDead;
DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1), NowDead);
DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1));
CombineTo(N->getOperand(0).Val, Load);
} else
CombineTo(N0.Val, Load, Load.getValue(1));
@ -3694,12 +3689,12 @@ bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) {
std::vector<SDNode*> NowDead;
if (isLoad) {
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
NowDead);
&NowDead);
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), Result.getValue(2),
NowDead);
&NowDead);
} else {
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(1),
NowDead);
&NowDead);
}
// Nodes can end up on the worklist more than once. Make sure we do
@ -3711,7 +3706,7 @@ bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) {
// Replace the uses of Ptr with uses of the updated base value.
DAG.ReplaceAllUsesOfValueWith(Ptr, Result.getValue(isLoad ? 1 : 0),
NowDead);
&NowDead);
removeFromWorkList(Ptr.Val);
for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
removeFromWorkList(NowDead[i]);
@ -3825,12 +3820,12 @@ bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
std::vector<SDNode*> NowDead;
if (isLoad) {
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(0),
NowDead);
&NowDead);
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 1), Result.getValue(2),
NowDead);
&NowDead);
} else {
DAG.ReplaceAllUsesOfValueWith(SDOperand(N, 0), Result.getValue(1),
NowDead);
&NowDead);
}
// Nodes can end up on the worklist more than once. Make sure we do
@ -3843,7 +3838,7 @@ bool DAGCombiner::CombineToPostIndexedLoadStore(SDNode *N) {
// Replace the uses of Use with uses of the updated base value.
DAG.ReplaceAllUsesOfValueWith(SDOperand(Op, 0),
Result.getValue(isLoad ? 1 : 0),
NowDead);
&NowDead);
removeFromWorkList(Op);
for (unsigned i = 0, e = NowDead.size(); i != e; ++i)
removeFromWorkList(NowDead[i]);

File diff suppressed because it is too large Load Diff

View File

@ -422,14 +422,12 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
N = NewNodes[1];
SDNode *LoadNode = NewNodes[0];
std::vector<SDNode*> Deleted;
unsigned NumVals = N->getNumValues();
unsigned OldNumVals = SU->Node->getNumValues();
for (unsigned i = 0; i != NumVals; ++i)
DAG.ReplaceAllUsesOfValueWith(SDOperand(SU->Node, i),
SDOperand(N, i), Deleted);
DAG.ReplaceAllUsesOfValueWith(SDOperand(SU->Node, i), SDOperand(N, i));
DAG.ReplaceAllUsesOfValueWith(SDOperand(SU->Node, OldNumVals-1),
SDOperand(LoadNode, 1), Deleted);
SDOperand(LoadNode, 1));
SUnit *LoadSU = NewSUnit(LoadNode);
SUnit *NewSU = NewSUnit(N);

View File

@ -3232,11 +3232,11 @@ void SelectionDAG::ReplaceAllUsesWith(SDNode *From,
/// uses of other values produced by From.Val alone. The Deleted vector is
/// handled the same was as for ReplaceAllUsesWith.
void SelectionDAG::ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
std::vector<SDNode*> &Deleted) {
std::vector<SDNode*> *Deleted) {
assert(From != To && "Cannot replace a value with itself");
// Handle the simple, trivial, case efficiently.
if (From.Val->getNumValues() == 1 && To.Val->getNumValues() == 1) {
ReplaceAllUsesWith(From, To, &Deleted);
ReplaceAllUsesWith(From, To, Deleted);
return;
}
@ -3244,48 +3244,66 @@ void SelectionDAG::ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
// deterministically ordered and uniqued set, so we use a SmallSetVector.
SmallSetVector<SDNode*, 16> Users(From.Val->use_begin(), From.Val->use_end());
std::vector<SDNode*> LocalDeletionVector;
// Pick a deletion vector to use. If the user specified one, use theirs,
// otherwise use a local one.
std::vector<SDNode*> *DeleteVector = Deleted ? Deleted : &LocalDeletionVector;
while (!Users.empty()) {
// We know that this user uses some value of From. If it is the right
// value, update it.
SDNode *User = Users.back();
Users.pop_back();
for (SDOperand *Op = User->OperandList,
*E = User->OperandList+User->NumOperands; Op != E; ++Op) {
// Scan for an operand that matches From.
SDOperand *Op = User->OperandList, *E = User->OperandList+User->NumOperands;
for (; Op != E; ++Op)
if (*Op == From) break;
// If there are no matches, the user must use some other result of From.
if (Op == E) continue;
// Okay, we know this user needs to be updated. Remove its old self
// from the CSE maps.
RemoveNodeFromCSEMaps(User);
// Update all operands that match "From".
for (; Op != E; ++Op) {
if (*Op == From) {
// Okay, we know this user needs to be updated. Remove its old self
// from the CSE maps.
RemoveNodeFromCSEMaps(User);
// Update all operands that match "From".
for (; Op != E; ++Op) {
if (*Op == From) {
From.Val->removeUser(User);
*Op = To;
To.Val->addUser(User);
}
}
// Now that we have modified User, add it back to the CSE maps. If it
// already exists there, recursively merge the results together.
if (SDNode *Existing = AddNonLeafNodeToCSEMaps(User)) {
unsigned NumDeleted = Deleted.size();
ReplaceAllUsesWith(User, Existing, &Deleted);
// User is now dead.
Deleted.push_back(User);
DeleteNodeNotInCSEMaps(User);
// We have to be careful here, because ReplaceAllUsesWith could have
// deleted a user of From, which means there may be dangling pointers
// in the "Users" setvector. Scan over the deleted node pointers and
// remove them from the setvector.
for (unsigned i = NumDeleted, e = Deleted.size(); i != e; ++i)
Users.remove(Deleted[i]);
}
break; // Exit the operand scanning loop.
From.Val->removeUser(User);
*Op = To;
To.Val->addUser(User);
}
}
// Now that we have modified User, add it back to the CSE maps. If it
// already exists there, recursively merge the results together.
SDNode *Existing = AddNonLeafNodeToCSEMaps(User);
if (!Existing) continue; // Continue on to next user.
// If there was already an existing matching node, use ReplaceAllUsesWith
// to replace the dead one with the existing one. However, this can cause
// recursive merging of other unrelated nodes down the line. The merging
// can cause deletion of nodes that used the old value. In this case,
// we have to be certain to remove them from the Users set.
unsigned NumDeleted = DeleteVector->size();
ReplaceAllUsesWith(User, Existing, DeleteVector);
// User is now dead.
DeleteVector->push_back(User);
DeleteNodeNotInCSEMaps(User);
// We have to be careful here, because ReplaceAllUsesWith could have
// deleted a user of From, which means there may be dangling pointers
// in the "Users" setvector. Scan over the deleted node pointers and
// remove them from the setvector.
for (unsigned i = NumDeleted, e = DeleteVector->size(); i != e; ++i)
Users.remove((*DeleteVector)[i]);
// If the user doesn't need the set of deleted elements, don't retain them
// to the next loop iteration.
if (Deleted == 0)
LocalDeletionVector.clear();
}
}

View File

@ -4714,6 +4714,10 @@ void SelectionDAGISel::CodeGenAndEmitDAG(SelectionDAG &DAG) {
// Second step, hack on the DAG until it only uses operations and types that
// the target supports.
#if 0 // Enable this some day.
DAG.LegalizeTypes();
// Someday even later, enable a dag combine pass here.
#endif
DAG.Legalize();
DOUT << "Legalized selection DAG:\n";

View File

@ -3939,7 +3939,7 @@ OS << " unsigned NumKilled = ISelKilled.size();\n";
OS << "}\n\n";
OS << "void ReplaceUses(SDOperand F, SDOperand T) DISABLE_INLINE {\n";
OS << " CurDAG->ReplaceAllUsesOfValueWith(F, T, ISelKilled);\n";
OS << " CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISelKilled);\n";
OS << " setSelected(F.Val->getNodeId());\n";
OS << " RemoveKilled();\n";
OS << "}\n";
@ -3950,7 +3950,7 @@ OS << " unsigned NumKilled = ISelKilled.size();\n";
OS << " for (unsigned i = 0, e = std::min(FNumVals, TNumVals); "
<< "i < e; ++i)\n";
OS << " CurDAG->ReplaceAllUsesOfValueWith(SDOperand(F, i), "
<< "SDOperand(T, i), ISelKilled);\n";
<< "SDOperand(T, i), &ISelKilled);\n";
OS << " } else {\n";
OS << " CurDAG->ReplaceAllUsesWith(F, T, &ISelKilled);\n";
OS << " }\n";