2002-07-11 06:38:08 +08:00
|
|
|
//===- DataStructure.cpp - Implement the core data structure analysis -----===//
|
2003-10-21 03:43:21 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2002-03-27 06:39:06 +08:00
|
|
|
//
|
2002-07-11 06:38:08 +08:00
|
|
|
// This file implements the core data structure functionality.
|
2002-03-27 06:39:06 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2002-10-02 06:33:50 +08:00
|
|
|
#include "llvm/Analysis/DSGraph.h"
|
|
|
|
#include "llvm/Function.h"
|
2004-02-26 07:36:08 +08:00
|
|
|
#include "llvm/GlobalVariable.h"
|
2002-10-21 05:41:02 +08:00
|
|
|
#include "llvm/iOther.h"
|
2002-07-11 06:38:08 +08:00
|
|
|
#include "llvm/DerivedTypes.h"
|
2002-10-02 12:57:39 +08:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2003-07-02 12:38:49 +08:00
|
|
|
#include "llvm/Assembly/Writer.h"
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
#include "Support/CommandLine.h"
|
2003-08-02 06:15:03 +08:00
|
|
|
#include "Support/Debug.h"
|
2002-07-11 06:38:08 +08:00
|
|
|
#include "Support/STLExtras.h"
|
2002-10-02 06:33:50 +08:00
|
|
|
#include "Support/Statistic.h"
|
2002-11-19 05:44:46 +08:00
|
|
|
#include "Support/Timer.h"
|
2002-07-18 08:12:30 +08:00
|
|
|
#include <algorithm>
|
2003-11-13 07:11:14 +08:00
|
|
|
using namespace llvm;
|
2003-11-12 06:41:34 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
namespace {
|
2004-02-08 07:58:05 +08:00
|
|
|
Statistic<> NumFolds ("dsa", "Number of nodes completely folded");
|
|
|
|
Statistic<> NumCallNodesMerged("dsa", "Number of call nodes merged");
|
|
|
|
Statistic<> NumNodeAllocated ("dsa", "Number of nodes allocated");
|
|
|
|
Statistic<> NumDNE ("dsa", "Number of nodes removed by reachability");
|
2004-02-08 09:51:48 +08:00
|
|
|
Statistic<> NumTrivialDNE ("dsa", "Number of nodes trivially removed");
|
|
|
|
Statistic<> NumTrivialGlobalDNE("dsa", "Number of globals trivially removed");
|
2002-11-06 14:20:27 +08:00
|
|
|
};
|
|
|
|
|
2004-01-28 10:41:32 +08:00
|
|
|
#if 1
|
2004-01-23 00:36:28 +08:00
|
|
|
#define TIME_REGION(VARNAME, DESC) \
|
|
|
|
NamedRegionTimer VARNAME(DESC)
|
|
|
|
#else
|
|
|
|
#define TIME_REGION(VARNAME, DESC)
|
|
|
|
#endif
|
|
|
|
|
2002-11-07 13:20:53 +08:00
|
|
|
using namespace DS;
|
2002-10-02 06:33:50 +08:00
|
|
|
|
2003-02-14 03:09:00 +08:00
|
|
|
DSNode *DSNodeHandle::HandleForwarding() const {
|
2004-02-08 09:27:18 +08:00
|
|
|
assert(N->isForwarding() && "Can only be invoked if forwarding!");
|
2003-02-14 03:09:00 +08:00
|
|
|
|
|
|
|
// Handle node forwarding here!
|
|
|
|
DSNode *Next = N->ForwardNH.getNode(); // Cause recursive shrinkage
|
|
|
|
Offset += N->ForwardNH.getOffset();
|
|
|
|
|
|
|
|
if (--N->NumReferrers == 0) {
|
|
|
|
// Removing the last referrer to the node, sever the forwarding link
|
|
|
|
N->stopForwarding();
|
|
|
|
}
|
|
|
|
|
|
|
|
N = Next;
|
|
|
|
N->NumReferrers++;
|
|
|
|
if (N->Size <= Offset) {
|
|
|
|
assert(N->Size <= 1 && "Forwarded to shrunk but not collapsed node?");
|
|
|
|
Offset = 0;
|
|
|
|
}
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2002-07-11 06:38:08 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DSNode Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2002-03-27 06:39:06 +08:00
|
|
|
|
2003-06-20 05:15:11 +08:00
|
|
|
DSNode::DSNode(const Type *T, DSGraph *G)
|
2003-07-03 07:57:05 +08:00
|
|
|
: NumReferrers(0), Size(0), ParentGraph(G), Ty(Type::VoidTy), NodeType(0) {
|
2002-10-31 13:45:02 +08:00
|
|
|
// Add the type entry if it is specified...
|
2002-11-06 14:20:27 +08:00
|
|
|
if (T) mergeTypeInfo(T, 0);
|
2004-02-08 09:05:37 +08:00
|
|
|
if (G) G->addNode(this);
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
++NumNodeAllocated;
|
2002-07-11 06:38:08 +08:00
|
|
|
}
|
2002-03-27 06:39:06 +08:00
|
|
|
|
2002-07-18 08:12:30 +08:00
|
|
|
// DSNode copy constructor... do not copy over the referrers list!
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
DSNode::DSNode(const DSNode &N, DSGraph *G, bool NullLinks)
|
2003-07-03 07:57:05 +08:00
|
|
|
: NumReferrers(0), Size(N.Size), ParentGraph(G),
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
Ty(N.Ty), Globals(N.Globals), NodeType(N.NodeType) {
|
|
|
|
if (!NullLinks)
|
|
|
|
Links = N.Links;
|
|
|
|
else
|
|
|
|
Links.resize(N.Links.size()); // Create the appropriate number of null links
|
2004-02-08 07:58:05 +08:00
|
|
|
G->addNode(this);
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
++NumNodeAllocated;
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
2003-11-03 06:27:28 +08:00
|
|
|
/// getTargetData - Get the target data object used to construct this node.
|
|
|
|
///
|
|
|
|
const TargetData &DSNode::getTargetData() const {
|
|
|
|
return ParentGraph->getTargetData();
|
|
|
|
}
|
|
|
|
|
2003-02-12 07:11:51 +08:00
|
|
|
void DSNode::assertOK() const {
|
|
|
|
assert((Ty != Type::VoidTy ||
|
|
|
|
Ty == Type::VoidTy && (Size == 0 ||
|
|
|
|
(NodeType & DSNode::Array))) &&
|
|
|
|
"Node not OK!");
|
2003-07-03 10:03:53 +08:00
|
|
|
|
|
|
|
assert(ParentGraph && "Node has no parent?");
|
2004-01-28 17:15:42 +08:00
|
|
|
const DSScalarMap &SM = ParentGraph->getScalarMap();
|
2003-07-03 10:03:53 +08:00
|
|
|
for (unsigned i = 0, e = Globals.size(); i != e; ++i) {
|
2004-01-28 10:41:32 +08:00
|
|
|
assert(SM.count(Globals[i]));
|
2003-07-03 10:03:53 +08:00
|
|
|
assert(SM.find(Globals[i])->second.getNode() == this);
|
|
|
|
}
|
2003-02-12 07:11:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// forwardNode - Mark this node as being obsolete, and all references to it
|
|
|
|
/// should be forwarded to the specified node and offset.
|
|
|
|
///
|
|
|
|
void DSNode::forwardNode(DSNode *To, unsigned Offset) {
|
|
|
|
assert(this != To && "Cannot forward a node to itself!");
|
|
|
|
assert(ForwardNH.isNull() && "Already forwarding from this node!");
|
|
|
|
if (To->Size <= 1) Offset = 0;
|
|
|
|
assert((Offset < To->Size || (Offset == To->Size && Offset == 0)) &&
|
|
|
|
"Forwarded offset is wrong!");
|
|
|
|
ForwardNH.setNode(To);
|
|
|
|
ForwardNH.setOffset(Offset);
|
|
|
|
NodeType = DEAD;
|
|
|
|
Size = 0;
|
|
|
|
Ty = Type::VoidTy;
|
2004-02-08 09:27:18 +08:00
|
|
|
|
|
|
|
// Remove this node from the parent graph's Nodes list.
|
|
|
|
ParentGraph->unlinkNode(this);
|
|
|
|
ParentGraph = 0;
|
2002-03-27 06:39:06 +08:00
|
|
|
}
|
|
|
|
|
2002-07-12 04:32:22 +08:00
|
|
|
// addGlobal - Add an entry for a global value to the Globals list. This also
|
|
|
|
// marks the node with the 'G' flag if it does not already have it.
|
|
|
|
//
|
|
|
|
void DSNode::addGlobal(GlobalValue *GV) {
|
2002-07-18 08:12:30 +08:00
|
|
|
// Keep the list sorted.
|
2003-02-01 12:01:21 +08:00
|
|
|
std::vector<GlobalValue*>::iterator I =
|
2002-07-18 08:12:30 +08:00
|
|
|
std::lower_bound(Globals.begin(), Globals.end(), GV);
|
|
|
|
|
|
|
|
if (I == Globals.end() || *I != GV) {
|
2002-10-02 06:33:50 +08:00
|
|
|
//assert(GV->getType()->getElementType() == Ty);
|
2002-07-18 08:12:30 +08:00
|
|
|
Globals.insert(I, GV);
|
|
|
|
NodeType |= GlobalNode;
|
|
|
|
}
|
2002-07-12 04:32:22 +08:00
|
|
|
}
|
|
|
|
|
2002-10-31 13:45:02 +08:00
|
|
|
/// foldNodeCompletely - If we determine that this node has some funny
|
|
|
|
/// behavior happening to it that we cannot represent, we fold it down to a
|
|
|
|
/// single, completely pessimistic, node. This node is represented as a
|
|
|
|
/// single byte with a single TypeEntry of "void".
|
|
|
|
///
|
|
|
|
void DSNode::foldNodeCompletely() {
|
2003-02-12 07:11:51 +08:00
|
|
|
if (isNodeCompletelyFolded()) return; // If this node is already folded...
|
2002-11-06 14:20:27 +08:00
|
|
|
|
|
|
|
++NumFolds;
|
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// If this node has a size that is <= 1, we don't need to create a forwarding
|
|
|
|
// node.
|
|
|
|
if (getSize() <= 1) {
|
|
|
|
NodeType |= DSNode::Array;
|
|
|
|
Ty = Type::VoidTy;
|
|
|
|
Size = 1;
|
|
|
|
assert(Links.size() <= 1 && "Size is 1, but has more links?");
|
|
|
|
Links.resize(1);
|
2003-02-12 07:11:51 +08:00
|
|
|
} else {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Create the node we are going to forward to. This is required because
|
|
|
|
// some referrers may have an offset that is > 0. By forcing them to
|
|
|
|
// forward, the forwarder has the opportunity to correct the offset.
|
|
|
|
DSNode *DestNode = new DSNode(0, ParentGraph);
|
|
|
|
DestNode->NodeType = NodeType|DSNode::Array;
|
|
|
|
DestNode->Ty = Type::VoidTy;
|
|
|
|
DestNode->Size = 1;
|
|
|
|
DestNode->Globals.swap(Globals);
|
|
|
|
|
|
|
|
// Start forwarding to the destination node...
|
|
|
|
forwardNode(DestNode, 0);
|
|
|
|
|
|
|
|
if (!Links.empty()) {
|
|
|
|
DestNode->Links.reserve(1);
|
|
|
|
|
|
|
|
DSNodeHandle NH(DestNode);
|
|
|
|
DestNode->Links.push_back(Links[0]);
|
|
|
|
|
|
|
|
// If we have links, merge all of our outgoing links together...
|
|
|
|
for (unsigned i = Links.size()-1; i != 0; --i)
|
|
|
|
NH.getNode()->Links[0].mergeWith(Links[i]);
|
|
|
|
Links.clear();
|
|
|
|
} else {
|
|
|
|
DestNode->Links.resize(1);
|
|
|
|
}
|
2003-02-12 07:11:51 +08:00
|
|
|
}
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
2002-11-07 14:31:54 +08:00
|
|
|
|
2002-10-31 13:45:02 +08:00
|
|
|
/// isNodeCompletelyFolded - Return true if this node has been completely
|
|
|
|
/// folded down to something that can never be expanded, effectively losing
|
|
|
|
/// all of the field sensitivity that may be present in the node.
|
|
|
|
///
|
|
|
|
bool DSNode::isNodeCompletelyFolded() const {
|
2002-11-19 05:44:46 +08:00
|
|
|
return getSize() == 1 && Ty == Type::VoidTy && isArray();
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
|
|
|
|
2003-06-30 04:27:45 +08:00
|
|
|
namespace {
|
|
|
|
/// TypeElementWalker Class - Used for implementation of physical subtyping...
|
|
|
|
///
|
|
|
|
class TypeElementWalker {
|
|
|
|
struct StackState {
|
|
|
|
const Type *Ty;
|
|
|
|
unsigned Offset;
|
|
|
|
unsigned Idx;
|
|
|
|
StackState(const Type *T, unsigned Off = 0)
|
|
|
|
: Ty(T), Offset(Off), Idx(0) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<StackState> Stack;
|
2003-11-03 06:27:28 +08:00
|
|
|
const TargetData &TD;
|
2003-06-30 04:27:45 +08:00
|
|
|
public:
|
2003-11-03 06:27:28 +08:00
|
|
|
TypeElementWalker(const Type *T, const TargetData &td) : TD(td) {
|
2003-06-30 04:27:45 +08:00
|
|
|
Stack.push_back(T);
|
|
|
|
StepToLeaf();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDone() const { return Stack.empty(); }
|
|
|
|
const Type *getCurrentType() const { return Stack.back().Ty; }
|
|
|
|
unsigned getCurrentOffset() const { return Stack.back().Offset; }
|
|
|
|
|
|
|
|
void StepToNextType() {
|
|
|
|
PopStackAndAdvance();
|
|
|
|
StepToLeaf();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// PopStackAndAdvance - Pop the current element off of the stack and
|
|
|
|
/// advance the underlying element to the next contained member.
|
|
|
|
void PopStackAndAdvance() {
|
|
|
|
assert(!Stack.empty() && "Cannot pop an empty stack!");
|
|
|
|
Stack.pop_back();
|
|
|
|
while (!Stack.empty()) {
|
|
|
|
StackState &SS = Stack.back();
|
|
|
|
if (const StructType *ST = dyn_cast<StructType>(SS.Ty)) {
|
|
|
|
++SS.Idx;
|
2004-02-09 12:37:31 +08:00
|
|
|
if (SS.Idx != ST->getNumElements()) {
|
2003-06-30 04:27:45 +08:00
|
|
|
const StructLayout *SL = TD.getStructLayout(ST);
|
|
|
|
SS.Offset += SL->MemberOffsets[SS.Idx]-SL->MemberOffsets[SS.Idx-1];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Stack.pop_back(); // At the end of the structure
|
|
|
|
} else {
|
|
|
|
const ArrayType *AT = cast<ArrayType>(SS.Ty);
|
|
|
|
++SS.Idx;
|
|
|
|
if (SS.Idx != AT->getNumElements()) {
|
|
|
|
SS.Offset += TD.getTypeSize(AT->getElementType());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Stack.pop_back(); // At the end of the array
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// StepToLeaf - Used by physical subtyping to move to the first leaf node
|
|
|
|
/// on the type stack.
|
|
|
|
void StepToLeaf() {
|
|
|
|
if (Stack.empty()) return;
|
|
|
|
while (!Stack.empty() && !Stack.back().Ty->isFirstClassType()) {
|
|
|
|
StackState &SS = Stack.back();
|
|
|
|
if (const StructType *ST = dyn_cast<StructType>(SS.Ty)) {
|
2004-02-09 12:37:31 +08:00
|
|
|
if (ST->getNumElements() == 0) {
|
2003-06-30 04:27:45 +08:00
|
|
|
assert(SS.Idx == 0);
|
|
|
|
PopStackAndAdvance();
|
|
|
|
} else {
|
|
|
|
// Step into the structure...
|
2004-02-09 12:37:31 +08:00
|
|
|
assert(SS.Idx < ST->getNumElements());
|
2003-06-30 04:27:45 +08:00
|
|
|
const StructLayout *SL = TD.getStructLayout(ST);
|
2004-02-09 12:37:31 +08:00
|
|
|
Stack.push_back(StackState(ST->getElementType(SS.Idx),
|
2003-06-30 04:27:45 +08:00
|
|
|
SS.Offset+SL->MemberOffsets[SS.Idx]));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const ArrayType *AT = cast<ArrayType>(SS.Ty);
|
|
|
|
if (AT->getNumElements() == 0) {
|
|
|
|
assert(SS.Idx == 0);
|
|
|
|
PopStackAndAdvance();
|
|
|
|
} else {
|
|
|
|
// Step into the array...
|
|
|
|
assert(SS.Idx < AT->getNumElements());
|
|
|
|
Stack.push_back(StackState(AT->getElementType(),
|
|
|
|
SS.Offset+SS.Idx*
|
|
|
|
TD.getTypeSize(AT->getElementType())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2003-11-12 06:41:34 +08:00
|
|
|
} // end anonymous namespace
|
2003-06-30 04:27:45 +08:00
|
|
|
|
|
|
|
/// ElementTypesAreCompatible - Check to see if the specified types are
|
|
|
|
/// "physically" compatible. If so, return true, else return false. We only
|
2003-11-03 05:02:20 +08:00
|
|
|
/// have to check the fields in T1: T2 may be larger than T1. If AllowLargerT1
|
|
|
|
/// is true, then we also allow a larger T1.
|
2003-06-30 04:27:45 +08:00
|
|
|
///
|
2003-11-03 05:02:20 +08:00
|
|
|
static bool ElementTypesAreCompatible(const Type *T1, const Type *T2,
|
2003-11-03 06:27:28 +08:00
|
|
|
bool AllowLargerT1, const TargetData &TD){
|
|
|
|
TypeElementWalker T1W(T1, TD), T2W(T2, TD);
|
2003-06-30 04:27:45 +08:00
|
|
|
|
|
|
|
while (!T1W.isDone() && !T2W.isDone()) {
|
|
|
|
if (T1W.getCurrentOffset() != T2W.getCurrentOffset())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const Type *T1 = T1W.getCurrentType();
|
|
|
|
const Type *T2 = T2W.getCurrentType();
|
|
|
|
if (T1 != T2 && !T1->isLosslesslyConvertibleTo(T2))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
T1W.StepToNextType();
|
|
|
|
T2W.StepToNextType();
|
|
|
|
}
|
|
|
|
|
2003-11-03 05:02:20 +08:00
|
|
|
return AllowLargerT1 || T1W.isDone();
|
2003-06-30 04:27:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
/// mergeTypeInfo - This method merges the specified type into the current node
|
|
|
|
/// at the specified offset. This may update the current node's type record if
|
|
|
|
/// this gives more information to the node, it may do nothing to the node if
|
|
|
|
/// this information is already known, or it may merge the node completely (and
|
|
|
|
/// return true) if the information is incompatible with what is already known.
|
2002-10-02 12:57:39 +08:00
|
|
|
///
|
2002-11-06 14:20:27 +08:00
|
|
|
/// This method returns true if the node is completely folded, otherwise false.
|
|
|
|
///
|
2003-03-04 01:13:31 +08:00
|
|
|
bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
|
|
|
|
bool FoldIfIncompatible) {
|
2003-11-03 06:27:28 +08:00
|
|
|
const TargetData &TD = getTargetData();
|
2002-11-06 14:20:27 +08:00
|
|
|
// Check to make sure the Size member is up-to-date. Size can be one of the
|
|
|
|
// following:
|
|
|
|
// Size = 0, Ty = Void: Nothing is known about this node.
|
|
|
|
// Size = 0, Ty = FnTy: FunctionPtr doesn't have a size, so we use zero
|
|
|
|
// Size = 1, Ty = Void, Array = 1: The node is collapsed
|
|
|
|
// Otherwise, sizeof(Ty) = Size
|
|
|
|
//
|
2002-11-19 05:44:46 +08:00
|
|
|
assert(((Size == 0 && Ty == Type::VoidTy && !isArray()) ||
|
|
|
|
(Size == 0 && !Ty->isSized() && !isArray()) ||
|
|
|
|
(Size == 1 && Ty == Type::VoidTy && isArray()) ||
|
|
|
|
(Size == 0 && !Ty->isSized() && !isArray()) ||
|
|
|
|
(TD.getTypeSize(Ty) == Size)) &&
|
2002-11-06 14:20:27 +08:00
|
|
|
"Size member of DSNode doesn't match the type structure!");
|
|
|
|
assert(NewTy != Type::VoidTy && "Cannot merge void type into DSNode!");
|
|
|
|
|
2002-11-19 05:44:46 +08:00
|
|
|
if (Offset == 0 && NewTy == Ty)
|
2002-11-06 14:20:27 +08:00
|
|
|
return false; // This should be a common case, handle it efficiently
|
|
|
|
|
|
|
|
// Return true immediately if the node is completely folded.
|
|
|
|
if (isNodeCompletelyFolded()) return true;
|
|
|
|
|
2002-11-09 06:49:57 +08:00
|
|
|
// If this is an array type, eliminate the outside arrays because they won't
|
|
|
|
// be used anyway. This greatly reduces the size of large static arrays used
|
|
|
|
// as global variables, for example.
|
|
|
|
//
|
2002-11-10 03:25:27 +08:00
|
|
|
bool WillBeArray = false;
|
2002-11-09 06:49:57 +08:00
|
|
|
while (const ArrayType *AT = dyn_cast<ArrayType>(NewTy)) {
|
|
|
|
// FIXME: we might want to keep small arrays, but must be careful about
|
|
|
|
// things like: [2 x [10000 x int*]]
|
|
|
|
NewTy = AT->getElementType();
|
2002-11-10 03:25:27 +08:00
|
|
|
WillBeArray = true;
|
2002-11-09 06:49:57 +08:00
|
|
|
}
|
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Figure out how big the new type we're merging in is...
|
|
|
|
unsigned NewTySize = NewTy->isSized() ? TD.getTypeSize(NewTy) : 0;
|
|
|
|
|
|
|
|
// Otherwise check to see if we can fold this type into the current node. If
|
|
|
|
// we can't, we fold the node completely, if we can, we potentially update our
|
|
|
|
// internal state.
|
|
|
|
//
|
2002-11-19 05:44:46 +08:00
|
|
|
if (Ty == Type::VoidTy) {
|
2002-11-06 14:20:27 +08:00
|
|
|
// If this is the first type that this node has seen, just accept it without
|
|
|
|
// question....
|
2003-11-03 05:02:20 +08:00
|
|
|
assert(Offset == 0 && !isArray() &&
|
|
|
|
"Cannot have an offset into a void node!");
|
2002-11-19 05:44:46 +08:00
|
|
|
Ty = NewTy;
|
|
|
|
NodeType &= ~Array;
|
|
|
|
if (WillBeArray) NodeType |= Array;
|
2002-11-06 14:20:27 +08:00
|
|
|
Size = NewTySize;
|
|
|
|
|
|
|
|
// Calculate the number of outgoing links from this node.
|
|
|
|
Links.resize((Size+DS::PointerSize-1) >> DS::PointerShift);
|
|
|
|
return false;
|
2002-10-02 12:57:39 +08:00
|
|
|
}
|
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Handle node expansion case here...
|
|
|
|
if (Offset+NewTySize > Size) {
|
|
|
|
// It is illegal to grow this node if we have treated it as an array of
|
|
|
|
// objects...
|
2002-11-19 05:44:46 +08:00
|
|
|
if (isArray()) {
|
2003-03-04 01:13:31 +08:00
|
|
|
if (FoldIfIncompatible) foldNodeCompletely();
|
2002-11-06 14:20:27 +08:00
|
|
|
return true;
|
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
if (Offset) { // We could handle this case, but we don't for now...
|
2003-06-30 04:27:45 +08:00
|
|
|
std::cerr << "UNIMP: Trying to merge a growth type into "
|
|
|
|
<< "offset != 0: Collapsing!\n";
|
2003-03-04 01:13:31 +08:00
|
|
|
if (FoldIfIncompatible) foldNodeCompletely();
|
2002-11-06 14:20:27 +08:00
|
|
|
return true;
|
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Okay, the situation is nice and simple, we are trying to merge a type in
|
|
|
|
// at offset 0 that is bigger than our current type. Implement this by
|
|
|
|
// switching to the new type and then merge in the smaller one, which should
|
|
|
|
// hit the other code path here. If the other code path decides it's not
|
|
|
|
// ok, it will collapse the node as appropriate.
|
|
|
|
//
|
2002-11-19 05:44:46 +08:00
|
|
|
const Type *OldTy = Ty;
|
|
|
|
Ty = NewTy;
|
|
|
|
NodeType &= ~Array;
|
|
|
|
if (WillBeArray) NodeType |= Array;
|
2002-11-06 14:20:27 +08:00
|
|
|
Size = NewTySize;
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Must grow links to be the appropriate size...
|
|
|
|
Links.resize((Size+DS::PointerSize-1) >> DS::PointerShift);
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Merge in the old type now... which is guaranteed to be smaller than the
|
|
|
|
// "current" type.
|
|
|
|
return mergeTypeInfo(OldTy, 0);
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
2002-11-06 14:20:27 +08:00
|
|
|
|
2002-11-07 12:59:28 +08:00
|
|
|
assert(Offset <= Size &&
|
2002-11-06 14:20:27 +08:00
|
|
|
"Cannot merge something into a part of our type that doesn't exist!");
|
|
|
|
|
2002-11-19 05:44:46 +08:00
|
|
|
// Find the section of Ty that NewTy overlaps with... first we find the
|
2002-11-06 14:20:27 +08:00
|
|
|
// type that starts at offset Offset.
|
2002-10-31 13:45:02 +08:00
|
|
|
//
|
2002-11-06 14:20:27 +08:00
|
|
|
unsigned O = 0;
|
2002-11-19 05:44:46 +08:00
|
|
|
const Type *SubType = Ty;
|
2002-11-06 14:20:27 +08:00
|
|
|
while (O < Offset) {
|
|
|
|
assert(Offset-O < TD.getTypeSize(SubType) && "Offset out of range!");
|
|
|
|
|
|
|
|
switch (SubType->getPrimitiveID()) {
|
|
|
|
case Type::StructTyID: {
|
|
|
|
const StructType *STy = cast<StructType>(SubType);
|
|
|
|
const StructLayout &SL = *TD.getStructLayout(STy);
|
|
|
|
|
|
|
|
unsigned i = 0, e = SL.MemberOffsets.size();
|
|
|
|
for (; i+1 < e && SL.MemberOffsets[i+1] <= Offset-O; ++i)
|
|
|
|
/* empty */;
|
|
|
|
|
|
|
|
// The offset we are looking for must be in the i'th element...
|
2004-02-09 12:37:31 +08:00
|
|
|
SubType = STy->getElementType(i);
|
2002-11-06 14:20:27 +08:00
|
|
|
O += SL.MemberOffsets[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Type::ArrayTyID: {
|
|
|
|
SubType = cast<ArrayType>(SubType)->getElementType();
|
|
|
|
unsigned ElSize = TD.getTypeSize(SubType);
|
|
|
|
unsigned Remainder = (Offset-O) % ElSize;
|
|
|
|
O = Offset-Remainder;
|
|
|
|
break;
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
2002-11-06 14:20:27 +08:00
|
|
|
default:
|
2003-03-04 01:13:31 +08:00
|
|
|
if (FoldIfIncompatible) foldNodeCompletely();
|
2003-02-04 03:12:15 +08:00
|
|
|
return true;
|
2002-11-06 14:20:27 +08:00
|
|
|
}
|
|
|
|
}
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
assert(O == Offset && "Could not achieve the correct offset!");
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// If we found our type exactly, early exit
|
|
|
|
if (SubType == NewTy) return false;
|
2002-10-31 13:45:02 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Differing function types don't require us to merge. They are not values anyway.
|
|
|
|
if (isa<FunctionType>(SubType) &&
|
|
|
|
isa<FunctionType>(NewTy)) return false;
|
|
|
|
|
2003-06-30 04:27:45 +08:00
|
|
|
unsigned SubTypeSize = SubType->isSized() ? TD.getTypeSize(SubType) : 0;
|
|
|
|
|
|
|
|
// Ok, we are getting desperate now. Check for physical subtyping, where we
|
|
|
|
// just require each element in the node to be compatible.
|
2003-06-30 06:36:31 +08:00
|
|
|
if (NewTySize <= SubTypeSize && NewTySize && NewTySize < 256 &&
|
2003-06-30 04:27:45 +08:00
|
|
|
SubTypeSize && SubTypeSize < 256 &&
|
2003-11-03 06:27:28 +08:00
|
|
|
ElementTypesAreCompatible(NewTy, SubType, !isArray(), TD))
|
2003-06-30 04:27:45 +08:00
|
|
|
return false;
|
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Okay, so we found the leader type at the offset requested. Search the list
|
|
|
|
// of types that starts at this offset. If SubType is currently an array or
|
|
|
|
// structure, the type desired may actually be the first element of the
|
|
|
|
// composite type...
|
|
|
|
//
|
2002-11-19 05:44:46 +08:00
|
|
|
unsigned PadSize = SubTypeSize; // Size, including pad memory which is ignored
|
2002-11-06 14:20:27 +08:00
|
|
|
while (SubType != NewTy) {
|
|
|
|
const Type *NextSubType = 0;
|
2002-11-09 08:49:05 +08:00
|
|
|
unsigned NextSubTypeSize = 0;
|
2002-11-19 05:44:46 +08:00
|
|
|
unsigned NextPadSize = 0;
|
2002-11-06 14:20:27 +08:00
|
|
|
switch (SubType->getPrimitiveID()) {
|
2002-11-19 05:44:46 +08:00
|
|
|
case Type::StructTyID: {
|
|
|
|
const StructType *STy = cast<StructType>(SubType);
|
|
|
|
const StructLayout &SL = *TD.getStructLayout(STy);
|
|
|
|
if (SL.MemberOffsets.size() > 1)
|
|
|
|
NextPadSize = SL.MemberOffsets[1];
|
|
|
|
else
|
|
|
|
NextPadSize = SubTypeSize;
|
2004-02-09 12:37:31 +08:00
|
|
|
NextSubType = STy->getElementType(0);
|
2002-11-19 05:44:46 +08:00
|
|
|
NextSubTypeSize = TD.getTypeSize(NextSubType);
|
2002-11-06 14:20:27 +08:00
|
|
|
break;
|
2002-11-19 05:44:46 +08:00
|
|
|
}
|
2002-11-06 14:20:27 +08:00
|
|
|
case Type::ArrayTyID:
|
|
|
|
NextSubType = cast<ArrayType>(SubType)->getElementType();
|
2002-11-19 05:44:46 +08:00
|
|
|
NextSubTypeSize = TD.getTypeSize(NextSubType);
|
|
|
|
NextPadSize = NextSubTypeSize;
|
2002-11-06 14:20:27 +08:00
|
|
|
break;
|
|
|
|
default: ;
|
|
|
|
// fall out
|
|
|
|
}
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
if (NextSubType == 0)
|
|
|
|
break; // In the default case, break out of the loop
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-19 05:44:46 +08:00
|
|
|
if (NextPadSize < NewTySize)
|
2002-11-06 14:20:27 +08:00
|
|
|
break; // Don't allow shrinking to a smaller type than NewTySize
|
|
|
|
SubType = NextSubType;
|
|
|
|
SubTypeSize = NextSubTypeSize;
|
2002-11-19 05:44:46 +08:00
|
|
|
PadSize = NextPadSize;
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// If we found the type exactly, return it...
|
|
|
|
if (SubType == NewTy)
|
|
|
|
return false;
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Check to see if we have a compatible, but different type...
|
|
|
|
if (NewTySize == SubTypeSize) {
|
2003-05-21 02:45:36 +08:00
|
|
|
// Check to see if this type is obviously convertible... int -> uint f.e.
|
|
|
|
if (NewTy->isLosslesslyConvertibleTo(SubType))
|
2002-11-06 14:20:27 +08:00
|
|
|
return false;
|
2002-10-31 13:45:02 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// Check to see if we have a pointer & integer mismatch going on here,
|
|
|
|
// loading a pointer as a long, for example.
|
2002-10-31 13:45:02 +08:00
|
|
|
//
|
2002-11-06 14:20:27 +08:00
|
|
|
if (SubType->isInteger() && isa<PointerType>(NewTy) ||
|
|
|
|
NewTy->isInteger() && isa<PointerType>(SubType))
|
|
|
|
return false;
|
2002-11-19 05:44:46 +08:00
|
|
|
} else if (NewTySize > SubTypeSize && NewTySize <= PadSize) {
|
|
|
|
// We are accessing the field, plus some structure padding. Ignore the
|
|
|
|
// structure padding.
|
|
|
|
return false;
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
2002-11-06 14:20:27 +08:00
|
|
|
|
2003-07-02 12:38:49 +08:00
|
|
|
Module *M = 0;
|
|
|
|
if (getParentGraph()->getReturnNodes().size())
|
|
|
|
M = getParentGraph()->getReturnNodes().begin()->first->getParent();
|
|
|
|
DEBUG(std::cerr << "MergeTypeInfo Folding OrigTy: ";
|
|
|
|
WriteTypeSymbolic(std::cerr, Ty, M) << "\n due to:";
|
|
|
|
WriteTypeSymbolic(std::cerr, NewTy, M) << " @ " << Offset << "!\n"
|
|
|
|
<< "SubType: ";
|
|
|
|
WriteTypeSymbolic(std::cerr, SubType, M) << "\n\n");
|
2002-11-06 14:20:27 +08:00
|
|
|
|
2003-03-04 01:13:31 +08:00
|
|
|
if (FoldIfIncompatible) foldNodeCompletely();
|
2002-11-06 14:20:27 +08:00
|
|
|
return true;
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
|
|
|
|
2002-04-05 03:21:27 +08:00
|
|
|
|
2002-11-05 08:01:58 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
// addEdgeTo - Add an edge from the current node to the specified node. This
|
|
|
|
// can cause merging of nodes in the graph.
|
|
|
|
//
|
|
|
|
void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
if (NH.isNull()) return; // Nothing to do
|
2002-10-02 12:57:39 +08:00
|
|
|
|
2002-11-06 14:20:27 +08:00
|
|
|
DSNodeHandle &ExistingEdge = getLink(Offset);
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
if (!ExistingEdge.isNull()) {
|
2002-11-06 14:20:27 +08:00
|
|
|
// Merge the two nodes...
|
|
|
|
ExistingEdge.mergeWith(NH);
|
|
|
|
} else { // No merging to perform...
|
|
|
|
setLink(Offset, NH); // Just force a link in there...
|
2002-10-02 12:57:39 +08:00
|
|
|
}
|
2002-03-27 06:39:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-02 06:33:50 +08:00
|
|
|
// MergeSortedVectors - Efficiently merge a vector into another vector where
|
|
|
|
// duplicates are not allowed and both are sorted. This assumes that 'T's are
|
|
|
|
// efficiently copyable and have sane comparison semantics.
|
2002-03-27 06:39:06 +08:00
|
|
|
//
|
2003-02-01 12:01:21 +08:00
|
|
|
static void MergeSortedVectors(std::vector<GlobalValue*> &Dest,
|
|
|
|
const std::vector<GlobalValue*> &Src) {
|
2002-10-02 06:33:50 +08:00
|
|
|
// By far, the most common cases will be the simple ones. In these cases,
|
|
|
|
// avoid having to allocate a temporary vector...
|
|
|
|
//
|
|
|
|
if (Src.empty()) { // Nothing to merge in...
|
|
|
|
return;
|
|
|
|
} else if (Dest.empty()) { // Just copy the result in...
|
|
|
|
Dest = Src;
|
|
|
|
} else if (Src.size() == 1) { // Insert a single element...
|
2002-11-19 05:44:46 +08:00
|
|
|
const GlobalValue *V = Src[0];
|
2003-02-01 12:01:21 +08:00
|
|
|
std::vector<GlobalValue*>::iterator I =
|
2002-10-02 06:33:50 +08:00
|
|
|
std::lower_bound(Dest.begin(), Dest.end(), V);
|
|
|
|
if (I == Dest.end() || *I != Src[0]) // If not already contained...
|
|
|
|
Dest.insert(I, Src[0]);
|
|
|
|
} else if (Dest.size() == 1) {
|
2002-11-19 05:44:46 +08:00
|
|
|
GlobalValue *Tmp = Dest[0]; // Save value in temporary...
|
2002-10-02 06:33:50 +08:00
|
|
|
Dest = Src; // Copy over list...
|
2003-02-01 12:01:21 +08:00
|
|
|
std::vector<GlobalValue*>::iterator I =
|
2002-11-12 15:20:45 +08:00
|
|
|
std::lower_bound(Dest.begin(), Dest.end(), Tmp);
|
|
|
|
if (I == Dest.end() || *I != Tmp) // If not already contained...
|
|
|
|
Dest.insert(I, Tmp);
|
2002-10-02 06:33:50 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Make a copy to the side of Dest...
|
2003-02-01 12:01:21 +08:00
|
|
|
std::vector<GlobalValue*> Old(Dest);
|
2002-10-02 06:33:50 +08:00
|
|
|
|
|
|
|
// Make space for all of the type entries now...
|
|
|
|
Dest.resize(Dest.size()+Src.size());
|
|
|
|
|
|
|
|
// Merge the two sorted ranges together... into Dest.
|
|
|
|
std::merge(Old.begin(), Old.end(), Src.begin(), Src.end(), Dest.begin());
|
|
|
|
|
|
|
|
// Now erase any duplicate entries that may have accumulated into the
|
|
|
|
// vectors (because they were in both of the input sets)
|
|
|
|
Dest.erase(std::unique(Dest.begin(), Dest.end()), Dest.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
void DSNode::mergeGlobals(const std::vector<GlobalValue*> &RHS) {
|
|
|
|
MergeSortedVectors(Globals, RHS);
|
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// MergeNodes - Helper function for DSNode::mergeWith().
|
2002-12-07 05:15:21 +08:00
|
|
|
// This function does the hard work of merging two nodes, CurNodeH
|
|
|
|
// and NH after filtering out trivial cases and making sure that
|
|
|
|
// CurNodeH.offset >= NH.offset.
|
|
|
|
//
|
|
|
|
// ***WARNING***
|
|
|
|
// Since merging may cause either node to go away, we must always
|
|
|
|
// use the node-handles to refer to the nodes. These node handles are
|
|
|
|
// automatically updated during merging, so will always provide access
|
|
|
|
// to the correct node after a merge.
|
2002-10-02 06:33:50 +08:00
|
|
|
//
|
2002-12-07 05:15:21 +08:00
|
|
|
void DSNode::MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH) {
|
|
|
|
assert(CurNodeH.getOffset() >= NH.getOffset() &&
|
|
|
|
"This should have been enforced in the caller.");
|
2002-11-12 15:20:45 +08:00
|
|
|
|
|
|
|
// Now we know that Offset >= NH.Offset, so convert it so our "Offset" (with
|
|
|
|
// respect to NH.Offset) is now zero. NOffset is the distance from the base
|
|
|
|
// of our object that N starts from.
|
|
|
|
//
|
2002-12-07 05:15:21 +08:00
|
|
|
unsigned NOffset = CurNodeH.getOffset()-NH.getOffset();
|
|
|
|
unsigned NSize = NH.getNode()->getSize();
|
2002-11-12 15:20:45 +08:00
|
|
|
|
2003-06-30 04:27:45 +08:00
|
|
|
// If the two nodes are of different size, and the smaller node has the array
|
|
|
|
// bit set, collapse!
|
|
|
|
if (NSize != CurNodeH.getNode()->getSize()) {
|
|
|
|
if (NSize < CurNodeH.getNode()->getSize()) {
|
|
|
|
if (NH.getNode()->isArray())
|
|
|
|
NH.getNode()->foldNodeCompletely();
|
|
|
|
} else if (CurNodeH.getNode()->isArray()) {
|
|
|
|
NH.getNode()->foldNodeCompletely();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge the type entries of the two nodes together...
|
2003-02-12 07:11:51 +08:00
|
|
|
if (NH.getNode()->Ty != Type::VoidTy)
|
2002-12-07 05:15:21 +08:00
|
|
|
CurNodeH.getNode()->mergeTypeInfo(NH.getNode()->Ty, NOffset);
|
2003-06-20 05:15:11 +08:00
|
|
|
assert(!CurNodeH.getNode()->isDeadNode());
|
2002-11-09 05:27:12 +08:00
|
|
|
|
2002-10-31 13:45:02 +08:00
|
|
|
// If we are merging a node with a completely folded node, then both nodes are
|
|
|
|
// now completely folded.
|
|
|
|
//
|
2002-12-07 05:15:21 +08:00
|
|
|
if (CurNodeH.getNode()->isNodeCompletelyFolded()) {
|
|
|
|
if (!NH.getNode()->isNodeCompletelyFolded()) {
|
|
|
|
NH.getNode()->foldNodeCompletely();
|
2003-02-12 07:11:51 +08:00
|
|
|
assert(NH.getNode() && NH.getOffset() == 0 &&
|
|
|
|
"folding did not make offset 0?");
|
2002-12-07 05:15:21 +08:00
|
|
|
NOffset = NH.getOffset();
|
|
|
|
NSize = NH.getNode()->getSize();
|
|
|
|
assert(NOffset == 0 && NSize == 1);
|
2002-11-09 05:27:12 +08:00
|
|
|
}
|
2002-12-07 05:15:21 +08:00
|
|
|
} else if (NH.getNode()->isNodeCompletelyFolded()) {
|
|
|
|
CurNodeH.getNode()->foldNodeCompletely();
|
2003-02-12 07:11:51 +08:00
|
|
|
assert(CurNodeH.getNode() && CurNodeH.getOffset() == 0 &&
|
|
|
|
"folding did not make offset 0?");
|
2002-11-12 15:20:45 +08:00
|
|
|
NOffset = NH.getOffset();
|
2002-12-07 05:15:21 +08:00
|
|
|
NSize = NH.getNode()->getSize();
|
|
|
|
assert(NOffset == 0 && NSize == 1);
|
2002-10-31 13:45:02 +08:00
|
|
|
}
|
|
|
|
|
2003-02-12 07:11:51 +08:00
|
|
|
DSNode *N = NH.getNode();
|
|
|
|
if (CurNodeH.getNode() == N || N == 0) return;
|
2003-06-20 05:15:11 +08:00
|
|
|
assert(!CurNodeH.getNode()->isDeadNode());
|
2002-10-02 06:33:50 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Merge the NodeType information.
|
2003-02-12 07:11:51 +08:00
|
|
|
CurNodeH.getNode()->NodeType |= N->NodeType;
|
2003-06-20 05:15:11 +08:00
|
|
|
|
|
|
|
// Start forwarding to the new node!
|
2003-02-12 07:11:51 +08:00
|
|
|
N->forwardNode(CurNodeH.getNode(), NOffset);
|
2003-06-20 05:15:11 +08:00
|
|
|
assert(!CurNodeH.getNode()->isDeadNode());
|
2002-12-07 05:15:21 +08:00
|
|
|
|
2003-02-12 07:11:51 +08:00
|
|
|
// Make all of the outgoing links of N now be outgoing links of CurNodeH.
|
|
|
|
//
|
|
|
|
for (unsigned i = 0; i < N->getNumLinks(); ++i) {
|
|
|
|
DSNodeHandle &Link = N->getLink(i << DS::PointerShift);
|
2002-11-06 14:20:27 +08:00
|
|
|
if (Link.getNode()) {
|
2002-12-06 01:17:26 +08:00
|
|
|
// Compute the offset into the current node at which to
|
|
|
|
// merge this link. In the common case, this is a linear
|
|
|
|
// relation to the offset in the original node (with
|
|
|
|
// wrapping), but if the current node gets collapsed due to
|
|
|
|
// recursive merging, we must make sure to merge in all remaining
|
|
|
|
// links at offset zero.
|
|
|
|
unsigned MergeOffset = 0;
|
2003-02-12 07:11:51 +08:00
|
|
|
DSNode *CN = CurNodeH.getNode();
|
|
|
|
if (CN->Size != 1)
|
|
|
|
MergeOffset = ((i << DS::PointerShift)+NOffset) % CN->getSize();
|
|
|
|
CN->addEdgeTo(MergeOffset, Link);
|
2002-10-02 12:57:39 +08:00
|
|
|
}
|
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
|
|
|
|
// Now that there are no outgoing edges, all of the Links are dead.
|
2003-02-12 07:11:51 +08:00
|
|
|
N->Links.clear();
|
2002-07-12 04:32:22 +08:00
|
|
|
|
2002-10-02 06:33:50 +08:00
|
|
|
// Merge the globals list...
|
2003-02-12 07:11:51 +08:00
|
|
|
if (!N->Globals.empty()) {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
CurNodeH.getNode()->mergeGlobals(N->Globals);
|
2002-07-18 08:12:30 +08:00
|
|
|
|
|
|
|
// Delete the globals from the old node...
|
2003-02-12 07:11:51 +08:00
|
|
|
std::vector<GlobalValue*>().swap(N->Globals);
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
2002-03-27 06:39:06 +08:00
|
|
|
}
|
|
|
|
|
2002-12-07 05:15:21 +08:00
|
|
|
|
|
|
|
// mergeWith - Merge this node and the specified node, moving all links to and
|
|
|
|
// from the argument node into the current node, deleting the node argument.
|
|
|
|
// Offset indicates what offset the specified node is to be merged into the
|
|
|
|
// current node.
|
|
|
|
//
|
2004-01-23 00:31:08 +08:00
|
|
|
// The specified node may be a null pointer (in which case, we update it to
|
|
|
|
// point to this node).
|
2002-12-07 05:15:21 +08:00
|
|
|
//
|
|
|
|
void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
|
|
|
|
DSNode *N = NH.getNode();
|
2004-01-23 00:31:08 +08:00
|
|
|
if (N == this && NH.getOffset() == Offset)
|
2002-12-07 05:15:21 +08:00
|
|
|
return; // Noop
|
|
|
|
|
2004-01-23 00:31:08 +08:00
|
|
|
// If the RHS is a null node, make it point to this node!
|
|
|
|
if (N == 0) {
|
|
|
|
NH.mergeWith(DSNodeHandle(this, Offset));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-06-20 05:15:11 +08:00
|
|
|
assert(!N->isDeadNode() && !isDeadNode());
|
2002-12-07 05:15:21 +08:00
|
|
|
assert(!hasNoReferrers() && "Should not try to fold a useless node!");
|
|
|
|
|
|
|
|
if (N == this) {
|
|
|
|
// We cannot merge two pieces of the same node together, collapse the node
|
|
|
|
// completely.
|
|
|
|
DEBUG(std::cerr << "Attempting to merge two chunks of"
|
|
|
|
<< " the same node together!\n");
|
|
|
|
foldNodeCompletely();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If both nodes are not at offset 0, make sure that we are merging the node
|
|
|
|
// at an later offset into the node with the zero offset.
|
|
|
|
//
|
|
|
|
if (Offset < NH.getOffset()) {
|
|
|
|
N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
|
|
|
|
return;
|
|
|
|
} else if (Offset == NH.getOffset() && getSize() < N->getSize()) {
|
|
|
|
// If the offsets are the same, merge the smaller node into the bigger node
|
|
|
|
N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ok, now we can merge the two nodes. Use a static helper that works with
|
|
|
|
// two node handles, since "this" may get merged away at intermediate steps.
|
|
|
|
DSNodeHandle CurNodeH(this, Offset);
|
|
|
|
DSNodeHandle NHCopy(NH);
|
|
|
|
DSNode::MergeNodes(CurNodeH, NHCopy);
|
|
|
|
}
|
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ReachabilityCloner Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
DSNodeHandle ReachabilityCloner::getClonedNH(const DSNodeHandle &SrcNH) {
|
|
|
|
if (SrcNH.isNull()) return DSNodeHandle();
|
|
|
|
const DSNode *SN = SrcNH.getNode();
|
|
|
|
|
|
|
|
DSNodeHandle &NH = NodeMap[SN];
|
|
|
|
if (!NH.isNull()) // Node already mapped?
|
|
|
|
return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset());
|
|
|
|
|
|
|
|
DSNode *DN = new DSNode(*SN, &Dest, true /* Null out all links */);
|
|
|
|
DN->maskNodeTypes(BitsToKeep);
|
2004-01-28 10:05:05 +08:00
|
|
|
NH = DN;
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
// Next, recursively clone all outgoing links as necessary. Note that
|
|
|
|
// adding these links can cause the node to collapse itself at any time, and
|
|
|
|
// the current node may be merged with arbitrary other nodes. For this
|
|
|
|
// reason, we must always go through NH.
|
|
|
|
DN = 0;
|
|
|
|
for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) {
|
|
|
|
const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift);
|
|
|
|
if (!SrcEdge.isNull()) {
|
|
|
|
const DSNodeHandle &DestEdge = getClonedNH(SrcEdge);
|
|
|
|
// Compute the offset into the current node at which to
|
|
|
|
// merge this link. In the common case, this is a linear
|
|
|
|
// relation to the offset in the original node (with
|
|
|
|
// wrapping), but if the current node gets collapsed due to
|
|
|
|
// recursive merging, we must make sure to merge in all remaining
|
|
|
|
// links at offset zero.
|
|
|
|
unsigned MergeOffset = 0;
|
|
|
|
DSNode *CN = NH.getNode();
|
|
|
|
if (CN->getSize() != 1)
|
|
|
|
MergeOffset = ((i << DS::PointerShift)+NH.getOffset()
|
|
|
|
- SrcNH.getOffset()) %CN->getSize();
|
|
|
|
CN->addEdgeTo(MergeOffset, DestEdge);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this node contains any globals, make sure they end up in the scalar
|
|
|
|
// map with the correct offset.
|
|
|
|
for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
GlobalValue *GV = *I;
|
|
|
|
const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV);
|
|
|
|
DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()];
|
|
|
|
assert(DestGNH.getNode() == NH.getNode() &&"Global mapping inconsistent");
|
|
|
|
Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),
|
2004-01-28 10:05:05 +08:00
|
|
|
DestGNH.getOffset()+SrcGNH.getOffset()));
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
if (CloneFlags & DSGraph::UpdateInlinedGlobals)
|
|
|
|
Dest.getInlinedGlobals().insert(GV);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReachabilityCloner::merge(const DSNodeHandle &NH,
|
|
|
|
const DSNodeHandle &SrcNH) {
|
|
|
|
if (SrcNH.isNull()) return; // Noop
|
|
|
|
if (NH.isNull()) {
|
|
|
|
// If there is no destination node, just clone the source and assign the
|
|
|
|
// destination node to be it.
|
|
|
|
NH.mergeWith(getClonedNH(SrcNH));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, at this point, we know that we have both a destination and a source
|
|
|
|
// node that need to be merged. Check to see if the source node has already
|
|
|
|
// been cloned.
|
|
|
|
const DSNode *SN = SrcNH.getNode();
|
|
|
|
DSNodeHandle &SCNH = NodeMap[SN]; // SourceClonedNodeHandle
|
2004-02-22 08:53:54 +08:00
|
|
|
if (!SCNH.isNull()) { // Node already cloned?
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
NH.mergeWith(DSNodeHandle(SCNH.getNode(),
|
|
|
|
SCNH.getOffset()+SrcNH.getOffset()));
|
|
|
|
|
|
|
|
return; // Nothing to do!
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, so the source node has not already been cloned. Instead of creating
|
|
|
|
// a new DSNode, only to merge it into the one we already have, try to perform
|
|
|
|
// the merge in-place. The only case we cannot handle here is when the offset
|
|
|
|
// into the existing node is less than the offset into the virtual node we are
|
|
|
|
// merging in. In this case, we have to extend the existing node, which
|
|
|
|
// requires an allocation anyway.
|
|
|
|
DSNode *DN = NH.getNode(); // Make sure the Offset is up-to-date
|
|
|
|
if (NH.getOffset() >= SrcNH.getOffset()) {
|
|
|
|
if (!DN->isNodeCompletelyFolded()) {
|
|
|
|
// Make sure the destination node is folded if the source node is folded.
|
|
|
|
if (SN->isNodeCompletelyFolded()) {
|
|
|
|
DN->foldNodeCompletely();
|
|
|
|
DN = NH.getNode();
|
|
|
|
} else if (SN->getSize() != DN->getSize()) {
|
|
|
|
// If the two nodes are of different size, and the smaller node has the
|
|
|
|
// array bit set, collapse!
|
|
|
|
if (SN->getSize() < DN->getSize()) {
|
|
|
|
if (SN->isArray()) {
|
|
|
|
DN->foldNodeCompletely();
|
|
|
|
DN = NH.getNode();
|
|
|
|
}
|
|
|
|
} else if (DN->isArray()) {
|
|
|
|
DN->foldNodeCompletely();
|
|
|
|
DN = NH.getNode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge the type entries of the two nodes together...
|
|
|
|
if (SN->getType() != Type::VoidTy && !DN->isNodeCompletelyFolded()) {
|
|
|
|
DN->mergeTypeInfo(SN->getType(), NH.getOffset()-SrcNH.getOffset());
|
|
|
|
DN = NH.getNode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!DN->isDeadNode());
|
|
|
|
|
|
|
|
// Merge the NodeType information.
|
|
|
|
DN->mergeNodeFlags(SN->getNodeFlags() & BitsToKeep);
|
|
|
|
|
|
|
|
// Before we start merging outgoing links and updating the scalar map, make
|
|
|
|
// sure it is known that this is the representative node for the src node.
|
|
|
|
SCNH = DSNodeHandle(DN, NH.getOffset()-SrcNH.getOffset());
|
|
|
|
|
|
|
|
// If the source node contains any globals, make sure they end up in the
|
|
|
|
// scalar map with the correct offset.
|
|
|
|
if (SN->global_begin() != SN->global_end()) {
|
|
|
|
// Update the globals in the destination node itself.
|
|
|
|
DN->mergeGlobals(SN->getGlobals());
|
|
|
|
|
|
|
|
// Update the scalar map for the graph we are merging the source node
|
|
|
|
// into.
|
|
|
|
for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
GlobalValue *GV = *I;
|
|
|
|
const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV);
|
|
|
|
DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()];
|
|
|
|
assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent");
|
|
|
|
Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),
|
2004-01-29 16:36:22 +08:00
|
|
|
DestGNH.getOffset()+SrcGNH.getOffset()));
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
if (CloneFlags & DSGraph::UpdateInlinedGlobals)
|
|
|
|
Dest.getInlinedGlobals().insert(GV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We cannot handle this case without allocating a temporary node. Fall
|
|
|
|
// back on being simple.
|
|
|
|
DSNode *NewDN = new DSNode(*SN, &Dest, true /* Null out all links */);
|
|
|
|
NewDN->maskNodeTypes(BitsToKeep);
|
|
|
|
|
|
|
|
unsigned NHOffset = NH.getOffset();
|
|
|
|
NH.mergeWith(DSNodeHandle(NewDN, SrcNH.getOffset()));
|
2004-01-29 16:36:22 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
assert(NH.getNode() &&
|
|
|
|
(NH.getOffset() > NHOffset ||
|
|
|
|
(NH.getOffset() == 0 && NH.getNode()->isNodeCompletelyFolded())) &&
|
|
|
|
"Merging did not adjust the offset!");
|
|
|
|
|
|
|
|
// Before we start merging outgoing links and updating the scalar map, make
|
|
|
|
// sure it is known that this is the representative node for the src node.
|
|
|
|
SCNH = DSNodeHandle(NH.getNode(), NH.getOffset()-SrcNH.getOffset());
|
2004-01-29 16:36:22 +08:00
|
|
|
|
|
|
|
// If the source node contained any globals, make sure to create entries
|
|
|
|
// in the scalar map for them!
|
|
|
|
for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
GlobalValue *GV = *I;
|
|
|
|
const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV);
|
|
|
|
DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()];
|
|
|
|
assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent");
|
|
|
|
assert(SrcGNH.getNode() == SN && "Global mapping inconsistent");
|
|
|
|
Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),
|
|
|
|
DestGNH.getOffset()+SrcGNH.getOffset()));
|
|
|
|
|
|
|
|
if (CloneFlags & DSGraph::UpdateInlinedGlobals)
|
|
|
|
Dest.getInlinedGlobals().insert(GV);
|
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Next, recursively merge all outgoing links as necessary. Note that
|
|
|
|
// adding these links can cause the destination node to collapse itself at
|
|
|
|
// any time, and the current node may be merged with arbitrary other nodes.
|
|
|
|
// For this reason, we must always go through NH.
|
|
|
|
DN = 0;
|
|
|
|
for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) {
|
|
|
|
const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift);
|
|
|
|
if (!SrcEdge.isNull()) {
|
|
|
|
// Compute the offset into the current node at which to
|
|
|
|
// merge this link. In the common case, this is a linear
|
|
|
|
// relation to the offset in the original node (with
|
|
|
|
// wrapping), but if the current node gets collapsed due to
|
|
|
|
// recursive merging, we must make sure to merge in all remaining
|
|
|
|
// links at offset zero.
|
|
|
|
unsigned MergeOffset = 0;
|
|
|
|
DSNode *CN = SCNH.getNode();
|
|
|
|
if (CN->getSize() != 1)
|
|
|
|
MergeOffset = ((i << DS::PointerShift)+SCNH.getOffset()) %CN->getSize();
|
|
|
|
|
2004-02-22 08:53:54 +08:00
|
|
|
DSNodeHandle &Link = CN->getLink(MergeOffset);
|
|
|
|
if (!Link.isNull()) {
|
|
|
|
// Perform the recursive merging. Make sure to create a temporary NH,
|
|
|
|
// because the Link can disappear in the process of recursive merging.
|
|
|
|
DSNodeHandle Tmp = Link;
|
|
|
|
merge(Tmp, SrcEdge);
|
|
|
|
} else {
|
|
|
|
merge(Link, SrcEdge);
|
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// mergeCallSite - Merge the nodes reachable from the specified src call
|
|
|
|
/// site into the nodes reachable from DestCS.
|
|
|
|
void ReachabilityCloner::mergeCallSite(const DSCallSite &DestCS,
|
|
|
|
const DSCallSite &SrcCS) {
|
|
|
|
merge(DestCS.getRetVal(), SrcCS.getRetVal());
|
|
|
|
unsigned MinArgs = DestCS.getNumPtrArgs();
|
|
|
|
if (SrcCS.getNumPtrArgs() < MinArgs) MinArgs = SrcCS.getNumPtrArgs();
|
|
|
|
|
|
|
|
for (unsigned a = 0; a != MinArgs; ++a)
|
|
|
|
merge(DestCS.getPtrArg(a), SrcCS.getPtrArg(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-10-21 06:11:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DSCallSite Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2002-10-21 05:41:02 +08:00
|
|
|
// Define here to avoid including iOther.h and BasicBlock.h in DSGraph.h
|
2002-10-21 06:11:44 +08:00
|
|
|
Function &DSCallSite::getCaller() const {
|
2003-09-21 00:34:13 +08:00
|
|
|
return *Site.getInstruction()->getParent()->getParent();
|
2002-10-21 05:41:02 +08:00
|
|
|
}
|
2002-10-21 02:07:37 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
void DSCallSite::InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
|
|
|
|
ReachabilityCloner &RC) {
|
|
|
|
NH = RC.getClonedNH(Src);
|
|
|
|
}
|
2002-10-21 02:07:37 +08:00
|
|
|
|
2002-07-11 06:38:08 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DSGraph Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2002-03-29 01:56:03 +08:00
|
|
|
|
2003-06-30 13:57:30 +08:00
|
|
|
/// getFunctionNames - Return a space separated list of the name of the
|
|
|
|
/// functions in this graph (if any)
|
|
|
|
std::string DSGraph::getFunctionNames() const {
|
|
|
|
switch (getReturnNodes().size()) {
|
|
|
|
case 0: return "Globals graph";
|
|
|
|
case 1: return getReturnNodes().begin()->first->getName();
|
|
|
|
default:
|
|
|
|
std::string Return;
|
|
|
|
for (DSGraph::ReturnNodesTy::const_iterator I = getReturnNodes().begin();
|
|
|
|
I != getReturnNodes().end(); ++I)
|
|
|
|
Return += I->first->getName() + " ";
|
|
|
|
Return.erase(Return.end()-1, Return.end()); // Remove last space character
|
|
|
|
return Return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-03 06:27:28 +08:00
|
|
|
DSGraph::DSGraph(const DSGraph &G) : GlobalsGraph(0), TD(G.TD) {
|
2002-11-10 14:59:55 +08:00
|
|
|
PrintAuxCalls = false;
|
2003-06-30 11:15:25 +08:00
|
|
|
NodeMapTy NodeMap;
|
|
|
|
cloneInto(G, ScalarMap, ReturnNodes, NodeMap);
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
2003-06-30 11:15:25 +08:00
|
|
|
DSGraph::DSGraph(const DSGraph &G, NodeMapTy &NodeMap)
|
2003-11-03 06:27:28 +08:00
|
|
|
: GlobalsGraph(0), TD(G.TD) {
|
2002-11-10 14:59:55 +08:00
|
|
|
PrintAuxCalls = false;
|
2003-06-30 11:15:25 +08:00
|
|
|
cloneInto(G, ScalarMap, ReturnNodes, NodeMap);
|
2002-10-21 23:32:34 +08:00
|
|
|
}
|
|
|
|
|
2002-07-11 06:38:08 +08:00
|
|
|
DSGraph::~DSGraph() {
|
|
|
|
FunctionCalls.clear();
|
2002-11-09 05:27:12 +08:00
|
|
|
AuxFunctionCalls.clear();
|
2003-07-17 05:36:31 +08:00
|
|
|
InlinedGlobals.clear();
|
2002-11-04 05:27:48 +08:00
|
|
|
ScalarMap.clear();
|
2003-06-30 11:15:25 +08:00
|
|
|
ReturnNodes.clear();
|
2002-03-29 01:56:03 +08:00
|
|
|
|
2002-07-11 06:38:08 +08:00
|
|
|
// Drop all intra-node references, so that assertions don't fail...
|
2004-02-08 08:53:26 +08:00
|
|
|
for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI)
|
|
|
|
(*NI)->dropAllReferences();
|
2002-03-29 01:56:03 +08:00
|
|
|
|
2004-02-08 08:53:26 +08:00
|
|
|
// Free all of the nodes.
|
|
|
|
Nodes.clear();
|
2002-03-29 01:56:03 +08:00
|
|
|
}
|
|
|
|
|
2002-07-18 08:12:30 +08:00
|
|
|
// dump - Allow inspection of graph in a debugger.
|
|
|
|
void DSGraph::dump() const { print(std::cerr); }
|
|
|
|
|
2002-10-21 02:07:37 +08:00
|
|
|
|
2002-10-02 06:33:50 +08:00
|
|
|
/// remapLinks - Change all of the Links in the current node according to the
|
|
|
|
/// specified mapping.
|
2002-10-31 13:45:02 +08:00
|
|
|
///
|
2003-06-30 11:36:09 +08:00
|
|
|
void DSNode::remapLinks(DSGraph::NodeMapTy &OldNodeMap) {
|
2004-01-23 00:56:13 +08:00
|
|
|
for (unsigned i = 0, e = Links.size(); i != e; ++i)
|
|
|
|
if (DSNode *N = Links[i].getNode()) {
|
2004-01-23 09:44:53 +08:00
|
|
|
DSGraph::NodeMapTy::const_iterator ONMI = OldNodeMap.find(N);
|
|
|
|
if (ONMI != OldNodeMap.end()) {
|
|
|
|
Links[i].setNode(ONMI->second.getNode());
|
|
|
|
Links[i].setOffset(Links[i].getOffset()+ONMI->second.getOffset());
|
|
|
|
}
|
2004-01-23 00:56:13 +08:00
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
}
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2003-07-17 05:36:31 +08:00
|
|
|
/// updateFromGlobalGraph - This function rematerializes global nodes and
|
|
|
|
/// nodes reachable from them from the globals graph into the current graph.
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
/// It uses the vector InlinedGlobals to avoid cloning and merging globals that
|
|
|
|
/// are already up-to-date in the current graph. In practice, in the TD pass,
|
|
|
|
/// this is likely to be a large fraction of the live global nodes in each
|
|
|
|
/// function (since most live nodes are likely to have been brought up-to-date
|
|
|
|
/// in at _some_ caller or callee).
|
2003-07-17 05:36:31 +08:00
|
|
|
///
|
|
|
|
void DSGraph::updateFromGlobalGraph() {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
TIME_REGION(X, "updateFromGlobalGraph");
|
|
|
|
ReachabilityCloner RC(*this, *GlobalsGraph, 0);
|
2003-07-17 05:36:31 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Clone the non-up-to-date global nodes into this graph.
|
2004-01-28 11:03:06 +08:00
|
|
|
for (DSScalarMap::global_iterator I = getScalarMap().global_begin(),
|
|
|
|
E = getScalarMap().global_end(); I != E; ++I)
|
|
|
|
if (InlinedGlobals.count(*I) == 0) { // GNode is not up-to-date
|
2004-01-28 17:15:42 +08:00
|
|
|
DSScalarMap::iterator It = GlobalsGraph->ScalarMap.find(*I);
|
2004-01-28 11:03:06 +08:00
|
|
|
if (It != GlobalsGraph->ScalarMap.end())
|
|
|
|
RC.merge(getNodeForValue(*I), It->second);
|
|
|
|
}
|
2003-07-17 05:36:31 +08:00
|
|
|
}
|
|
|
|
|
2003-06-30 11:15:25 +08:00
|
|
|
/// cloneInto - Clone the specified DSGraph into the current graph. The
|
|
|
|
/// translated ScalarMap for the old function is filled into the OldValMap
|
|
|
|
/// member, and the translated ReturnNodes map is returned into ReturnNodes.
|
|
|
|
///
|
|
|
|
/// The CloneFlags member controls various aspects of the cloning process.
|
|
|
|
///
|
2004-01-28 17:15:42 +08:00
|
|
|
void DSGraph::cloneInto(const DSGraph &G, DSScalarMap &OldValMap,
|
2003-06-30 11:15:25 +08:00
|
|
|
ReturnNodesTy &OldReturnNodes, NodeMapTy &OldNodeMap,
|
|
|
|
unsigned CloneFlags) {
|
2004-01-23 00:36:28 +08:00
|
|
|
TIME_REGION(X, "cloneInto");
|
2002-10-02 06:33:50 +08:00
|
|
|
assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!");
|
2002-11-08 09:21:07 +08:00
|
|
|
assert(&G != this && "Cannot clone graph into itself!");
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2003-02-04 04:08:51 +08:00
|
|
|
// Remove alloca or mod/ref bits as specified...
|
2003-07-17 05:36:31 +08:00
|
|
|
unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0)
|
|
|
|
| ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0)
|
|
|
|
| ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0);
|
2003-06-20 05:15:11 +08:00
|
|
|
BitsToClear |= DSNode::DEAD; // Clear dead flag...
|
2004-02-08 08:23:16 +08:00
|
|
|
|
2004-02-22 06:28:26 +08:00
|
|
|
for (node_iterator I = G.node_begin(), E = G.node_end(); I != E; ++I) {
|
|
|
|
assert(!(*I)->isForwarding() &&
|
|
|
|
"Forward nodes shouldn't be in node list!");
|
|
|
|
DSNode *New = new DSNode(**I, this);
|
|
|
|
New->maskNodeTypes(~BitsToClear);
|
|
|
|
OldNodeMap[*I] = New;
|
|
|
|
}
|
|
|
|
|
2002-11-19 05:44:46 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
Timer::addPeakMemoryMeasurement();
|
|
|
|
#endif
|
2004-02-22 06:28:26 +08:00
|
|
|
|
2002-07-31 06:05:22 +08:00
|
|
|
// Rewrite the links in the new nodes to point into the current graph now.
|
2004-02-22 06:28:26 +08:00
|
|
|
// Note that we don't loop over the node's list to do this. The problem is
|
|
|
|
// that remaping links can cause recursive merging to happen, which means
|
|
|
|
// that node_iterator's can get easily invalidated! Because of this, we
|
|
|
|
// loop over the OldNodeMap, which contains all of the new nodes as the
|
|
|
|
// .second element of the map elements. Also note that if we remap a node
|
|
|
|
// more than once, we won't break anything.
|
|
|
|
for (NodeMapTy::iterator I = OldNodeMap.begin(), E = OldNodeMap.end();
|
|
|
|
I != E; ++I)
|
|
|
|
I->second.getNode()->remapLinks(OldNodeMap);
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
// Copy the scalar map... merging all of the global nodes...
|
2004-01-28 17:15:42 +08:00
|
|
|
for (DSScalarMap::const_iterator I = G.ScalarMap.begin(),
|
2002-11-04 05:27:48 +08:00
|
|
|
E = G.ScalarMap.end(); I != E; ++I) {
|
2002-11-08 13:01:14 +08:00
|
|
|
DSNodeHandle &MappedNode = OldNodeMap[I->second.getNode()];
|
2003-06-30 13:09:29 +08:00
|
|
|
DSNodeHandle &H = OldValMap[I->first];
|
|
|
|
H.mergeWith(DSNodeHandle(MappedNode.getNode(),
|
|
|
|
I->second.getOffset()+MappedNode.getOffset()));
|
2002-10-18 04:09:52 +08:00
|
|
|
|
2003-06-30 13:09:29 +08:00
|
|
|
// If this is a global, add the global to this fn or merge if already exists
|
2003-07-17 05:36:31 +08:00
|
|
|
if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) {
|
|
|
|
ScalarMap[GV].mergeWith(H);
|
2004-01-23 09:44:53 +08:00
|
|
|
if (CloneFlags & DSGraph::UpdateInlinedGlobals)
|
|
|
|
InlinedGlobals.insert(GV);
|
2003-07-17 05:36:31 +08:00
|
|
|
}
|
2002-10-18 04:09:52 +08:00
|
|
|
}
|
2002-10-02 06:33:50 +08:00
|
|
|
|
2002-11-09 05:27:12 +08:00
|
|
|
if (!(CloneFlags & DontCloneCallNodes)) {
|
|
|
|
// Copy the function calls list...
|
|
|
|
unsigned FC = FunctionCalls.size(); // FirstCall
|
|
|
|
FunctionCalls.reserve(FC+G.FunctionCalls.size());
|
|
|
|
for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i)
|
|
|
|
FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap));
|
2002-11-09 06:27:09 +08:00
|
|
|
}
|
2002-11-09 05:27:12 +08:00
|
|
|
|
2002-11-09 06:27:09 +08:00
|
|
|
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
2003-09-12 02:14:24 +08:00
|
|
|
// Copy the auxiliary function calls list...
|
2002-11-09 06:27:09 +08:00
|
|
|
unsigned FC = AuxFunctionCalls.size(); // FirstCall
|
2002-11-09 05:27:12 +08:00
|
|
|
AuxFunctionCalls.reserve(FC+G.AuxFunctionCalls.size());
|
|
|
|
for (unsigned i = 0, ei = G.AuxFunctionCalls.size(); i != ei; ++i)
|
|
|
|
AuxFunctionCalls.push_back(DSCallSite(G.AuxFunctionCalls[i], OldNodeMap));
|
|
|
|
}
|
2002-10-18 04:09:52 +08:00
|
|
|
|
2003-06-30 11:15:25 +08:00
|
|
|
// Map the return node pointers over...
|
|
|
|
for (ReturnNodesTy::const_iterator I = G.getReturnNodes().begin(),
|
|
|
|
E = G.getReturnNodes().end(); I != E; ++I) {
|
|
|
|
const DSNodeHandle &Ret = I->second;
|
|
|
|
DSNodeHandle &MappedRet = OldNodeMap[Ret.getNode()];
|
|
|
|
OldReturnNodes.insert(std::make_pair(I->first,
|
|
|
|
DSNodeHandle(MappedRet.getNode(),
|
|
|
|
MappedRet.getOffset()+Ret.getOffset())));
|
|
|
|
}
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
2004-01-22 23:30:58 +08:00
|
|
|
|
2002-11-07 14:31:54 +08:00
|
|
|
/// mergeInGraph - The method is used for merging graphs together. If the
|
|
|
|
/// argument graph is not *this, it makes a clone of the specified graph, then
|
|
|
|
/// merges the nodes specified in the call site with the formal arguments in the
|
|
|
|
/// graph.
|
|
|
|
///
|
2003-06-30 13:27:18 +08:00
|
|
|
void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F,
|
|
|
|
const DSGraph &Graph, unsigned CloneFlags) {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
TIME_REGION(X, "mergeInGraph");
|
|
|
|
|
2004-03-04 04:55:27 +08:00
|
|
|
// Fastpath for a noop inline.
|
|
|
|
if (CS.getNumPtrArgs() == 0 && CS.getRetVal().isNull())
|
|
|
|
return;
|
|
|
|
|
2002-11-07 14:31:54 +08:00
|
|
|
// If this is not a recursive call, clone the graph into this graph...
|
|
|
|
if (&Graph != this) {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Clone the callee's graph into the current graph, keeping track of where
|
|
|
|
// scalars in the old graph _used_ to point, and of the new nodes matching
|
|
|
|
// nodes of the old graph.
|
|
|
|
ReachabilityCloner RC(*this, Graph, CloneFlags);
|
|
|
|
|
2004-01-22 23:30:58 +08:00
|
|
|
// Set up argument bindings
|
|
|
|
Function::aiterator AI = F.abegin();
|
|
|
|
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) {
|
|
|
|
// Advance the argument iterator to the first pointer argument...
|
|
|
|
while (AI != F.aend() && !isPointerType(AI->getType())) {
|
|
|
|
++AI;
|
2004-01-29 11:32:15 +08:00
|
|
|
#ifndef NDEBUG // FIXME: We should merge vararg arguments!
|
|
|
|
if (AI == F.aend() && !F.getFunctionType()->isVarArg())
|
2004-01-22 23:30:58 +08:00
|
|
|
std::cerr << "Bad call to Function: " << F.getName() << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (AI == F.aend()) break;
|
|
|
|
|
|
|
|
// Add the link from the argument scalar to the provided value.
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
RC.merge(CS.getPtrArg(i), Graph.getNodeForValue(AI));
|
2004-01-22 23:30:58 +08:00
|
|
|
}
|
2002-11-07 14:31:54 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Map the return node pointer over.
|
2004-02-22 08:53:54 +08:00
|
|
|
if (!CS.getRetVal().isNull())
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
RC.merge(CS.getRetVal(), Graph.getReturnNodeFor(F));
|
|
|
|
|
|
|
|
// If requested, copy the calls or aux-calls lists.
|
|
|
|
if (!(CloneFlags & DontCloneCallNodes)) {
|
|
|
|
// Copy the function calls list...
|
|
|
|
FunctionCalls.reserve(FunctionCalls.size()+Graph.FunctionCalls.size());
|
|
|
|
for (unsigned i = 0, ei = Graph.FunctionCalls.size(); i != ei; ++i)
|
|
|
|
FunctionCalls.push_back(DSCallSite(Graph.FunctionCalls[i], RC));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(CloneFlags & DontCloneAuxCallNodes)) {
|
|
|
|
// Copy the auxiliary function calls list...
|
|
|
|
AuxFunctionCalls.reserve(AuxFunctionCalls.size()+
|
|
|
|
Graph.AuxFunctionCalls.size());
|
|
|
|
for (unsigned i = 0, ei = Graph.AuxFunctionCalls.size(); i != ei; ++i)
|
|
|
|
AuxFunctionCalls.push_back(DSCallSite(Graph.AuxFunctionCalls[i], RC));
|
|
|
|
}
|
|
|
|
|
2004-02-28 04:05:15 +08:00
|
|
|
// Clone over all globals that appear in the caller and callee graphs.
|
|
|
|
for (DSScalarMap::global_iterator GI = Graph.getScalarMap().global_begin(),
|
|
|
|
E = Graph.getScalarMap().global_end(); GI != E; ++GI)
|
|
|
|
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(*GI))
|
|
|
|
if (ScalarMap.count(GV))
|
|
|
|
RC.merge(ScalarMap[GV], Graph.getNodeForValue(GV));
|
2004-01-22 23:30:58 +08:00
|
|
|
} else {
|
|
|
|
DSNodeHandle RetVal = getReturnNodeFor(F);
|
2002-12-07 05:15:21 +08:00
|
|
|
|
2004-01-22 23:30:58 +08:00
|
|
|
// Merge the return value with the return value of the context...
|
|
|
|
RetVal.mergeWith(CS.getRetVal());
|
|
|
|
|
|
|
|
// Resolve all of the function arguments...
|
|
|
|
Function::aiterator AI = F.abegin();
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) {
|
|
|
|
// Advance the argument iterator to the first pointer argument...
|
|
|
|
while (AI != F.aend() && !isPointerType(AI->getType())) {
|
|
|
|
++AI;
|
2004-01-29 11:32:15 +08:00
|
|
|
#ifndef NDEBUG // FIXME: We should merge varargs arguments!!
|
|
|
|
if (AI == F.aend() && !F.getFunctionType()->isVarArg())
|
2004-01-22 23:30:58 +08:00
|
|
|
std::cerr << "Bad call to Function: " << F.getName() << "\n";
|
2002-11-07 14:31:54 +08:00
|
|
|
#endif
|
2004-01-22 23:30:58 +08:00
|
|
|
}
|
|
|
|
if (AI == F.aend()) break;
|
|
|
|
|
|
|
|
// Add the link from the argument scalar to the provided value
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
DSNodeHandle &NH = getNodeForValue(AI);
|
2004-01-22 23:30:58 +08:00
|
|
|
assert(NH.getNode() && "Pointer argument without scalarmap entry?");
|
|
|
|
NH.mergeWith(CS.getPtrArg(i));
|
2002-11-07 14:31:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-02 12:38:49 +08:00
|
|
|
/// getCallSiteForArguments - Get the arguments and return value bindings for
|
|
|
|
/// the specified function in the current graph.
|
|
|
|
///
|
|
|
|
DSCallSite DSGraph::getCallSiteForArguments(Function &F) const {
|
|
|
|
std::vector<DSNodeHandle> Args;
|
|
|
|
|
|
|
|
for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
|
|
|
|
if (isPointerType(I->getType()))
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
Args.push_back(getNodeForValue(I));
|
2003-07-02 12:38:49 +08:00
|
|
|
|
2003-09-21 00:34:13 +08:00
|
|
|
return DSCallSite(CallSite(), getReturnNodeFor(F), &F, Args);
|
2003-07-02 12:38:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2002-07-18 08:12:30 +08:00
|
|
|
// markIncompleteNodes - Mark the specified node as having contents that are not
|
|
|
|
// known with the current analysis we have performed. Because a node makes all
|
2003-06-20 05:15:11 +08:00
|
|
|
// of the nodes it can reach incomplete if the node itself is incomplete, we
|
2002-07-18 08:12:30 +08:00
|
|
|
// must recursively traverse the data structure graph, marking all reachable
|
|
|
|
// nodes as incomplete.
|
|
|
|
//
|
|
|
|
static void markIncompleteNode(DSNode *N) {
|
|
|
|
// Stop recursion if no node, or if node already marked...
|
2003-06-29 05:58:28 +08:00
|
|
|
if (N == 0 || N->isIncomplete()) return;
|
2002-07-18 08:12:30 +08:00
|
|
|
|
|
|
|
// Actually mark the node
|
2003-06-20 05:15:11 +08:00
|
|
|
N->setIncompleteMarker();
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2003-09-12 02:14:24 +08:00
|
|
|
// Recursively process children...
|
2002-11-06 14:20:27 +08:00
|
|
|
for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
|
|
|
|
if (DSNode *DSN = N->getLink(i).getNode())
|
|
|
|
markIncompleteNode(DSN);
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
2002-11-11 11:36:55 +08:00
|
|
|
static void markIncomplete(DSCallSite &Call) {
|
|
|
|
// Then the return value is certainly incomplete!
|
|
|
|
markIncompleteNode(Call.getRetVal().getNode());
|
|
|
|
|
|
|
|
// All objects pointed to by function arguments are incomplete!
|
|
|
|
for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i)
|
|
|
|
markIncompleteNode(Call.getPtrArg(i).getNode());
|
|
|
|
}
|
2002-07-18 08:12:30 +08:00
|
|
|
|
|
|
|
// markIncompleteNodes - Traverse the graph, identifying nodes that may be
|
|
|
|
// modified by other functions that have not been resolved yet. This marks
|
|
|
|
// nodes that are reachable through three sources of "unknownness":
|
|
|
|
//
|
|
|
|
// Global Variables, Function Calls, and Incoming Arguments
|
|
|
|
//
|
|
|
|
// For any node that may have unknown components (because something outside the
|
|
|
|
// scope of current analysis may have modified it), the 'Incomplete' flag is
|
|
|
|
// added to the NodeType.
|
|
|
|
//
|
2003-01-24 06:05:33 +08:00
|
|
|
void DSGraph::markIncompleteNodes(unsigned Flags) {
|
2002-07-18 08:12:30 +08:00
|
|
|
// Mark any incoming arguments as incomplete...
|
2003-06-30 11:15:25 +08:00
|
|
|
if (Flags & DSGraph::MarkFormalArgs)
|
|
|
|
for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end();
|
|
|
|
FI != E; ++FI) {
|
|
|
|
Function &F = *FI->first;
|
|
|
|
if (F.getName() != "main")
|
|
|
|
for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
if (isPointerType(I->getType()))
|
|
|
|
markIncompleteNode(getNodeForValue(I).getNode());
|
2003-06-30 11:15:25 +08:00
|
|
|
}
|
2002-07-18 08:12:30 +08:00
|
|
|
|
|
|
|
// Mark stuff passed into functions calls as being incomplete...
|
2002-11-11 11:36:55 +08:00
|
|
|
if (!shouldPrintAuxCalls())
|
|
|
|
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
|
|
|
markIncomplete(FunctionCalls[i]);
|
|
|
|
else
|
|
|
|
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
|
|
markIncomplete(AuxFunctionCalls[i]);
|
|
|
|
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2003-02-10 02:41:49 +08:00
|
|
|
// Mark all global nodes as incomplete...
|
|
|
|
if ((Flags & DSGraph::IgnoreGlobals) == 0)
|
2004-02-26 07:08:00 +08:00
|
|
|
for (DSScalarMap::global_iterator I = ScalarMap.global_begin(),
|
|
|
|
E = ScalarMap.global_end(); I != E; ++I)
|
2004-02-26 07:36:08 +08:00
|
|
|
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(*I))
|
|
|
|
if (!GV->isConstant())
|
|
|
|
markIncompleteNode(ScalarMap[GV].getNode());
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
static inline void killIfUselessEdge(DSNodeHandle &Edge) {
|
|
|
|
if (DSNode *N = Edge.getNode()) // Is there an edge?
|
2003-02-12 07:11:51 +08:00
|
|
|
if (N->getNumReferrers() == 1) // Does it point to a lonely node?
|
2003-06-20 05:15:11 +08:00
|
|
|
// No interesting info?
|
|
|
|
if ((N->getNodeFlags() & ~DSNode::Incomplete) == 0 &&
|
2002-11-19 05:44:46 +08:00
|
|
|
N->getType() == Type::VoidTy && !N->isNodeCompletelyFolded())
|
2002-11-10 14:59:55 +08:00
|
|
|
Edge.setNode(0); // Kill the edge!
|
|
|
|
}
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
static inline bool nodeContainsExternalFunction(const DSNode *N) {
|
|
|
|
const std::vector<GlobalValue*> &Globals = N->getGlobals();
|
|
|
|
for (unsigned i = 0, e = Globals.size(); i != e; ++i)
|
|
|
|
if (Globals[i]->isExternal())
|
|
|
|
return true;
|
2002-07-18 08:12:30 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-06-30 11:15:25 +08:00
|
|
|
static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) {
|
2002-07-31 06:05:22 +08:00
|
|
|
// Remove trivially identical function calls
|
|
|
|
unsigned NumFns = Calls.size();
|
2002-11-10 14:59:55 +08:00
|
|
|
std::sort(Calls.begin(), Calls.end()); // Sort by callee as primary key!
|
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
#if 1
|
2002-11-10 14:59:55 +08:00
|
|
|
// Scan the call list cleaning it up as necessary...
|
2003-02-06 05:59:58 +08:00
|
|
|
DSNode *LastCalleeNode = 0;
|
|
|
|
Function *LastCalleeFunc = 0;
|
2002-11-10 14:59:55 +08:00
|
|
|
unsigned NumDuplicateCalls = 0;
|
|
|
|
bool LastCalleeContainsExternalFunction = false;
|
2002-11-12 05:35:38 +08:00
|
|
|
for (unsigned i = 0; i != Calls.size(); ++i) {
|
2002-11-10 14:59:55 +08:00
|
|
|
DSCallSite &CS = Calls[i];
|
|
|
|
|
2002-11-12 05:35:38 +08:00
|
|
|
// If the Callee is a useless edge, this must be an unreachable call site,
|
|
|
|
// eliminate it.
|
2003-02-12 07:11:51 +08:00
|
|
|
if (CS.isIndirectCall() && CS.getCalleeNode()->getNumReferrers() == 1 &&
|
2004-02-26 11:43:43 +08:00
|
|
|
CS.getCalleeNode()->isComplete() &&
|
2004-02-26 11:45:03 +08:00
|
|
|
CS.getCalleeNode()->getGlobals().empty()) { // No useful info?
|
2004-01-28 09:19:52 +08:00
|
|
|
#ifndef NDEBUG
|
2004-02-26 11:43:43 +08:00
|
|
|
std::cerr << "WARNING: Useless call site found.\n";
|
2004-01-28 09:19:52 +08:00
|
|
|
#endif
|
2002-11-12 05:35:38 +08:00
|
|
|
CS.swap(Calls.back());
|
|
|
|
Calls.pop_back();
|
|
|
|
--i;
|
2002-11-10 14:59:55 +08:00
|
|
|
} else {
|
2002-11-12 05:35:38 +08:00
|
|
|
// If the return value or any arguments point to a void node with no
|
|
|
|
// information at all in it, and the call node is the only node to point
|
|
|
|
// to it, remove the edge to the node (killing the node).
|
|
|
|
//
|
|
|
|
killIfUselessEdge(CS.getRetVal());
|
|
|
|
for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
|
|
|
|
killIfUselessEdge(CS.getPtrArg(a));
|
|
|
|
|
|
|
|
// If this call site calls the same function as the last call site, and if
|
|
|
|
// the function pointer contains an external function, this node will
|
|
|
|
// never be resolved. Merge the arguments of the call node because no
|
|
|
|
// information will be lost.
|
|
|
|
//
|
2003-02-06 05:59:58 +08:00
|
|
|
if ((CS.isDirectCall() && CS.getCalleeFunc() == LastCalleeFunc) ||
|
|
|
|
(CS.isIndirectCall() && CS.getCalleeNode() == LastCalleeNode)) {
|
2002-11-12 05:35:38 +08:00
|
|
|
++NumDuplicateCalls;
|
|
|
|
if (NumDuplicateCalls == 1) {
|
2003-02-06 05:59:58 +08:00
|
|
|
if (LastCalleeNode)
|
|
|
|
LastCalleeContainsExternalFunction =
|
|
|
|
nodeContainsExternalFunction(LastCalleeNode);
|
|
|
|
else
|
|
|
|
LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal();
|
2002-11-12 05:35:38 +08:00
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
// It is not clear why, but enabling this code makes DSA really
|
|
|
|
// sensitive to node forwarding. Basically, with this enabled, DSA
|
|
|
|
// performs different number of inlinings based on which nodes are
|
|
|
|
// forwarding or not. This is clearly a problem, so this code is
|
|
|
|
// disabled until this can be resolved.
|
2003-07-02 12:38:49 +08:00
|
|
|
#if 1
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
if (LastCalleeContainsExternalFunction
|
|
|
|
#if 0
|
|
|
|
||
|
2002-11-12 05:35:38 +08:00
|
|
|
// This should be more than enough context sensitivity!
|
|
|
|
// FIXME: Evaluate how many times this is tripped!
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
NumDuplicateCalls > 20
|
|
|
|
#endif
|
|
|
|
) {
|
2002-11-12 05:35:38 +08:00
|
|
|
DSCallSite &OCS = Calls[i-1];
|
|
|
|
OCS.mergeWith(CS);
|
|
|
|
|
|
|
|
// The node will now be eliminated as a duplicate!
|
|
|
|
if (CS.getNumPtrArgs() < OCS.getNumPtrArgs())
|
|
|
|
CS = OCS;
|
|
|
|
else if (CS.getNumPtrArgs() > OCS.getNumPtrArgs())
|
|
|
|
OCS = CS;
|
|
|
|
}
|
2003-07-02 00:28:11 +08:00
|
|
|
#endif
|
2002-11-12 05:35:38 +08:00
|
|
|
} else {
|
2003-02-06 05:59:58 +08:00
|
|
|
if (CS.isDirectCall()) {
|
|
|
|
LastCalleeFunc = CS.getCalleeFunc();
|
|
|
|
LastCalleeNode = 0;
|
|
|
|
} else {
|
|
|
|
LastCalleeNode = CS.getCalleeNode();
|
|
|
|
LastCalleeFunc = 0;
|
|
|
|
}
|
2002-11-12 05:35:38 +08:00
|
|
|
NumDuplicateCalls = 0;
|
|
|
|
}
|
2002-11-10 14:59:55 +08:00
|
|
|
}
|
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
#endif
|
2004-01-22 23:30:58 +08:00
|
|
|
Calls.erase(std::unique(Calls.begin(), Calls.end()), Calls.end());
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2002-11-08 09:21:07 +08:00
|
|
|
// Track the number of call nodes merged away...
|
|
|
|
NumCallNodesMerged += NumFns-Calls.size();
|
|
|
|
|
2002-07-31 06:05:22 +08:00
|
|
|
DEBUG(if (NumFns != Calls.size())
|
2003-06-30 11:15:25 +08:00
|
|
|
std::cerr << "Merged " << (NumFns-Calls.size()) << " call nodes.\n";);
|
2002-07-31 06:05:22 +08:00
|
|
|
}
|
2002-07-18 08:12:30 +08:00
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
|
2002-07-19 02:22:40 +08:00
|
|
|
// removeTriviallyDeadNodes - After the graph has been constructed, this method
|
|
|
|
// removes all unreachable nodes that are created because they got merged with
|
|
|
|
// other nodes in the graph. These nodes will all be trivially unreachable, so
|
|
|
|
// we don't have to perform any non-trivial analysis here.
|
2002-07-18 08:12:30 +08:00
|
|
|
//
|
2002-11-10 06:07:02 +08:00
|
|
|
void DSGraph::removeTriviallyDeadNodes() {
|
2004-01-23 00:36:28 +08:00
|
|
|
TIME_REGION(X, "removeTriviallyDeadNodes");
|
2002-11-10 14:59:55 +08:00
|
|
|
|
2003-09-21 05:34:07 +08:00
|
|
|
// Loop over all of the nodes in the graph, calling getNode on each field.
|
|
|
|
// This will cause all nodes to update their forwarding edges, causing
|
|
|
|
// forwarded nodes to be delete-able.
|
2004-02-08 08:23:16 +08:00
|
|
|
for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI) {
|
|
|
|
DSNode *N = *NI;
|
2003-09-21 05:34:07 +08:00
|
|
|
for (unsigned l = 0, e = N->getNumLinks(); l != e; ++l)
|
|
|
|
N->getLink(l*N->getPointerSize()).getNode();
|
|
|
|
}
|
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// NOTE: This code is disabled. Though it should, in theory, allow us to
|
|
|
|
// remove more nodes down below, the scan of the scalar map is incredibly
|
|
|
|
// expensive for certain programs (with large SCCs). In the future, if we can
|
|
|
|
// make the scalar map scan more efficient, then we can reenable this.
|
|
|
|
#if 0
|
|
|
|
{ TIME_REGION(X, "removeTriviallyDeadNodes:scalarmap");
|
|
|
|
|
2004-01-22 23:30:58 +08:00
|
|
|
// Likewise, forward any edges from the scalar nodes. While we are at it,
|
|
|
|
// clean house a bit.
|
2004-01-28 17:15:42 +08:00
|
|
|
for (DSScalarMap::iterator I = ScalarMap.begin(),E = ScalarMap.end();I != E;){
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
I->second.getNode();
|
|
|
|
++I;
|
2004-01-22 23:30:58 +08:00
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
}
|
|
|
|
#endif
|
2003-07-17 05:36:31 +08:00
|
|
|
bool isGlobalsGraph = !GlobalsGraph;
|
|
|
|
|
2004-02-08 08:23:16 +08:00
|
|
|
for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E; ) {
|
2004-02-08 08:53:26 +08:00
|
|
|
DSNode &Node = *NI;
|
2003-07-17 05:36:31 +08:00
|
|
|
|
|
|
|
// Do not remove *any* global nodes in the globals graph.
|
|
|
|
// This is a special case because such nodes may not have I, M, R flags set.
|
2004-02-08 08:53:26 +08:00
|
|
|
if (Node.isGlobalNode() && isGlobalsGraph) {
|
2004-02-08 08:23:16 +08:00
|
|
|
++NI;
|
2003-07-17 05:36:31 +08:00
|
|
|
continue;
|
2004-02-08 08:23:16 +08:00
|
|
|
}
|
2003-07-17 05:36:31 +08:00
|
|
|
|
2004-02-08 08:53:26 +08:00
|
|
|
if (Node.isComplete() && !Node.isModified() && !Node.isRead()) {
|
2003-02-04 03:12:15 +08:00
|
|
|
// This is a useless node if it has no mod/ref info (checked above),
|
|
|
|
// outgoing edges (which it cannot, as it is not modified in this
|
|
|
|
// context), and it has no incoming edges. If it is a global node it may
|
|
|
|
// have all of these properties and still have incoming edges, due to the
|
|
|
|
// scalar map, so we check those now.
|
|
|
|
//
|
2004-02-08 08:53:26 +08:00
|
|
|
if (Node.getNumReferrers() == Node.getGlobals().size()) {
|
|
|
|
const std::vector<GlobalValue*> &Globals = Node.getGlobals();
|
2003-02-12 07:11:51 +08:00
|
|
|
|
2004-01-29 11:32:15 +08:00
|
|
|
// Loop through and make sure all of the globals are referring directly
|
|
|
|
// to the node...
|
|
|
|
for (unsigned j = 0, e = Globals.size(); j != e; ++j) {
|
|
|
|
DSNode *N = getNodeForValue(Globals[j]).getNode();
|
2004-02-08 08:53:26 +08:00
|
|
|
assert(N == &Node && "ScalarMap doesn't match globals list!");
|
2004-01-29 11:32:15 +08:00
|
|
|
}
|
|
|
|
|
2003-06-20 05:15:11 +08:00
|
|
|
// Make sure NumReferrers still agrees, if so, the node is truly dead.
|
2004-02-08 08:53:26 +08:00
|
|
|
if (Node.getNumReferrers() == Globals.size()) {
|
2003-02-12 07:11:51 +08:00
|
|
|
for (unsigned j = 0, e = Globals.size(); j != e; ++j)
|
|
|
|
ScalarMap.erase(Globals[j]);
|
2004-02-08 08:53:26 +08:00
|
|
|
Node.makeNodeDead();
|
2004-02-08 09:51:48 +08:00
|
|
|
++NumTrivialGlobalDNE;
|
2003-02-12 07:11:51 +08:00
|
|
|
}
|
2003-02-04 03:12:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-08 08:53:26 +08:00
|
|
|
if (Node.getNodeFlags() == 0 && Node.hasNoReferrers()) {
|
2003-02-11 02:18:18 +08:00
|
|
|
// This node is dead!
|
2004-02-08 08:53:26 +08:00
|
|
|
NI = Nodes.erase(NI); // Erase & remove from node list.
|
2004-02-08 09:51:48 +08:00
|
|
|
++NumTrivialDNE;
|
2004-02-08 08:23:16 +08:00
|
|
|
} else {
|
|
|
|
++NI;
|
2002-11-10 14:59:55 +08:00
|
|
|
}
|
2003-02-04 03:12:15 +08:00
|
|
|
}
|
2004-02-08 09:51:48 +08:00
|
|
|
|
|
|
|
removeIdenticalCalls(FunctionCalls);
|
|
|
|
removeIdenticalCalls(AuxFunctionCalls);
|
2002-07-18 08:12:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-30 05:10:20 +08:00
|
|
|
/// markReachableNodes - This method recursively traverses the specified
|
|
|
|
/// DSNodes, marking any nodes which are reachable. All reachable nodes it adds
|
|
|
|
/// to the set, which allows it to only traverse visited nodes once.
|
|
|
|
///
|
2003-02-01 12:52:08 +08:00
|
|
|
void DSNode::markReachableNodes(hash_set<DSNode*> &ReachableNodes) {
|
2003-01-30 05:10:20 +08:00
|
|
|
if (this == 0) return;
|
2003-02-12 07:11:51 +08:00
|
|
|
assert(getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
2004-01-22 23:30:58 +08:00
|
|
|
if (ReachableNodes.insert(this).second) // Is newly reachable?
|
|
|
|
for (unsigned i = 0, e = getSize(); i < e; i += DS::PointerSize)
|
|
|
|
getLink(i).getNode()->markReachableNodes(ReachableNodes);
|
2003-01-30 05:10:20 +08:00
|
|
|
}
|
2002-07-19 02:22:40 +08:00
|
|
|
|
2003-02-01 12:52:08 +08:00
|
|
|
void DSCallSite::markReachableNodes(hash_set<DSNode*> &Nodes) {
|
2003-01-30 05:10:20 +08:00
|
|
|
getRetVal().getNode()->markReachableNodes(Nodes);
|
2003-02-06 05:59:58 +08:00
|
|
|
if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes);
|
2003-01-30 05:10:20 +08:00
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
for (unsigned i = 0, e = getNumPtrArgs(); i != e; ++i)
|
|
|
|
getPtrArg(i).getNode()->markReachableNodes(Nodes);
|
2002-07-31 06:05:22 +08:00
|
|
|
}
|
|
|
|
|
2003-02-01 14:17:02 +08:00
|
|
|
// CanReachAliveNodes - Simple graph walker that recursively traverses the graph
|
|
|
|
// looking for a node that is marked alive. If an alive node is found, return
|
|
|
|
// true, otherwise return false. If an alive node is reachable, this node is
|
|
|
|
// marked as alive...
|
2002-11-10 14:59:55 +08:00
|
|
|
//
|
2003-02-01 14:17:02 +08:00
|
|
|
static bool CanReachAliveNodes(DSNode *N, hash_set<DSNode*> &Alive,
|
2003-07-03 10:03:53 +08:00
|
|
|
hash_set<DSNode*> &Visited,
|
|
|
|
bool IgnoreGlobals) {
|
2002-07-31 06:05:22 +08:00
|
|
|
if (N == 0) return false;
|
2003-02-12 07:11:51 +08:00
|
|
|
assert(N->getForwardNode() == 0 && "Cannot mark a forwarded node!");
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2003-07-03 10:03:53 +08:00
|
|
|
// If this is a global node, it will end up in the globals graph anyway, so we
|
|
|
|
// don't need to worry about it.
|
|
|
|
if (IgnoreGlobals && N->isGlobalNode()) return false;
|
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
// If we know that this node is alive, return so!
|
|
|
|
if (Alive.count(N)) return true;
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
// Otherwise, we don't think the node is alive yet, check for infinite
|
|
|
|
// recursion.
|
2003-02-01 12:52:08 +08:00
|
|
|
if (Visited.count(N)) return false; // Found a cycle
|
2003-02-01 14:17:02 +08:00
|
|
|
Visited.insert(N); // No recursion, insert into Visited...
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
|
2003-07-03 10:03:53 +08:00
|
|
|
if (CanReachAliveNodes(N->getLink(i).getNode(), Alive, Visited,
|
|
|
|
IgnoreGlobals)) {
|
2003-02-01 14:17:02 +08:00
|
|
|
N->markReachableNodes(Alive);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2002-07-31 06:05:22 +08:00
|
|
|
}
|
|
|
|
|
2003-02-01 14:17:02 +08:00
|
|
|
// CallSiteUsesAliveArgs - Return true if the specified call site can reach any
|
|
|
|
// alive nodes.
|
|
|
|
//
|
2003-02-01 12:52:08 +08:00
|
|
|
static bool CallSiteUsesAliveArgs(DSCallSite &CS, hash_set<DSNode*> &Alive,
|
2003-07-03 10:03:53 +08:00
|
|
|
hash_set<DSNode*> &Visited,
|
|
|
|
bool IgnoreGlobals) {
|
|
|
|
if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited,
|
|
|
|
IgnoreGlobals))
|
2003-02-06 05:59:58 +08:00
|
|
|
return true;
|
|
|
|
if (CS.isIndirectCall() &&
|
2003-07-03 10:03:53 +08:00
|
|
|
CanReachAliveNodes(CS.getCalleeNode(), Alive, Visited, IgnoreGlobals))
|
2002-11-10 14:59:55 +08:00
|
|
|
return true;
|
2003-02-04 03:12:15 +08:00
|
|
|
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i)
|
2003-07-03 10:03:53 +08:00
|
|
|
if (CanReachAliveNodes(CS.getPtrArg(i).getNode(), Alive, Visited,
|
|
|
|
IgnoreGlobals))
|
2002-11-10 14:59:55 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2002-07-19 02:22:40 +08:00
|
|
|
// removeDeadNodes - Use a more powerful reachability analysis to eliminate
|
|
|
|
// subgraphs that are unreachable. This often occurs because the data
|
|
|
|
// structure doesn't "escape" into it's caller, and thus should be eliminated
|
|
|
|
// from the caller's graph entirely. This is only appropriate to use when
|
|
|
|
// inlining graphs.
|
|
|
|
//
|
2003-01-24 06:05:33 +08:00
|
|
|
void DSGraph::removeDeadNodes(unsigned Flags) {
|
2003-11-12 12:57:58 +08:00
|
|
|
DEBUG(AssertGraphOK(); if (GlobalsGraph) GlobalsGraph->AssertGraphOK());
|
2003-07-03 10:03:53 +08:00
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
// Reduce the amount of work we have to do... remove dummy nodes left over by
|
|
|
|
// merging...
|
2004-01-28 11:24:41 +08:00
|
|
|
removeTriviallyDeadNodes();
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2004-01-23 00:36:28 +08:00
|
|
|
TIME_REGION(X, "removeDeadNodes");
|
|
|
|
|
2003-09-12 02:14:24 +08:00
|
|
|
// FIXME: Merge non-trivially identical call nodes...
|
2002-07-19 02:22:40 +08:00
|
|
|
|
|
|
|
// Alive - a set that holds all nodes found to be reachable/alive.
|
2003-02-01 12:52:08 +08:00
|
|
|
hash_set<DSNode*> Alive;
|
2002-11-10 14:59:55 +08:00
|
|
|
std::vector<std::pair<Value*, DSNode*> > GlobalNodes;
|
2002-07-19 02:22:40 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Copy and merge all information about globals to the GlobalsGraph if this is
|
|
|
|
// not a final pass (where unreachable globals are removed).
|
|
|
|
//
|
|
|
|
// Strip all alloca bits since the current function is only for the BU pass.
|
|
|
|
// Strip all incomplete bits since they are short-lived properties and they
|
|
|
|
// will be correctly computed when rematerializing nodes into the functions.
|
|
|
|
//
|
|
|
|
ReachabilityCloner GGCloner(*GlobalsGraph, *this, DSGraph::StripAllocaBit |
|
|
|
|
DSGraph::StripIncompleteBit);
|
|
|
|
|
2002-11-10 14:59:55 +08:00
|
|
|
// Mark all nodes reachable by (non-global) scalar nodes as alive...
|
2004-01-28 10:05:05 +08:00
|
|
|
{ TIME_REGION(Y, "removeDeadNodes:scalarscan");
|
2004-01-28 17:15:42 +08:00
|
|
|
for (DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end(); I !=E;)
|
2003-02-14 14:28:00 +08:00
|
|
|
if (isa<GlobalValue>(I->first)) { // Keep track of global nodes
|
2003-02-04 03:12:15 +08:00
|
|
|
assert(I->second.getNode() && "Null global node?");
|
2003-07-17 05:36:31 +08:00
|
|
|
assert(I->second.getNode()->isGlobalNode() && "Should be a global node!");
|
2003-02-14 14:28:00 +08:00
|
|
|
GlobalNodes.push_back(std::make_pair(I->first, I->second.getNode()));
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
|
|
|
|
// Make sure that all globals are cloned over as roots.
|
2004-01-28 10:05:05 +08:00
|
|
|
if (!(Flags & DSGraph::RemoveUnreachableGlobals)) {
|
|
|
|
DSGraph::ScalarMapTy::iterator SMI =
|
|
|
|
GlobalsGraph->getScalarMap().find(I->first);
|
|
|
|
if (SMI != GlobalsGraph->getScalarMap().end())
|
|
|
|
GGCloner.merge(SMI->second, I->second);
|
|
|
|
else
|
|
|
|
GGCloner.getClonedNH(I->second);
|
|
|
|
}
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
++I;
|
2003-02-14 14:28:00 +08:00
|
|
|
} else {
|
2004-01-28 10:41:32 +08:00
|
|
|
DSNode *N = I->second.getNode();
|
|
|
|
#if 0
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Check to see if this is a worthless node generated for non-pointer
|
|
|
|
// values, such as integers. Consider an addition of long types: A+B.
|
|
|
|
// Assuming we can track all uses of the value in this context, and it is
|
|
|
|
// NOT used as a pointer, we can delete the node. We will be able to
|
|
|
|
// detect this situation if the node pointed to ONLY has Unknown bit set
|
|
|
|
// in the node. In this case, the node is not incomplete, does not point
|
|
|
|
// to any other nodes (no mod/ref bits set), and is therefore
|
|
|
|
// uninteresting for data structure analysis. If we run across one of
|
|
|
|
// these, prune the scalar pointing to it.
|
|
|
|
//
|
|
|
|
if (N->getNodeFlags() == DSNode::UnknownNode && !isa<Argument>(I->first))
|
|
|
|
ScalarMap.erase(I++);
|
|
|
|
else {
|
2004-01-28 10:41:32 +08:00
|
|
|
#endif
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
N->markReachableNodes(Alive);
|
|
|
|
++I;
|
2004-01-28 10:41:32 +08:00
|
|
|
//}
|
2003-02-04 03:12:15 +08:00
|
|
|
}
|
2004-01-28 10:05:05 +08:00
|
|
|
}
|
2002-11-02 08:13:20 +08:00
|
|
|
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// The return values are alive as well.
|
2003-06-30 11:15:25 +08:00
|
|
|
for (ReturnNodesTy::iterator I = ReturnNodes.begin(), E = ReturnNodes.end();
|
|
|
|
I != E; ++I)
|
|
|
|
I->second.getNode()->markReachableNodes(Alive);
|
2002-07-31 06:05:22 +08:00
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
// Mark any nodes reachable by primary calls as alive...
|
2002-11-10 14:59:55 +08:00
|
|
|
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
2003-02-04 03:12:15 +08:00
|
|
|
FunctionCalls[i].markReachableNodes(Alive);
|
2002-11-10 14:59:55 +08:00
|
|
|
|
2003-07-17 05:36:31 +08:00
|
|
|
|
|
|
|
// Now find globals and aux call nodes that are already live or reach a live
|
|
|
|
// value (which makes them live in turn), and continue till no more are found.
|
|
|
|
//
|
2003-02-04 03:12:15 +08:00
|
|
|
bool Iterate;
|
|
|
|
hash_set<DSNode*> Visited;
|
|
|
|
std::vector<unsigned char> AuxFCallsAlive(AuxFunctionCalls.size());
|
|
|
|
do {
|
|
|
|
Visited.clear();
|
2003-07-03 07:57:05 +08:00
|
|
|
// If any global node points to a non-global that is "alive", the global is
|
2003-02-12 07:11:51 +08:00
|
|
|
// "alive" as well... Remove it from the GlobalNodes list so we only have
|
2003-02-04 03:12:15 +08:00
|
|
|
// unreachable globals in the list.
|
|
|
|
//
|
|
|
|
Iterate = false;
|
2003-07-17 05:36:31 +08:00
|
|
|
if (!(Flags & DSGraph::RemoveUnreachableGlobals))
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
for (unsigned i = 0; i != GlobalNodes.size(); ++i)
|
|
|
|
if (CanReachAliveNodes(GlobalNodes[i].second, Alive, Visited,
|
|
|
|
Flags & DSGraph::RemoveUnreachableGlobals)) {
|
|
|
|
std::swap(GlobalNodes[i--], GlobalNodes.back()); // Move to end to...
|
|
|
|
GlobalNodes.pop_back(); // erase efficiently
|
|
|
|
Iterate = true;
|
|
|
|
}
|
2003-07-17 05:36:31 +08:00
|
|
|
|
|
|
|
// Mark only unresolvable call nodes for moving to the GlobalsGraph since
|
|
|
|
// call nodes that get resolved will be difficult to remove from that graph.
|
|
|
|
// The final unresolved call nodes must be handled specially at the end of
|
|
|
|
// the BU pass (i.e., in main or other roots of the call graph).
|
2003-02-04 03:12:15 +08:00
|
|
|
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
|
|
if (!AuxFCallsAlive[i] &&
|
2003-07-17 05:36:31 +08:00
|
|
|
(AuxFunctionCalls[i].isIndirectCall()
|
|
|
|
|| CallSiteUsesAliveArgs(AuxFunctionCalls[i], Alive, Visited,
|
|
|
|
Flags & DSGraph::RemoveUnreachableGlobals))) {
|
2003-02-04 03:12:15 +08:00
|
|
|
AuxFunctionCalls[i].markReachableNodes(Alive);
|
|
|
|
AuxFCallsAlive[i] = true;
|
|
|
|
Iterate = true;
|
|
|
|
}
|
|
|
|
} while (Iterate);
|
2002-11-10 14:59:55 +08:00
|
|
|
|
2003-07-17 05:36:31 +08:00
|
|
|
// Move dead aux function calls to the end of the list
|
2003-02-04 03:12:15 +08:00
|
|
|
unsigned CurIdx = 0;
|
2002-11-10 14:59:55 +08:00
|
|
|
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
|
|
if (AuxFCallsAlive[i])
|
|
|
|
AuxFunctionCalls[CurIdx++].swap(AuxFunctionCalls[i]);
|
2003-07-17 05:36:31 +08:00
|
|
|
|
|
|
|
// Copy and merge all global nodes and dead aux call nodes into the
|
|
|
|
// GlobalsGraph, and all nodes reachable from those nodes
|
|
|
|
//
|
|
|
|
if (!(Flags & DSGraph::RemoveUnreachableGlobals)) {
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
// Copy the unreachable call nodes to the globals graph, updating their
|
|
|
|
// target pointers using the GGCloner
|
2003-07-17 05:36:31 +08:00
|
|
|
for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
|
|
GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(AuxFunctionCalls[i],
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
GGCloner));
|
2003-02-04 03:12:15 +08:00
|
|
|
}
|
|
|
|
// Crop all the useless ones out...
|
2002-11-10 14:59:55 +08:00
|
|
|
AuxFunctionCalls.erase(AuxFunctionCalls.begin()+CurIdx,
|
|
|
|
AuxFunctionCalls.end());
|
|
|
|
|
2004-02-08 09:51:48 +08:00
|
|
|
// We are finally done with the GGCloner so we can destroy it.
|
|
|
|
GGCloner.destroy();
|
2003-07-17 05:36:31 +08:00
|
|
|
|
2003-07-22 20:08:58 +08:00
|
|
|
// At this point, any nodes which are visited, but not alive, are nodes
|
|
|
|
// which can be removed. Loop over all nodes, eliminating completely
|
|
|
|
// unreachable nodes.
|
2003-02-04 03:12:15 +08:00
|
|
|
//
|
2003-02-12 07:11:51 +08:00
|
|
|
std::vector<DSNode*> DeadNodes;
|
|
|
|
DeadNodes.reserve(Nodes.size());
|
2004-02-26 07:08:00 +08:00
|
|
|
for (NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E;) {
|
|
|
|
DSNode *N = NI++;
|
|
|
|
assert(!N->isForwarding() && "Forwarded node in nodes list?");
|
|
|
|
|
|
|
|
if (!Alive.count(N)) {
|
|
|
|
Nodes.remove(N);
|
|
|
|
assert(!N->isForwarding() && "Cannot remove a forwarding node!");
|
2003-07-17 05:36:31 +08:00
|
|
|
DeadNodes.push_back(N);
|
|
|
|
N->dropAllReferences();
|
2004-02-26 07:08:00 +08:00
|
|
|
++NumDNE;
|
2003-02-04 03:12:15 +08:00
|
|
|
}
|
2004-02-26 07:08:00 +08:00
|
|
|
}
|
2003-02-01 14:41:15 +08:00
|
|
|
|
2003-07-17 05:36:31 +08:00
|
|
|
// Remove all unreachable globals from the ScalarMap.
|
|
|
|
// If flag RemoveUnreachableGlobals is set, GlobalNodes has only dead nodes.
|
|
|
|
// In either case, the dead nodes will not be in the set Alive.
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i)
|
2003-07-17 05:36:31 +08:00
|
|
|
if (!Alive.count(GlobalNodes[i].second))
|
|
|
|
ScalarMap.erase(GlobalNodes[i].first);
|
* Add a new commandline argument to control the "global roots hack". Default
it to be off. If it looks like it's completely unnecessary after testing, I
will remove it completely (which is the hope).
* Callers of the DSNode "copy ctor" can not choose to not copy links.
* Make node collapsing not create a garbage node in some cases, avoiding a
memory allocation, and a subsequent DNE.
* When merging types, allow two functions of different types to be merged
without collapsing.
* Use DSNodeHandle::isNull more often instead of DSNodeHandle::getNode() == 0,
as it is much more efficient.
*** Implement the new, more efficient reachability cloner class
In addition to only cloning nodes that are reachable from interesting
roots, this also fixes the huge inefficiency we had where we cloned lots
of nodes, only to merge them away immediately after they were cloned.
Now we only actually allocate a node if there isn't one to merge it into.
* Eliminate the now-obsolete cloneReachable* and clonePartiallyInto methods
* Rewrite updateFromGlobalsGraph to use the reachability cloner
* Rewrite mergeInGraph to use the reachability cloner
* Disable the scalar map scanning code in removeTriviallyDeadNodes. In large
SCC's, this is extremely expensive. We need a better data structure for the
scalar map, because we really want to scan the unique node handles, not ALL
of the scalars.
* Remove the incorrect SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP code.
* Move the code for eliminating integer nodes from the trivially dead
eliminator to the dead node eliminator.
* removeDeadNodes no longer uses removeTriviallyDeadNodes, as it contains a
superset of the node removal power.
* Only futz around with the globals graph in removeDeadNodes if it is modified
llvm-svn: 10987
2004-01-28 06:03:40 +08:00
|
|
|
else
|
|
|
|
assert((Flags & DSGraph::RemoveUnreachableGlobals) && "non-dead global");
|
2003-02-04 03:12:15 +08:00
|
|
|
|
2003-07-17 05:36:31 +08:00
|
|
|
// Delete all dead nodes now since their referrer counts are zero.
|
2003-02-12 07:11:51 +08:00
|
|
|
for (unsigned i = 0, e = DeadNodes.size(); i != e; ++i)
|
|
|
|
delete DeadNodes[i];
|
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
DEBUG(AssertGraphOK(); GlobalsGraph->AssertGraphOK());
|
2002-07-19 02:22:40 +08:00
|
|
|
}
|
|
|
|
|
2004-03-04 04:55:27 +08:00
|
|
|
void DSGraph::AssertCallSiteInGraph(const DSCallSite &CS) const {
|
|
|
|
if (CS.isIndirectCall()) {
|
|
|
|
AssertNodeInGraph(CS.getCalleeNode());
|
|
|
|
#if 0
|
|
|
|
if (CS.getNumPtrArgs() && CS.getCalleeNode() == CS.getPtrArg(0).getNode() &&
|
|
|
|
CS.getCalleeNode() && CS.getCalleeNode()->getGlobals().empty())
|
|
|
|
std::cerr << "WARNING: WIERD CALL SITE FOUND!\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
AssertNodeInGraph(CS.getRetVal().getNode());
|
|
|
|
for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j)
|
|
|
|
AssertNodeInGraph(CS.getPtrArg(j).getNode());
|
|
|
|
}
|
|
|
|
|
|
|
|
void DSGraph::AssertCallNodesInGraph() const {
|
|
|
|
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
|
|
|
|
AssertCallSiteInGraph(FunctionCalls[i]);
|
|
|
|
}
|
|
|
|
void DSGraph::AssertAuxCallNodesInGraph() const {
|
|
|
|
for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
|
|
|
|
AssertCallSiteInGraph(AuxFunctionCalls[i]);
|
|
|
|
}
|
|
|
|
|
2003-02-04 03:12:15 +08:00
|
|
|
void DSGraph::AssertGraphOK() const {
|
2004-02-08 08:23:16 +08:00
|
|
|
for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI)
|
|
|
|
(*NI)->assertOK();
|
2003-07-03 10:03:53 +08:00
|
|
|
|
2003-06-30 11:36:09 +08:00
|
|
|
for (ScalarMapTy::const_iterator I = ScalarMap.begin(),
|
2003-02-04 03:12:15 +08:00
|
|
|
E = ScalarMap.end(); I != E; ++I) {
|
|
|
|
assert(I->second.getNode() && "Null node in scalarmap!");
|
|
|
|
AssertNodeInGraph(I->second.getNode());
|
|
|
|
if (GlobalValue *GV = dyn_cast<GlobalValue>(I->first)) {
|
2003-06-20 05:15:11 +08:00
|
|
|
assert(I->second.getNode()->isGlobalNode() &&
|
2003-02-04 03:12:15 +08:00
|
|
|
"Global points to node, but node isn't global?");
|
|
|
|
AssertNodeContainsGlobal(I->second.getNode(), GV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AssertCallNodesInGraph();
|
|
|
|
AssertAuxCallNodesInGraph();
|
|
|
|
}
|
2003-07-17 05:36:31 +08:00
|
|
|
|
2003-11-11 13:08:59 +08:00
|
|
|
/// computeNodeMapping - Given roots in two different DSGraphs, traverse the
|
|
|
|
/// nodes reachable from the two graphs, computing the mapping of nodes from
|
|
|
|
/// the first to the second graph.
|
|
|
|
///
|
|
|
|
void DSGraph::computeNodeMapping(const DSNodeHandle &NH1,
|
2003-11-13 01:58:22 +08:00
|
|
|
const DSNodeHandle &NH2, NodeMapTy &NodeMap,
|
|
|
|
bool StrictChecking) {
|
2003-11-11 13:08:59 +08:00
|
|
|
DSNode *N1 = NH1.getNode(), *N2 = NH2.getNode();
|
|
|
|
if (N1 == 0 || N2 == 0) return;
|
|
|
|
|
|
|
|
DSNodeHandle &Entry = NodeMap[N1];
|
|
|
|
if (Entry.getNode()) {
|
|
|
|
// Termination of recursion!
|
2003-11-13 01:58:22 +08:00
|
|
|
assert(!StrictChecking ||
|
|
|
|
(Entry.getNode() == N2 &&
|
|
|
|
Entry.getOffset() == (NH2.getOffset()-NH1.getOffset())) &&
|
2003-11-11 13:08:59 +08:00
|
|
|
"Inconsistent mapping detected!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Entry.setNode(N2);
|
2003-11-12 04:12:32 +08:00
|
|
|
Entry.setOffset(NH2.getOffset()-NH1.getOffset());
|
2003-11-11 13:08:59 +08:00
|
|
|
|
|
|
|
// Loop over all of the fields that N1 and N2 have in common, recursively
|
|
|
|
// mapping the edges together now.
|
|
|
|
int N2Idx = NH2.getOffset()-NH1.getOffset();
|
|
|
|
unsigned N2Size = N2->getSize();
|
|
|
|
for (unsigned i = 0, e = N1->getSize(); i < e; i += DS::PointerSize)
|
|
|
|
if (unsigned(N2Idx)+i < N2Size)
|
|
|
|
computeNodeMapping(N1->getLink(i), N2->getLink(N2Idx+i), NodeMap);
|
2004-03-03 13:34:31 +08:00
|
|
|
else
|
|
|
|
computeNodeMapping(N1->getLink(i),
|
|
|
|
N2->getLink(unsigned(N2Idx+i) % N2Size), NodeMap);
|
2003-11-11 13:08:59 +08:00
|
|
|
}
|