mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-09-26 09:18:56 +00:00
Add new entry/exit edges when removing delay slot nodes from the graph.
Renamed some header files. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@610 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
// $Id$
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
// File:
|
// File:
|
||||||
// InstrScheduling.cpp
|
// InstrScheduling.cpp
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
// History:
|
// History:
|
||||||
// 7/23/01 - Vikram Adve - Created
|
// 7/23/01 - Vikram Adve - Created
|
||||||
//***************************************************************************
|
//**************************************************************************/
|
||||||
|
|
||||||
#include "llvm/CodeGen/InstrScheduling.h"
|
#include "llvm/CodeGen/InstrScheduling.h"
|
||||||
#include "SchedPriorities.h"
|
#include "SchedPriorities.h"
|
||||||
@@ -68,6 +69,7 @@ static bool NodeCanFillDelaySlot (const SchedulingManager& S,
|
|||||||
bool nodeIsPredecessor);
|
bool nodeIsPredecessor);
|
||||||
|
|
||||||
static void MarkNodeForDelaySlot (SchedulingManager& S,
|
static void MarkNodeForDelaySlot (SchedulingManager& S,
|
||||||
|
SchedGraph* graph,
|
||||||
SchedGraphNode* node,
|
SchedGraphNode* node,
|
||||||
const SchedGraphNode* brNode,
|
const SchedGraphNode* brNode,
|
||||||
bool nodeIsPredecessor);
|
bool nodeIsPredecessor);
|
||||||
@@ -397,7 +399,6 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/*ctor*/ SchedulingManager (const TargetMachine& _target,
|
/*ctor*/ SchedulingManager (const TargetMachine& _target,
|
||||||
const MachineSchedInfo &schedinfo,
|
|
||||||
const SchedGraph* graph,
|
const SchedGraph* graph,
|
||||||
SchedPriorities& schedPrio);
|
SchedPriorities& schedPrio);
|
||||||
/*dtor*/ ~SchedulingManager () {}
|
/*dtor*/ ~SchedulingManager () {}
|
||||||
@@ -559,17 +560,16 @@ private:
|
|||||||
|
|
||||||
/*ctor*/
|
/*ctor*/
|
||||||
SchedulingManager::SchedulingManager(const TargetMachine& target,
|
SchedulingManager::SchedulingManager(const TargetMachine& target,
|
||||||
const MachineSchedInfo &schedinfo,
|
|
||||||
const SchedGraph* graph,
|
const SchedGraph* graph,
|
||||||
SchedPriorities& _schedPrio)
|
SchedPriorities& _schedPrio)
|
||||||
: nslots(schedinfo.getMaxNumIssueTotal()),
|
: nslots(target.getSchedInfo().getMaxNumIssueTotal()),
|
||||||
schedInfo(schedinfo),
|
schedInfo(target.getSchedInfo()),
|
||||||
schedPrio(_schedPrio),
|
schedPrio(_schedPrio),
|
||||||
isched(nslots, graph->getNumNodes()),
|
isched(nslots, graph->getNumNodes()),
|
||||||
totalInstrCount(graph->getNumNodes() - 2),
|
totalInstrCount(graph->getNumNodes() - 2),
|
||||||
nextEarliestIssueTime(0),
|
nextEarliestIssueTime(0),
|
||||||
choicesForSlot(nslots),
|
choicesForSlot(nslots),
|
||||||
numInClass(schedinfo.getNumSchedClasses(), 0), // set all to 0
|
numInClass(target.getSchedInfo().getNumSchedClasses(), 0), // set all to 0
|
||||||
nextEarliestStartTime(target.getInstrInfo().getNumRealOpCodes(),
|
nextEarliestStartTime(target.getInstrInfo().getNumRealOpCodes(),
|
||||||
(cycles_t) 0) // set all to 0
|
(cycles_t) 0) // set all to 0
|
||||||
{
|
{
|
||||||
@@ -621,8 +621,10 @@ SchedulingManager::updateEarliestStartTimes(const SchedGraphNode* node,
|
|||||||
// are still in SSA form.
|
// are still in SSA form.
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool ScheduleInstructionsWithSSA(Method* method, const TargetMachine &target,
|
bool
|
||||||
const MachineSchedInfo &schedInfo) {
|
ScheduleInstructionsWithSSA(Method* method,
|
||||||
|
const TargetMachine &target)
|
||||||
|
{
|
||||||
SchedGraphSet graphSet(method, target);
|
SchedGraphSet graphSet(method, target);
|
||||||
|
|
||||||
if (SchedDebugLevel >= Sched_PrintSchedGraphs)
|
if (SchedDebugLevel >= Sched_PrintSchedGraphs)
|
||||||
@@ -644,7 +646,7 @@ bool ScheduleInstructionsWithSSA(Method* method, const TargetMachine &target,
|
|||||||
cout << endl << "*** TRACE OF INSTRUCTION SCHEDULING OPERATIONS\n\n";
|
cout << endl << "*** TRACE OF INSTRUCTION SCHEDULING OPERATIONS\n\n";
|
||||||
|
|
||||||
SchedPriorities schedPrio(method, graph); // expensive!
|
SchedPriorities schedPrio(method, graph); // expensive!
|
||||||
SchedulingManager S(target, schedInfo, graph, schedPrio);
|
SchedulingManager S(target, graph, schedPrio);
|
||||||
|
|
||||||
ChooseInstructionsForDelaySlots(S, bb, graph); // modifies graph
|
ChooseInstructionsForDelaySlots(S, bb, graph); // modifies graph
|
||||||
|
|
||||||
@@ -718,6 +720,7 @@ instrIsFeasible(const SchedulingManager& S,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//************************* Internal Functions *****************************/
|
//************************* Internal Functions *****************************/
|
||||||
|
|
||||||
|
|
||||||
@@ -771,21 +774,32 @@ ForwardListSchedule(SchedulingManager& S)
|
|||||||
static void
|
static void
|
||||||
RecordSchedule(const BasicBlock* bb, const SchedulingManager& S)
|
RecordSchedule(const BasicBlock* bb, const SchedulingManager& S)
|
||||||
{
|
{
|
||||||
|
MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
|
||||||
|
const MachineInstrInfo& mii = S.schedInfo.getInstrInfo();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Lets make sure we didn't lose any instructions, except possibly
|
||||||
|
// some NOPs from delay slots. Also, PHIs are not included in the schedule.
|
||||||
|
unsigned numInstr = 0;
|
||||||
|
for (MachineCodeForBasicBlock::iterator I=mvec.begin(); I != mvec.end(); ++I)
|
||||||
|
if (! mii.isNop((*I)->getOpCode()) &&
|
||||||
|
! mii.isDummyPhiInstr((*I)->getOpCode()))
|
||||||
|
++numInstr;
|
||||||
|
assert(S.isched.getNumInstructions() >= numInstr &&
|
||||||
|
"Lost some non-NOP instructions during scheduling!");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (S.isched.getNumInstructions() == 0)
|
if (S.isched.getNumInstructions() == 0)
|
||||||
return; // empty basic block!
|
return; // empty basic block!
|
||||||
|
|
||||||
MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
|
|
||||||
unsigned int oldSize = mvec.size();
|
|
||||||
|
|
||||||
// First find the dummy instructions at the start of the basic block
|
// First find the dummy instructions at the start of the basic block
|
||||||
const MachineInstrInfo& mii = S.schedInfo.getInstrInfo();
|
|
||||||
MachineCodeForBasicBlock::iterator I = mvec.begin();
|
MachineCodeForBasicBlock::iterator I = mvec.begin();
|
||||||
for ( ; I != mvec.end(); ++I)
|
for ( ; I != mvec.end(); ++I)
|
||||||
if (! mii.isDummyPhiInstr((*I)->getOpCode()))
|
if (! mii.isDummyPhiInstr((*I)->getOpCode()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Erase all except the dummy PHI instructions from mvec, and
|
// Erase all except the dummy PHI instructions from mvec, and
|
||||||
// pre-allocate create space for the ones we will be put back in.
|
// pre-allocate create space for the ones we will put back in.
|
||||||
mvec.erase(I, mvec.end());
|
mvec.erase(I, mvec.end());
|
||||||
mvec.reserve(mvec.size() + S.isched.getNumInstructions());
|
mvec.reserve(mvec.size() + S.isched.getNumInstructions());
|
||||||
|
|
||||||
@@ -801,7 +815,7 @@ ChooseOneGroup(SchedulingManager& S)
|
|||||||
assert(S.schedPrio.getNumReady() > 0
|
assert(S.schedPrio.getNumReady() > 0
|
||||||
&& "Don't get here without ready instructions.");
|
&& "Don't get here without ready instructions.");
|
||||||
|
|
||||||
DelaySlotInfo* getDelaySlotInfo;
|
DelaySlotInfo* getDelaySlotInfo = NULL;
|
||||||
|
|
||||||
// Choose up to `nslots' feasible instructions and their possible slots.
|
// Choose up to `nslots' feasible instructions and their possible slots.
|
||||||
unsigned numIssued = FindSlotChoices(S, getDelaySlotInfo);
|
unsigned numIssued = FindSlotChoices(S, getDelaySlotInfo);
|
||||||
@@ -1289,11 +1303,11 @@ ChooseInstructionsForDelaySlots(SchedulingManager& S,
|
|||||||
|
|
||||||
// Mark the nodes chosen for delay slots. This removes them from the graph.
|
// Mark the nodes chosen for delay slots. This removes them from the graph.
|
||||||
for (unsigned i=0; i < sdelayNodeVec.size(); i++)
|
for (unsigned i=0; i < sdelayNodeVec.size(); i++)
|
||||||
MarkNodeForDelaySlot(S, sdelayNodeVec[i], brNode, true);
|
MarkNodeForDelaySlot(S, graph, sdelayNodeVec[i], brNode, true);
|
||||||
|
|
||||||
// And remove the unused NOPs the graph.
|
// And remove the unused NOPs from the graph.
|
||||||
for (unsigned i=0; i < nopNodeVec.size(); i++)
|
for (unsigned i=0; i < nopNodeVec.size(); i++)
|
||||||
nopNodeVec[i]->eraseAllEdges();
|
graph->eraseIncidentEdges(nopNodeVec[i], /*addDummyEdges*/ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1355,14 +1369,16 @@ NodeCanFillDelaySlot(const SchedulingManager& S,
|
|||||||
|
|
||||||
void
|
void
|
||||||
MarkNodeForDelaySlot(SchedulingManager& S,
|
MarkNodeForDelaySlot(SchedulingManager& S,
|
||||||
|
SchedGraph* graph,
|
||||||
SchedGraphNode* node,
|
SchedGraphNode* node,
|
||||||
const SchedGraphNode* brNode,
|
const SchedGraphNode* brNode,
|
||||||
bool nodeIsPredecessor)
|
bool nodeIsPredecessor)
|
||||||
{
|
{
|
||||||
if (nodeIsPredecessor)
|
if (nodeIsPredecessor)
|
||||||
{ // If node is in the same basic block (i.e., preceeds brNode),
|
{ // If node is in the same basic block (i.e., preceeds brNode),
|
||||||
// remove it and all its incident edges from the graph.
|
// remove it and all its incident edges from the graph. Make sure we
|
||||||
node->eraseAllEdges();
|
// add dummy edges for pred/succ nodes that become entry/exit nodes.
|
||||||
|
graph->eraseIncidentEdges(node, /*addDummyEdges*/ true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // If the node was from a target block, add the node to the graph
|
{ // If the node was from a target block, add the node to the graph
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// $Id$
|
||||||
//***************************************************************************
|
//***************************************************************************
|
||||||
// File:
|
// File:
|
||||||
// InstrScheduling.cpp
|
// InstrScheduling.cpp
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
// History:
|
// History:
|
||||||
// 7/23/01 - Vikram Adve - Created
|
// 7/23/01 - Vikram Adve - Created
|
||||||
//***************************************************************************
|
//**************************************************************************/
|
||||||
|
|
||||||
#include "llvm/CodeGen/InstrScheduling.h"
|
#include "llvm/CodeGen/InstrScheduling.h"
|
||||||
#include "SchedPriorities.h"
|
#include "SchedPriorities.h"
|
||||||
@@ -68,6 +69,7 @@ static bool NodeCanFillDelaySlot (const SchedulingManager& S,
|
|||||||
bool nodeIsPredecessor);
|
bool nodeIsPredecessor);
|
||||||
|
|
||||||
static void MarkNodeForDelaySlot (SchedulingManager& S,
|
static void MarkNodeForDelaySlot (SchedulingManager& S,
|
||||||
|
SchedGraph* graph,
|
||||||
SchedGraphNode* node,
|
SchedGraphNode* node,
|
||||||
const SchedGraphNode* brNode,
|
const SchedGraphNode* brNode,
|
||||||
bool nodeIsPredecessor);
|
bool nodeIsPredecessor);
|
||||||
@@ -397,7 +399,6 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/*ctor*/ SchedulingManager (const TargetMachine& _target,
|
/*ctor*/ SchedulingManager (const TargetMachine& _target,
|
||||||
const MachineSchedInfo &schedinfo,
|
|
||||||
const SchedGraph* graph,
|
const SchedGraph* graph,
|
||||||
SchedPriorities& schedPrio);
|
SchedPriorities& schedPrio);
|
||||||
/*dtor*/ ~SchedulingManager () {}
|
/*dtor*/ ~SchedulingManager () {}
|
||||||
@@ -559,17 +560,16 @@ private:
|
|||||||
|
|
||||||
/*ctor*/
|
/*ctor*/
|
||||||
SchedulingManager::SchedulingManager(const TargetMachine& target,
|
SchedulingManager::SchedulingManager(const TargetMachine& target,
|
||||||
const MachineSchedInfo &schedinfo,
|
|
||||||
const SchedGraph* graph,
|
const SchedGraph* graph,
|
||||||
SchedPriorities& _schedPrio)
|
SchedPriorities& _schedPrio)
|
||||||
: nslots(schedinfo.getMaxNumIssueTotal()),
|
: nslots(target.getSchedInfo().getMaxNumIssueTotal()),
|
||||||
schedInfo(schedinfo),
|
schedInfo(target.getSchedInfo()),
|
||||||
schedPrio(_schedPrio),
|
schedPrio(_schedPrio),
|
||||||
isched(nslots, graph->getNumNodes()),
|
isched(nslots, graph->getNumNodes()),
|
||||||
totalInstrCount(graph->getNumNodes() - 2),
|
totalInstrCount(graph->getNumNodes() - 2),
|
||||||
nextEarliestIssueTime(0),
|
nextEarliestIssueTime(0),
|
||||||
choicesForSlot(nslots),
|
choicesForSlot(nslots),
|
||||||
numInClass(schedinfo.getNumSchedClasses(), 0), // set all to 0
|
numInClass(target.getSchedInfo().getNumSchedClasses(), 0), // set all to 0
|
||||||
nextEarliestStartTime(target.getInstrInfo().getNumRealOpCodes(),
|
nextEarliestStartTime(target.getInstrInfo().getNumRealOpCodes(),
|
||||||
(cycles_t) 0) // set all to 0
|
(cycles_t) 0) // set all to 0
|
||||||
{
|
{
|
||||||
@@ -621,8 +621,10 @@ SchedulingManager::updateEarliestStartTimes(const SchedGraphNode* node,
|
|||||||
// are still in SSA form.
|
// are still in SSA form.
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool ScheduleInstructionsWithSSA(Method* method, const TargetMachine &target,
|
bool
|
||||||
const MachineSchedInfo &schedInfo) {
|
ScheduleInstructionsWithSSA(Method* method,
|
||||||
|
const TargetMachine &target)
|
||||||
|
{
|
||||||
SchedGraphSet graphSet(method, target);
|
SchedGraphSet graphSet(method, target);
|
||||||
|
|
||||||
if (SchedDebugLevel >= Sched_PrintSchedGraphs)
|
if (SchedDebugLevel >= Sched_PrintSchedGraphs)
|
||||||
@@ -644,7 +646,7 @@ bool ScheduleInstructionsWithSSA(Method* method, const TargetMachine &target,
|
|||||||
cout << endl << "*** TRACE OF INSTRUCTION SCHEDULING OPERATIONS\n\n";
|
cout << endl << "*** TRACE OF INSTRUCTION SCHEDULING OPERATIONS\n\n";
|
||||||
|
|
||||||
SchedPriorities schedPrio(method, graph); // expensive!
|
SchedPriorities schedPrio(method, graph); // expensive!
|
||||||
SchedulingManager S(target, schedInfo, graph, schedPrio);
|
SchedulingManager S(target, graph, schedPrio);
|
||||||
|
|
||||||
ChooseInstructionsForDelaySlots(S, bb, graph); // modifies graph
|
ChooseInstructionsForDelaySlots(S, bb, graph); // modifies graph
|
||||||
|
|
||||||
@@ -718,6 +720,7 @@ instrIsFeasible(const SchedulingManager& S,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//************************* Internal Functions *****************************/
|
//************************* Internal Functions *****************************/
|
||||||
|
|
||||||
|
|
||||||
@@ -771,21 +774,32 @@ ForwardListSchedule(SchedulingManager& S)
|
|||||||
static void
|
static void
|
||||||
RecordSchedule(const BasicBlock* bb, const SchedulingManager& S)
|
RecordSchedule(const BasicBlock* bb, const SchedulingManager& S)
|
||||||
{
|
{
|
||||||
|
MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
|
||||||
|
const MachineInstrInfo& mii = S.schedInfo.getInstrInfo();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Lets make sure we didn't lose any instructions, except possibly
|
||||||
|
// some NOPs from delay slots. Also, PHIs are not included in the schedule.
|
||||||
|
unsigned numInstr = 0;
|
||||||
|
for (MachineCodeForBasicBlock::iterator I=mvec.begin(); I != mvec.end(); ++I)
|
||||||
|
if (! mii.isNop((*I)->getOpCode()) &&
|
||||||
|
! mii.isDummyPhiInstr((*I)->getOpCode()))
|
||||||
|
++numInstr;
|
||||||
|
assert(S.isched.getNumInstructions() >= numInstr &&
|
||||||
|
"Lost some non-NOP instructions during scheduling!");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (S.isched.getNumInstructions() == 0)
|
if (S.isched.getNumInstructions() == 0)
|
||||||
return; // empty basic block!
|
return; // empty basic block!
|
||||||
|
|
||||||
MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
|
|
||||||
unsigned int oldSize = mvec.size();
|
|
||||||
|
|
||||||
// First find the dummy instructions at the start of the basic block
|
// First find the dummy instructions at the start of the basic block
|
||||||
const MachineInstrInfo& mii = S.schedInfo.getInstrInfo();
|
|
||||||
MachineCodeForBasicBlock::iterator I = mvec.begin();
|
MachineCodeForBasicBlock::iterator I = mvec.begin();
|
||||||
for ( ; I != mvec.end(); ++I)
|
for ( ; I != mvec.end(); ++I)
|
||||||
if (! mii.isDummyPhiInstr((*I)->getOpCode()))
|
if (! mii.isDummyPhiInstr((*I)->getOpCode()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Erase all except the dummy PHI instructions from mvec, and
|
// Erase all except the dummy PHI instructions from mvec, and
|
||||||
// pre-allocate create space for the ones we will be put back in.
|
// pre-allocate create space for the ones we will put back in.
|
||||||
mvec.erase(I, mvec.end());
|
mvec.erase(I, mvec.end());
|
||||||
mvec.reserve(mvec.size() + S.isched.getNumInstructions());
|
mvec.reserve(mvec.size() + S.isched.getNumInstructions());
|
||||||
|
|
||||||
@@ -801,7 +815,7 @@ ChooseOneGroup(SchedulingManager& S)
|
|||||||
assert(S.schedPrio.getNumReady() > 0
|
assert(S.schedPrio.getNumReady() > 0
|
||||||
&& "Don't get here without ready instructions.");
|
&& "Don't get here without ready instructions.");
|
||||||
|
|
||||||
DelaySlotInfo* getDelaySlotInfo;
|
DelaySlotInfo* getDelaySlotInfo = NULL;
|
||||||
|
|
||||||
// Choose up to `nslots' feasible instructions and their possible slots.
|
// Choose up to `nslots' feasible instructions and their possible slots.
|
||||||
unsigned numIssued = FindSlotChoices(S, getDelaySlotInfo);
|
unsigned numIssued = FindSlotChoices(S, getDelaySlotInfo);
|
||||||
@@ -1289,11 +1303,11 @@ ChooseInstructionsForDelaySlots(SchedulingManager& S,
|
|||||||
|
|
||||||
// Mark the nodes chosen for delay slots. This removes them from the graph.
|
// Mark the nodes chosen for delay slots. This removes them from the graph.
|
||||||
for (unsigned i=0; i < sdelayNodeVec.size(); i++)
|
for (unsigned i=0; i < sdelayNodeVec.size(); i++)
|
||||||
MarkNodeForDelaySlot(S, sdelayNodeVec[i], brNode, true);
|
MarkNodeForDelaySlot(S, graph, sdelayNodeVec[i], brNode, true);
|
||||||
|
|
||||||
// And remove the unused NOPs the graph.
|
// And remove the unused NOPs from the graph.
|
||||||
for (unsigned i=0; i < nopNodeVec.size(); i++)
|
for (unsigned i=0; i < nopNodeVec.size(); i++)
|
||||||
nopNodeVec[i]->eraseAllEdges();
|
graph->eraseIncidentEdges(nopNodeVec[i], /*addDummyEdges*/ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1355,14 +1369,16 @@ NodeCanFillDelaySlot(const SchedulingManager& S,
|
|||||||
|
|
||||||
void
|
void
|
||||||
MarkNodeForDelaySlot(SchedulingManager& S,
|
MarkNodeForDelaySlot(SchedulingManager& S,
|
||||||
|
SchedGraph* graph,
|
||||||
SchedGraphNode* node,
|
SchedGraphNode* node,
|
||||||
const SchedGraphNode* brNode,
|
const SchedGraphNode* brNode,
|
||||||
bool nodeIsPredecessor)
|
bool nodeIsPredecessor)
|
||||||
{
|
{
|
||||||
if (nodeIsPredecessor)
|
if (nodeIsPredecessor)
|
||||||
{ // If node is in the same basic block (i.e., preceeds brNode),
|
{ // If node is in the same basic block (i.e., preceeds brNode),
|
||||||
// remove it and all its incident edges from the graph.
|
// remove it and all its incident edges from the graph. Make sure we
|
||||||
node->eraseAllEdges();
|
// add dummy edges for pred/succ nodes that become entry/exit nodes.
|
||||||
|
graph->eraseIncidentEdges(node, /*addDummyEdges*/ true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // If the node was from a target block, add the node to the graph
|
{ // If the node was from a target block, add the node to the graph
|
||||||
|
Reference in New Issue
Block a user