|
@@ -12,30 +12,67 @@
|
|
|
//
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
-#include "llvm/CodeGen/MachineScheduler.h"
|
|
|
+#include "llvm/ADT/ArrayRef.h"
|
|
|
+#include "llvm/ADT/BitVector.h"
|
|
|
+#include "llvm/ADT/DenseMap.h"
|
|
|
+#include "llvm/ADT/iterator_range.h"
|
|
|
#include "llvm/ADT/PriorityQueue.h"
|
|
|
+#include "llvm/ADT/SmallVector.h"
|
|
|
+#include "llvm/ADT/STLExtras.h"
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
|
|
+#include "llvm/CodeGen/LiveInterval.h"
|
|
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
|
|
+#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
|
#include "llvm/CodeGen/MachineDominators.h"
|
|
|
+#include "llvm/CodeGen/MachineFunction.h"
|
|
|
+#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
|
+#include "llvm/CodeGen/MachineInstr.h"
|
|
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
|
|
+#include "llvm/CodeGen/MachineOperand.h"
|
|
|
+#include "llvm/CodeGen/MachinePassRegistry.h"
|
|
|
+#include "llvm/CodeGen/RegisterPressure.h"
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
+#include "llvm/CodeGen/MachineScheduler.h"
|
|
|
+#include "llvm/CodeGen/MachineValueType.h"
|
|
|
#include "llvm/CodeGen/Passes.h"
|
|
|
#include "llvm/CodeGen/RegisterClassInfo.h"
|
|
|
+#include "llvm/CodeGen/ScheduleDAG.h"
|
|
|
+#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
|
|
+#include "llvm/CodeGen/ScheduleDAGMutation.h"
|
|
|
#include "llvm/CodeGen/ScheduleDFS.h"
|
|
|
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
|
|
|
+#include "llvm/CodeGen/SlotIndexes.h"
|
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
|
|
+#include "llvm/CodeGen/TargetSchedule.h"
|
|
|
+#include "llvm/MC/LaneBitmask.h"
|
|
|
+#include "llvm/Pass.h"
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
+#include "llvm/Support/Compiler.h"
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
#include "llvm/Support/GraphWriter.h"
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
|
+#include "llvm/Target/TargetLowering.h"
|
|
|
+#include "llvm/Target/TargetRegisterInfo.h"
|
|
|
+#include "llvm/Target/TargetSubtargetInfo.h"
|
|
|
+#include <algorithm>
|
|
|
+#include <cassert>
|
|
|
+#include <cstdint>
|
|
|
+#include <iterator>
|
|
|
+#include <limits>
|
|
|
+#include <memory>
|
|
|
+#include <string>
|
|
|
+#include <tuple>
|
|
|
+#include <utility>
|
|
|
+#include <vector>
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
#define DEBUG_TYPE "misched"
|
|
|
|
|
|
namespace llvm {
|
|
|
+
|
|
|
cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden,
|
|
|
cl::desc("Force top-down list scheduling"));
|
|
|
cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
|
|
@@ -43,7 +80,8 @@ cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
|
|
|
cl::opt<bool>
|
|
|
DumpCriticalPathLength("misched-dcpl", cl::Hidden,
|
|
|
cl::desc("Print critical path length to stdout"));
|
|
|
-}
|
|
|
+
|
|
|
+} // end namespace llvm
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
static cl::opt<bool> ViewMISchedDAGs("view-misched-dags", cl::Hidden,
|
|
@@ -88,14 +126,14 @@ static const unsigned MinSubtreeSize = 8;
|
|
|
|
|
|
// Pin the vtables to this file.
|
|
|
void MachineSchedStrategy::anchor() {}
|
|
|
+
|
|
|
void ScheduleDAGMutation::anchor() {}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
// Machine Instruction Scheduling Pass and Registry
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
-MachineSchedContext::MachineSchedContext():
|
|
|
- MF(nullptr), MLI(nullptr), MDT(nullptr), PassConfig(nullptr), AA(nullptr), LIS(nullptr) {
|
|
|
+MachineSchedContext::MachineSchedContext() {
|
|
|
RegClassInfo = new RegisterClassInfo();
|
|
|
}
|
|
|
|
|
@@ -104,6 +142,7 @@ MachineSchedContext::~MachineSchedContext() {
|
|
|
}
|
|
|
|
|
|
namespace {
|
|
|
+
|
|
|
/// Base class for a machine scheduler class that can run at any point.
|
|
|
class MachineSchedulerBase : public MachineSchedContext,
|
|
|
public MachineFunctionPass {
|
|
@@ -145,7 +184,8 @@ public:
|
|
|
protected:
|
|
|
ScheduleDAGInstrs *createPostMachineScheduler();
|
|
|
};
|
|
|
-} // namespace
|
|
|
+
|
|
|
+} // end anonymous namespace
|
|
|
|
|
|
char MachineScheduler::ID = 0;
|
|
|
|
|
@@ -207,7 +247,7 @@ static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) {
|
|
|
|
|
|
/// MachineSchedOpt allows command line selection of the scheduler.
|
|
|
static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
|
|
|
- RegisterPassParser<MachineSchedRegistry> >
|
|
|
+ RegisterPassParser<MachineSchedRegistry>>
|
|
|
MachineSchedOpt("misched",
|
|
|
cl::init(&useDefaultMachineSched), cl::Hidden,
|
|
|
cl::desc("Machine instruction scheduler to use"));
|
|
@@ -444,7 +484,7 @@ void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler,
|
|
|
// instruction stream until we find the nearest boundary.
|
|
|
unsigned NumRegionInstrs = 0;
|
|
|
MachineBasicBlock::iterator I = RegionEnd;
|
|
|
- for (;I != MBB->begin(); --I) {
|
|
|
+ for (; I != MBB->begin(); --I) {
|
|
|
MachineInstr &MI = *std::prev(I);
|
|
|
if (isSchedBoundary(&MI, &*MBB, MF, TII))
|
|
|
break;
|
|
@@ -516,8 +556,7 @@ LLVM_DUMP_METHOD void ReadyQueue::dump() {
|
|
|
// ===----------------------------------------------------------------------===/
|
|
|
|
|
|
// Provide a vtable anchor.
|
|
|
-ScheduleDAGMI::~ScheduleDAGMI() {
|
|
|
-}
|
|
|
+ScheduleDAGMI::~ScheduleDAGMI() = default;
|
|
|
|
|
|
bool ScheduleDAGMI::canAddEdge(SUnit *SuccSU, SUnit *PredSU) {
|
|
|
return SuccSU == &ExitSU || !Topo.IsReachable(PredSU, SuccSU);
|
|
@@ -822,7 +861,7 @@ void ScheduleDAGMI::placeDebugValues() {
|
|
|
RegionBegin = FirstDbgValue;
|
|
|
}
|
|
|
|
|
|
- for (std::vector<std::pair<MachineInstr *, MachineInstr *> >::iterator
|
|
|
+ for (std::vector<std::pair<MachineInstr *, MachineInstr *>>::iterator
|
|
|
DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) {
|
|
|
std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI);
|
|
|
MachineInstr *DbgValue = P.first;
|
|
@@ -1009,7 +1048,7 @@ updateScheduledPressure(const SUnit *SU,
|
|
|
++CritIdx;
|
|
|
if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) {
|
|
|
if ((int)NewMaxPressure[ID] > RegionCriticalPSets[CritIdx].getUnitInc()
|
|
|
- && NewMaxPressure[ID] <= INT16_MAX)
|
|
|
+ && NewMaxPressure[ID] <= std::numeric_limits<int16_t>::max())
|
|
|
RegionCriticalPSets[CritIdx].setUnitInc(NewMaxPressure[ID]);
|
|
|
}
|
|
|
unsigned Limit = RegClassInfo->getRegPressureSetLimit(ID);
|
|
@@ -1393,6 +1432,7 @@ void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) {
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
namespace {
|
|
|
+
|
|
|
/// \brief Post-process the DAG to create cluster edges between neighboring
|
|
|
/// loads or between neighboring stores.
|
|
|
class BaseMemOpClusterMutation : public ScheduleDAGMutation {
|
|
@@ -1400,6 +1440,7 @@ class BaseMemOpClusterMutation : public ScheduleDAGMutation {
|
|
|
SUnit *SU;
|
|
|
unsigned BaseReg;
|
|
|
int64_t Offset;
|
|
|
+
|
|
|
MemOpInfo(SUnit *su, unsigned reg, int64_t ofs)
|
|
|
: SU(su), BaseReg(reg), Offset(ofs) {}
|
|
|
|
|
@@ -1436,25 +1477,26 @@ public:
|
|
|
LoadClusterMutation(const TargetInstrInfo *tii, const TargetRegisterInfo *tri)
|
|
|
: BaseMemOpClusterMutation(tii, tri, true) {}
|
|
|
};
|
|
|
-} // anonymous
|
|
|
+
|
|
|
+} // end anonymous namespace
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
std::unique_ptr<ScheduleDAGMutation>
|
|
|
createLoadClusterDAGMutation(const TargetInstrInfo *TII,
|
|
|
const TargetRegisterInfo *TRI) {
|
|
|
- return EnableMemOpCluster ? make_unique<LoadClusterMutation>(TII, TRI)
|
|
|
+ return EnableMemOpCluster ? llvm::make_unique<LoadClusterMutation>(TII, TRI)
|
|
|
: nullptr;
|
|
|
}
|
|
|
|
|
|
std::unique_ptr<ScheduleDAGMutation>
|
|
|
createStoreClusterDAGMutation(const TargetInstrInfo *TII,
|
|
|
const TargetRegisterInfo *TRI) {
|
|
|
- return EnableMemOpCluster ? make_unique<StoreClusterMutation>(TII, TRI)
|
|
|
+ return EnableMemOpCluster ? llvm::make_unique<StoreClusterMutation>(TII, TRI)
|
|
|
: nullptr;
|
|
|
}
|
|
|
|
|
|
-} // namespace llvm
|
|
|
+} // end namespace llvm
|
|
|
|
|
|
void BaseMemOpClusterMutation::clusterNeighboringMemOps(
|
|
|
ArrayRef<SUnit *> MemOps, ScheduleDAGMI *DAG) {
|
|
@@ -1544,6 +1586,7 @@ void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAGInstrs) {
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
namespace {
|
|
|
+
|
|
|
/// \brief Post-process the DAG to create weak edges from all uses of a copy to
|
|
|
/// the one use that defines the copy's source vreg, most likely an induction
|
|
|
/// variable increment.
|
|
@@ -1553,6 +1596,7 @@ class CopyConstrain : public ScheduleDAGMutation {
|
|
|
// RegionEndIdx is the slot index of the last non-debug instruction in the
|
|
|
// scheduling region. So we may have RegionBeginIdx == RegionEndIdx.
|
|
|
SlotIndex RegionEndIdx;
|
|
|
+
|
|
|
public:
|
|
|
CopyConstrain(const TargetInstrInfo *, const TargetRegisterInfo *) {}
|
|
|
|
|
@@ -1561,17 +1605,18 @@ public:
|
|
|
protected:
|
|
|
void constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG);
|
|
|
};
|
|
|
-} // anonymous
|
|
|
+
|
|
|
+} // end anonymous namespace
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
std::unique_ptr<ScheduleDAGMutation>
|
|
|
createCopyConstrainDAGMutation(const TargetInstrInfo *TII,
|
|
|
- const TargetRegisterInfo *TRI) {
|
|
|
- return make_unique<CopyConstrain>(TII, TRI);
|
|
|
+ const TargetRegisterInfo *TRI) {
|
|
|
+ return llvm::make_unique<CopyConstrain>(TII, TRI);
|
|
|
}
|
|
|
|
|
|
-} // namespace llvm
|
|
|
+} // end namespace llvm
|
|
|
|
|
|
/// constrainLocalCopy handles two possibilities:
|
|
|
/// 1) Local src:
|
|
@@ -1763,7 +1808,7 @@ void SchedBoundary::reset() {
|
|
|
CheckPending = false;
|
|
|
CurrCycle = 0;
|
|
|
CurrMOps = 0;
|
|
|
- MinReadyCycle = UINT_MAX;
|
|
|
+ MinReadyCycle = std::numeric_limits<unsigned>::max();
|
|
|
ExpectedLatency = 0;
|
|
|
DependentLatency = 0;
|
|
|
RetiredMOps = 0;
|
|
@@ -1966,7 +2011,8 @@ void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle) {
|
|
|
/// Move the boundary of scheduled code by one cycle.
|
|
|
void SchedBoundary::bumpCycle(unsigned NextCycle) {
|
|
|
if (SchedModel->getMicroOpBufferSize() == 0) {
|
|
|
- assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized");
|
|
|
+ assert(MinReadyCycle < std::numeric_limits<unsigned>::max() &&
|
|
|
+ "MinReadyCycle uninitialized");
|
|
|
if (MinReadyCycle > NextCycle)
|
|
|
NextCycle = MinReadyCycle;
|
|
|
}
|
|
@@ -2177,7 +2223,7 @@ void SchedBoundary::bumpNode(SUnit *SU) {
|
|
|
void SchedBoundary::releasePending() {
|
|
|
// If the available queue is empty, it is safe to reset MinReadyCycle.
|
|
|
if (Available.empty())
|
|
|
- MinReadyCycle = UINT_MAX;
|
|
|
+ MinReadyCycle = std::numeric_limits<unsigned>::max();
|
|
|
|
|
|
// Check to see if any of the pending instructions are ready to issue. If
|
|
|
// so, add them to the available queue.
|
|
@@ -3036,7 +3082,6 @@ SUnit *GenericScheduler::pickNode(bool &IsTopNode) {
|
|
|
}
|
|
|
|
|
|
void GenericScheduler::reschedulePhysRegCopies(SUnit *SU, bool isTop) {
|
|
|
-
|
|
|
MachineBasicBlock::iterator InsertPos = SU->getInstr();
|
|
|
if (!isTop)
|
|
|
++InsertPos;
|
|
@@ -3084,7 +3129,8 @@ void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
|
|
|
/// Create the standard converging machine scheduler. This will be used as the
|
|
|
/// default scheduler if the target does not set a default.
|
|
|
ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) {
|
|
|
- ScheduleDAGMILive *DAG = new ScheduleDAGMILive(C, make_unique<GenericScheduler>(C));
|
|
|
+ ScheduleDAGMILive *DAG =
|
|
|
+ new ScheduleDAGMILive(C, llvm::make_unique<GenericScheduler>(C));
|
|
|
// Register DAG post-processors.
|
|
|
//
|
|
|
// FIXME: extend the mutation API to allow earlier mutations to instantiate
|
|
@@ -3125,7 +3171,6 @@ void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
void PostGenericScheduler::registerRoots() {
|
|
|
Rem.CriticalPath = DAG->ExitSU.getDepth();
|
|
|
|
|
@@ -3232,7 +3277,7 @@ void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
|
|
|
}
|
|
|
|
|
|
ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
|
|
|
- return new ScheduleDAGMI(C, make_unique<PostGenericScheduler>(C),
|
|
|
+ return new ScheduleDAGMI(C, llvm::make_unique<PostGenericScheduler>(C),
|
|
|
/*RemoveKillFlags=*/true);
|
|
|
}
|
|
|
|
|
@@ -3241,14 +3286,14 @@ ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
namespace {
|
|
|
+
|
|
|
/// \brief Order nodes by the ILP metric.
|
|
|
struct ILPOrder {
|
|
|
- const SchedDFSResult *DFSResult;
|
|
|
- const BitVector *ScheduledTrees;
|
|
|
+ const SchedDFSResult *DFSResult = nullptr;
|
|
|
+ const BitVector *ScheduledTrees = nullptr;
|
|
|
bool MaximizeILP;
|
|
|
|
|
|
- ILPOrder(bool MaxILP)
|
|
|
- : DFSResult(nullptr), ScheduledTrees(nullptr), MaximizeILP(MaxILP) {}
|
|
|
+ ILPOrder(bool MaxILP) : MaximizeILP(MaxILP) {}
|
|
|
|
|
|
/// \brief Apply a less-than relation on node priority.
|
|
|
///
|
|
@@ -3277,12 +3322,13 @@ struct ILPOrder {
|
|
|
|
|
|
/// \brief Schedule based on the ILP metric.
|
|
|
class ILPScheduler : public MachineSchedStrategy {
|
|
|
- ScheduleDAGMILive *DAG;
|
|
|
+ ScheduleDAGMILive *DAG = nullptr;
|
|
|
ILPOrder Cmp;
|
|
|
|
|
|
std::vector<SUnit*> ReadyQ;
|
|
|
+
|
|
|
public:
|
|
|
- ILPScheduler(bool MaximizeILP): DAG(nullptr), Cmp(MaximizeILP) {}
|
|
|
+ ILPScheduler(bool MaximizeILP) : Cmp(MaximizeILP) {}
|
|
|
|
|
|
void initialize(ScheduleDAGMI *dag) override {
|
|
|
assert(dag->hasVRegLiveness() && "ILPScheduler needs vreg liveness");
|
|
@@ -3335,14 +3381,16 @@ public:
|
|
|
std::push_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
|
|
|
}
|
|
|
};
|
|
|
-} // namespace
|
|
|
+
|
|
|
+} // end anonymous namespace
|
|
|
|
|
|
static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) {
|
|
|
- return new ScheduleDAGMILive(C, make_unique<ILPScheduler>(true));
|
|
|
+ return new ScheduleDAGMILive(C, llvm::make_unique<ILPScheduler>(true));
|
|
|
}
|
|
|
static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) {
|
|
|
- return new ScheduleDAGMILive(C, make_unique<ILPScheduler>(false));
|
|
|
+ return new ScheduleDAGMILive(C, llvm::make_unique<ILPScheduler>(false));
|
|
|
}
|
|
|
+
|
|
|
static MachineSchedRegistry ILPMaxRegistry(
|
|
|
"ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler);
|
|
|
static MachineSchedRegistry ILPMinRegistry(
|
|
@@ -3354,6 +3402,7 @@ static MachineSchedRegistry ILPMinRegistry(
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
namespace {
|
|
|
+
|
|
|
/// Apply a less-than relation on the node order, which corresponds to the
|
|
|
/// instruction order prior to scheduling. IsReverse implements greater-than.
|
|
|
template<bool IsReverse>
|
|
@@ -3374,11 +3423,12 @@ class InstructionShuffler : public MachineSchedStrategy {
|
|
|
// Using a less-than relation (SUnitOrder<false>) for the TopQ priority
|
|
|
// gives nodes with a higher number higher priority causing the latest
|
|
|
// instructions to be scheduled first.
|
|
|
- PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false> >
|
|
|
+ PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>>
|
|
|
TopQ;
|
|
|
// When scheduling bottom-up, use greater-than as the queue priority.
|
|
|
- PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true> >
|
|
|
+ PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>>
|
|
|
BottomQ;
|
|
|
+
|
|
|
public:
|
|
|
InstructionShuffler(bool alternate, bool topdown)
|
|
|
: IsAlternating(alternate), IsTopDown(topdown) {}
|
|
@@ -3422,15 +3472,18 @@ public:
|
|
|
BottomQ.push(SU);
|
|
|
}
|
|
|
};
|
|
|
-} // namespace
|
|
|
+
|
|
|
+} // end anonymous namespace
|
|
|
|
|
|
static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) {
|
|
|
bool Alternate = !ForceTopDown && !ForceBottomUp;
|
|
|
bool TopDown = !ForceBottomUp;
|
|
|
assert((TopDown || !ForceTopDown) &&
|
|
|
"-misched-topdown incompatible with -misched-bottomup");
|
|
|
- return new ScheduleDAGMILive(C, make_unique<InstructionShuffler>(Alternate, TopDown));
|
|
|
+ return new ScheduleDAGMILive(
|
|
|
+ C, llvm::make_unique<InstructionShuffler>(Alternate, TopDown));
|
|
|
}
|
|
|
+
|
|
|
static MachineSchedRegistry ShufflerRegistry(
|
|
|
"shuffle", "Shuffle machine instructions alternating directions",
|
|
|
createInstructionShuffler);
|
|
@@ -3448,8 +3501,7 @@ template<> struct GraphTraits<
|
|
|
|
|
|
template<>
|
|
|
struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
|
|
|
-
|
|
|
- DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
|
|
+ DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
|
|
|
|
|
|
static std::string getGraphName(const ScheduleDAG *G) {
|
|
|
return G->MF.getName();
|
|
@@ -3506,7 +3558,8 @@ struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
|
|
|
return Str;
|
|
|
}
|
|
|
};
|
|
|
-} // namespace llvm
|
|
|
+
|
|
|
+} // end namespace llvm
|
|
|
#endif // NDEBUG
|
|
|
|
|
|
/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
|