2006-01-21 02:32:06 +00:00
|
|
|
//===---- ScheduleDAG.cpp - Implement the ScheduleDAG class ---------------===//
|
2005-08-18 18:45:24 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-08-18 18:45:24 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-07-11 22:39:58 +00:00
|
|
|
// This implements the ScheduleDAG class, which is a base class used by
|
|
|
|
// scheduling implementation classes.
|
2005-08-18 18:45:24 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2007-07-13 17:13:54 +00:00
|
|
|
#define DEBUG_TYPE "pre-RA-sched"
|
2007-01-12 23:31:12 +00:00
|
|
|
#include "llvm/Type.h"
|
2006-03-08 04:25:59 +00:00
|
|
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
2005-08-26 17:15:30 +00:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
2005-08-19 20:45:43 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2008-04-03 16:36:07 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2007-12-31 04:13:23 +00:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2006-05-12 06:33:49 +00:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2005-08-18 20:07:59 +00:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
2005-08-26 20:54:47 +00:00
|
|
|
#include "llvm/Target/TargetLowering.h"
|
2008-02-28 07:40:24 +00:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2006-05-11 23:55:42 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2006-03-20 01:51:46 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2005-08-18 18:45:24 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2008-02-28 07:40:24 +00:00
|
|
|
STATISTIC(NumCommutes, "Number of instructions commuted");
|
|
|
|
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
namespace {
|
|
|
|
static cl::opt<bool>
|
|
|
|
SchedLiveInCopies("schedule-livein-copies",
|
|
|
|
cl::desc("Schedule copies of livein registers"),
|
|
|
|
cl::init(false));
|
|
|
|
}
|
|
|
|
|
2007-12-31 04:13:23 +00:00
|
|
|
ScheduleDAG::ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
|
|
|
|
const TargetMachine &tm)
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
: DAG(dag), BB(bb), TM(tm), MRI(BB->getParent()->getRegInfo()) {
|
2008-04-03 16:36:07 +00:00
|
|
|
TII = TM.getInstrInfo();
|
|
|
|
MF = &DAG.getMachineFunction();
|
|
|
|
TRI = TM.getRegisterInfo();
|
|
|
|
TLI = &DAG.getTargetLoweringInfo();
|
|
|
|
ConstPool = BB->getParent()->getConstantPool();
|
2007-12-31 04:13:23 +00:00
|
|
|
}
|
2007-09-25 01:54:36 +00:00
|
|
|
|
|
|
|
/// CheckForPhysRegDependency - Check if the dependency between def and use of
|
|
|
|
/// a specified operand is a physical register dependency. If so, returns the
|
|
|
|
/// register and the cost of copying the register.
|
|
|
|
static void CheckForPhysRegDependency(SDNode *Def, SDNode *Use, unsigned Op,
|
2008-02-10 18:45:23 +00:00
|
|
|
const TargetRegisterInfo *TRI,
|
2007-09-25 01:54:36 +00:00
|
|
|
const TargetInstrInfo *TII,
|
|
|
|
unsigned &PhysReg, int &Cost) {
|
|
|
|
if (Op != 2 || Use->getOpcode() != ISD::CopyToReg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Use->getOperand(1))->getReg();
|
2008-02-10 18:45:23 +00:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
2007-09-25 01:54:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned ResNo = Use->getOperand(2).ResNo;
|
|
|
|
if (Def->isTargetOpcode()) {
|
2008-01-07 07:27:27 +00:00
|
|
|
const TargetInstrDesc &II = TII->get(Def->getTargetOpcode());
|
2008-01-07 03:13:06 +00:00
|
|
|
if (ResNo >= II.getNumDefs() &&
|
|
|
|
II.ImplicitDefs[ResNo - II.getNumDefs()] == Reg) {
|
2007-09-25 01:54:36 +00:00
|
|
|
PhysReg = Reg;
|
|
|
|
const TargetRegisterClass *RC =
|
2008-03-11 07:19:34 +00:00
|
|
|
TRI->getPhysicalRegisterRegClass(Reg, Def->getValueType(ResNo));
|
2007-09-25 01:54:36 +00:00
|
|
|
Cost = RC->getCopyCost();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SUnit *ScheduleDAG::Clone(SUnit *Old) {
|
|
|
|
SUnit *SU = NewSUnit(Old->Node);
|
2008-06-21 15:52:51 +00:00
|
|
|
SU->OrigNode = Old->OrigNode;
|
2008-03-10 23:48:14 +00:00
|
|
|
SU->FlaggedNodes = Old->FlaggedNodes;
|
2007-09-25 01:54:36 +00:00
|
|
|
SU->Latency = Old->Latency;
|
|
|
|
SU->isTwoAddress = Old->isTwoAddress;
|
|
|
|
SU->isCommutable = Old->isCommutable;
|
2007-09-28 22:32:30 +00:00
|
|
|
SU->hasPhysRegDefs = Old->hasPhysRegDefs;
|
2007-09-25 01:54:36 +00:00
|
|
|
return SU;
|
|
|
|
}
|
|
|
|
|
2007-10-05 01:39:18 +00:00
|
|
|
|
2006-05-11 23:55:42 +00:00
|
|
|
/// BuildSchedUnits - Build SUnits from the selection dag that we are input.
|
|
|
|
/// This SUnit graph is similar to the SelectionDAG, but represents flagged
|
|
|
|
/// together nodes with a single SUnit.
|
|
|
|
void ScheduleDAG::BuildSchedUnits() {
|
|
|
|
// Reserve entries in the vector for each of the SUnits we are creating. This
|
|
|
|
// ensure that reallocation of the vector won't happen, so SUnit*'s won't get
|
|
|
|
// invalidated.
|
2008-06-20 17:15:19 +00:00
|
|
|
SUnits.reserve(DAG.allnodes_size());
|
2006-05-11 23:55:42 +00:00
|
|
|
|
2008-06-21 19:18:17 +00:00
|
|
|
// During scheduling, the NodeId field of SDNode is used to map SDNodes
|
|
|
|
// to their associated SUnits by holding SUnits table indices. A value
|
|
|
|
// of -1 means the SDNode does not yet have an associated SUnit.
|
|
|
|
for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin(),
|
|
|
|
E = DAG.allnodes_end(); NI != E; ++NI)
|
|
|
|
NI->setNodeId(-1);
|
|
|
|
|
2006-05-11 23:55:42 +00:00
|
|
|
for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin(),
|
|
|
|
E = DAG.allnodes_end(); NI != E; ++NI) {
|
|
|
|
if (isPassiveNode(NI)) // Leaf node, e.g. a TargetImmediate.
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If this node has already been processed, stop now.
|
2008-06-21 19:18:17 +00:00
|
|
|
if (NI->getNodeId() != -1) continue;
|
2006-05-11 23:55:42 +00:00
|
|
|
|
|
|
|
SUnit *NodeSUnit = NewSUnit(NI);
|
|
|
|
|
|
|
|
// See if anything is flagged to this node, if so, add them to flagged
|
|
|
|
// nodes. Nodes can have at most one flag input and one flag output. Flags
|
|
|
|
// are required the be the last operand and result of a node.
|
|
|
|
|
|
|
|
// Scan up, adding flagged preds to FlaggedNodes.
|
|
|
|
SDNode *N = NI;
|
2006-08-07 22:12:12 +00:00
|
|
|
if (N->getNumOperands() &&
|
|
|
|
N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Flag) {
|
|
|
|
do {
|
|
|
|
N = N->getOperand(N->getNumOperands()-1).Val;
|
|
|
|
NodeSUnit->FlaggedNodes.push_back(N);
|
2008-06-21 19:18:17 +00:00
|
|
|
assert(N->getNodeId() == -1 && "Node already inserted!");
|
|
|
|
N->setNodeId(NodeSUnit->NodeNum);
|
2006-08-07 22:12:12 +00:00
|
|
|
} while (N->getNumOperands() &&
|
|
|
|
N->getOperand(N->getNumOperands()-1).getValueType()== MVT::Flag);
|
|
|
|
std::reverse(NodeSUnit->FlaggedNodes.begin(),
|
|
|
|
NodeSUnit->FlaggedNodes.end());
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Scan down, adding this node and any flagged succs to FlaggedNodes if they
|
|
|
|
// have a user of the flag operand.
|
|
|
|
N = NI;
|
|
|
|
while (N->getValueType(N->getNumValues()-1) == MVT::Flag) {
|
|
|
|
SDOperand FlagVal(N, N->getNumValues()-1);
|
|
|
|
|
|
|
|
// There are either zero or one users of the Flag result.
|
|
|
|
bool HasFlagUse = false;
|
|
|
|
for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end();
|
|
|
|
UI != E; ++UI)
|
2008-04-07 10:06:32 +00:00
|
|
|
if (FlagVal.isOperandOf(UI->getUser())) {
|
2006-05-11 23:55:42 +00:00
|
|
|
HasFlagUse = true;
|
|
|
|
NodeSUnit->FlaggedNodes.push_back(N);
|
2008-06-21 19:18:17 +00:00
|
|
|
assert(N->getNodeId() == -1 && "Node already inserted!");
|
|
|
|
N->setNodeId(NodeSUnit->NodeNum);
|
2008-04-07 10:06:32 +00:00
|
|
|
N = UI->getUser();
|
2006-05-11 23:55:42 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-08-17 00:09:56 +00:00
|
|
|
if (!HasFlagUse) break;
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now all flagged nodes are in FlaggedNodes and N is the bottom-most node.
|
|
|
|
// Update the SUnit
|
|
|
|
NodeSUnit->Node = N;
|
2008-06-21 19:18:17 +00:00
|
|
|
assert(N->getNodeId() == -1 && "Node already inserted!");
|
|
|
|
N->setNodeId(NodeSUnit->NodeNum);
|
2007-10-05 01:39:18 +00:00
|
|
|
|
|
|
|
ComputeLatency(NodeSUnit);
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pass 2: add the preds, succs, etc.
|
|
|
|
for (unsigned su = 0, e = SUnits.size(); su != e; ++su) {
|
|
|
|
SUnit *SU = &SUnits[su];
|
|
|
|
SDNode *MainNode = SU->Node;
|
|
|
|
|
|
|
|
if (MainNode->isTargetOpcode()) {
|
|
|
|
unsigned Opc = MainNode->getTargetOpcode();
|
2008-01-07 07:27:27 +00:00
|
|
|
const TargetInstrDesc &TID = TII->get(Opc);
|
2008-01-07 03:13:06 +00:00
|
|
|
for (unsigned i = 0; i != TID.getNumOperands(); ++i) {
|
2007-09-25 01:54:36 +00:00
|
|
|
if (TID.getOperandConstraint(i, TOI::TIED_TO) != -1) {
|
2006-11-04 09:44:31 +00:00
|
|
|
SU->isTwoAddress = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-01-07 06:42:05 +00:00
|
|
|
if (TID.isCommutable())
|
2006-05-12 01:58:24 +00:00
|
|
|
SU->isCommutable = true;
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find all predecessors and successors of the group.
|
|
|
|
// Temporarily add N to make code simpler.
|
|
|
|
SU->FlaggedNodes.push_back(MainNode);
|
|
|
|
|
|
|
|
for (unsigned n = 0, e = SU->FlaggedNodes.size(); n != e; ++n) {
|
|
|
|
SDNode *N = SU->FlaggedNodes[n];
|
2007-09-28 22:32:30 +00:00
|
|
|
if (N->isTargetOpcode() &&
|
2008-01-07 03:13:06 +00:00
|
|
|
TII->get(N->getTargetOpcode()).getImplicitDefs() &&
|
|
|
|
CountResults(N) > TII->get(N->getTargetOpcode()).getNumDefs())
|
2007-09-28 22:32:30 +00:00
|
|
|
SU->hasPhysRegDefs = true;
|
2006-05-11 23:55:42 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
|
|
|
|
SDNode *OpN = N->getOperand(i).Val;
|
|
|
|
if (isPassiveNode(OpN)) continue; // Not scheduled.
|
2008-06-21 19:18:17 +00:00
|
|
|
SUnit *OpSU = &SUnits[OpN->getNodeId()];
|
2006-05-11 23:55:42 +00:00
|
|
|
assert(OpSU && "Node has no SUnit!");
|
|
|
|
if (OpSU == SU) continue; // In the same group.
|
|
|
|
|
2008-06-06 12:08:01 +00:00
|
|
|
MVT OpVT = N->getOperand(i).getValueType();
|
2006-05-11 23:55:42 +00:00
|
|
|
assert(OpVT != MVT::Flag && "Flagged nodes should be in same sunit!");
|
|
|
|
bool isChain = OpVT == MVT::Other;
|
2007-09-25 01:54:36 +00:00
|
|
|
|
|
|
|
unsigned PhysReg = 0;
|
|
|
|
int Cost = 1;
|
|
|
|
// Determine if this is a physical register dependency.
|
2008-02-10 18:45:23 +00:00
|
|
|
CheckForPhysRegDependency(OpN, N, i, TRI, TII, PhysReg, Cost);
|
2007-09-25 01:54:36 +00:00
|
|
|
SU->addPred(OpSU, isChain, false, PhysReg, Cost);
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove MainNode from FlaggedNodes again.
|
|
|
|
SU->FlaggedNodes.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-05 01:39:18 +00:00
|
|
|
void ScheduleDAG::ComputeLatency(SUnit *SU) {
|
|
|
|
const InstrItineraryData &InstrItins = TM.getInstrItineraryData();
|
|
|
|
|
|
|
|
// Compute the latency for the node. We use the sum of the latencies for
|
|
|
|
// all nodes flagged together into this SUnit.
|
|
|
|
if (InstrItins.isEmpty()) {
|
|
|
|
// No latency information.
|
|
|
|
SU->Latency = 1;
|
2008-07-02 09:23:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SU->Latency = 0;
|
|
|
|
if (SU->Node->isTargetOpcode()) {
|
|
|
|
unsigned SchedClass = TII->get(SU->Node->getTargetOpcode()).getSchedClass();
|
|
|
|
const InstrStage *S = InstrItins.begin(SchedClass);
|
|
|
|
const InstrStage *E = InstrItins.end(SchedClass);
|
|
|
|
for (; S != E; ++S)
|
|
|
|
SU->Latency += S->Cycles;
|
|
|
|
}
|
|
|
|
for (unsigned i = 0, e = SU->FlaggedNodes.size(); i != e; ++i) {
|
|
|
|
SDNode *FNode = SU->FlaggedNodes[i];
|
|
|
|
if (FNode->isTargetOpcode()) {
|
|
|
|
unsigned SchedClass = TII->get(FNode->getTargetOpcode()).getSchedClass();
|
2008-03-25 21:45:14 +00:00
|
|
|
const InstrStage *S = InstrItins.begin(SchedClass);
|
|
|
|
const InstrStage *E = InstrItins.end(SchedClass);
|
2007-10-05 01:39:18 +00:00
|
|
|
for (; S != E; ++S)
|
|
|
|
SU->Latency += S->Cycles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-04 11:19:43 +00:00
|
|
|
/// CalculateDepths - compute depths using algorithms for the longest
|
|
|
|
/// paths in the DAG
|
2006-05-11 23:55:42 +00:00
|
|
|
void ScheduleDAG::CalculateDepths() {
|
2008-03-04 11:19:43 +00:00
|
|
|
unsigned DAGSize = SUnits.size();
|
|
|
|
std::vector<unsigned> InDegree(DAGSize);
|
|
|
|
std::vector<SUnit*> WorkList;
|
|
|
|
WorkList.reserve(DAGSize);
|
2006-05-11 23:55:42 +00:00
|
|
|
|
2008-03-04 11:19:43 +00:00
|
|
|
// Initialize the data structures
|
|
|
|
for (unsigned i = 0, e = DAGSize; i != e; ++i) {
|
|
|
|
SUnit *SU = &SUnits[i];
|
|
|
|
int NodeNum = SU->NodeNum;
|
|
|
|
unsigned Degree = SU->Preds.size();
|
|
|
|
InDegree[NodeNum] = Degree;
|
|
|
|
SU->Depth = 0;
|
|
|
|
|
|
|
|
// Is it a node without dependencies?
|
|
|
|
if (Degree == 0) {
|
|
|
|
assert(SU->Preds.empty() && "SUnit should have no predecessors");
|
|
|
|
// Collect leaf nodes
|
|
|
|
WorkList.push_back(SU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process nodes in the topological order
|
2007-07-06 01:37:28 +00:00
|
|
|
while (!WorkList.empty()) {
|
2008-03-04 11:19:43 +00:00
|
|
|
SUnit *SU = WorkList.back();
|
2007-07-06 01:37:28 +00:00
|
|
|
WorkList.pop_back();
|
2008-03-04 11:19:43 +00:00
|
|
|
unsigned &SUDepth = SU->Depth;
|
|
|
|
|
|
|
|
// Use dynamic programming:
|
|
|
|
// When current node is being processed, all of its dependencies
|
|
|
|
// are already processed.
|
|
|
|
// So, just iterate over all predecessors and take the longest path
|
|
|
|
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
unsigned PredDepth = I->Dep->Depth;
|
|
|
|
if (PredDepth+1 > SUDepth) {
|
|
|
|
SUDepth = PredDepth + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update InDegrees of all nodes depending on current SUnit
|
|
|
|
for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
SUnit *SU = I->Dep;
|
|
|
|
if (!--InDegree[SU->NodeNum])
|
|
|
|
// If all dependencies of the node are processed already,
|
|
|
|
// then the longest path for the node can be computed now
|
|
|
|
WorkList.push_back(SU);
|
2007-07-06 01:37:28 +00:00
|
|
|
}
|
2006-05-12 06:05:18 +00:00
|
|
|
}
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
2007-07-06 01:37:28 +00:00
|
|
|
|
2008-03-04 11:19:43 +00:00
|
|
|
/// CalculateHeights - compute heights using algorithms for the longest
|
|
|
|
/// paths in the DAG
|
2006-05-11 23:55:42 +00:00
|
|
|
void ScheduleDAG::CalculateHeights() {
|
2008-03-04 11:19:43 +00:00
|
|
|
unsigned DAGSize = SUnits.size();
|
|
|
|
std::vector<unsigned> InDegree(DAGSize);
|
|
|
|
std::vector<SUnit*> WorkList;
|
|
|
|
WorkList.reserve(DAGSize);
|
2007-07-06 01:37:28 +00:00
|
|
|
|
2008-03-04 11:19:43 +00:00
|
|
|
// Initialize the data structures
|
|
|
|
for (unsigned i = 0, e = DAGSize; i != e; ++i) {
|
|
|
|
SUnit *SU = &SUnits[i];
|
|
|
|
int NodeNum = SU->NodeNum;
|
|
|
|
unsigned Degree = SU->Succs.size();
|
|
|
|
InDegree[NodeNum] = Degree;
|
|
|
|
SU->Height = 0;
|
|
|
|
|
|
|
|
// Is it a node without dependencies?
|
|
|
|
if (Degree == 0) {
|
|
|
|
assert(SU->Succs.empty() && "Something wrong");
|
|
|
|
assert(WorkList.empty() && "Should be empty");
|
|
|
|
// Collect leaf nodes
|
|
|
|
WorkList.push_back(SU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process nodes in the topological order
|
2007-07-06 01:37:28 +00:00
|
|
|
while (!WorkList.empty()) {
|
2008-03-04 11:19:43 +00:00
|
|
|
SUnit *SU = WorkList.back();
|
2007-07-06 01:37:28 +00:00
|
|
|
WorkList.pop_back();
|
2008-03-04 11:19:43 +00:00
|
|
|
unsigned &SUHeight = SU->Height;
|
|
|
|
|
|
|
|
// Use dynamic programming:
|
|
|
|
// When current node is being processed, all of its dependencies
|
|
|
|
// are already processed.
|
|
|
|
// So, just iterate over all successors and take the longest path
|
|
|
|
for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
unsigned SuccHeight = I->Dep->Height;
|
|
|
|
if (SuccHeight+1 > SUHeight) {
|
|
|
|
SUHeight = SuccHeight + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update InDegrees of all nodes depending on current SUnit
|
|
|
|
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
SUnit *SU = I->Dep;
|
|
|
|
if (!--InDegree[SU->NodeNum])
|
|
|
|
// If all dependencies of the node are processed already,
|
|
|
|
// then the longest path for the node can be computed now
|
|
|
|
WorkList.push_back(SU);
|
2007-07-06 01:37:28 +00:00
|
|
|
}
|
|
|
|
}
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
2005-09-26 21:57:04 +00:00
|
|
|
/// CountResults - The results of target nodes have register or immediate
|
|
|
|
/// operands first, then an optional chain, and optional flag operands (which do
|
2008-02-11 19:00:03 +00:00
|
|
|
/// not go into the resulting MachineInstr).
|
2006-11-04 09:44:31 +00:00
|
|
|
unsigned ScheduleDAG::CountResults(SDNode *Node) {
|
2005-09-30 19:15:27 +00:00
|
|
|
unsigned N = Node->getNumValues();
|
|
|
|
while (N && Node->getValueType(N - 1) == MVT::Flag)
|
2005-09-26 21:57:04 +00:00
|
|
|
--N;
|
2005-09-30 19:15:27 +00:00
|
|
|
if (N && Node->getValueType(N - 1) == MVT::Other)
|
2005-09-26 21:57:04 +00:00
|
|
|
--N; // Skip over chain result.
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2008-02-06 22:27:42 +00:00
|
|
|
/// CountOperands - The inputs to target nodes have any actual inputs first,
|
2008-02-16 00:36:48 +00:00
|
|
|
/// followed by special operands that describe memory references, then an
|
|
|
|
/// optional chain operand, then flag operands. Compute the number of
|
|
|
|
/// actual operands that will go into the resulting MachineInstr.
|
2006-11-04 09:44:31 +00:00
|
|
|
unsigned ScheduleDAG::CountOperands(SDNode *Node) {
|
2008-02-16 00:36:48 +00:00
|
|
|
unsigned N = ComputeMemOperandsEnd(Node);
|
2008-02-11 19:00:34 +00:00
|
|
|
while (N && isa<MemOperandSDNode>(Node->getOperand(N - 1).Val))
|
2008-04-07 19:35:22 +00:00
|
|
|
--N; // Ignore MEMOPERAND nodes
|
2008-02-06 22:27:42 +00:00
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2008-02-16 00:36:48 +00:00
|
|
|
/// ComputeMemOperandsEnd - Find the index one past the last MemOperandSDNode
|
|
|
|
/// operand
|
|
|
|
unsigned ScheduleDAG::ComputeMemOperandsEnd(SDNode *Node) {
|
2005-09-30 19:15:27 +00:00
|
|
|
unsigned N = Node->getNumOperands();
|
|
|
|
while (N && Node->getOperand(N - 1).getValueType() == MVT::Flag)
|
2005-09-26 21:57:04 +00:00
|
|
|
--N;
|
2005-09-30 19:15:27 +00:00
|
|
|
if (N && Node->getOperand(N - 1).getValueType() == MVT::Other)
|
2005-09-26 21:57:04 +00:00
|
|
|
--N; // Ignore chain if it exists.
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
/// getInstrOperandRegClass - Return register class of the operand of an
|
|
|
|
/// instruction of the specified TargetInstrDesc.
|
|
|
|
static const TargetRegisterClass*
|
|
|
|
getInstrOperandRegClass(const TargetRegisterInfo *TRI,
|
|
|
|
const TargetInstrInfo *TII, const TargetInstrDesc &II,
|
|
|
|
unsigned Op) {
|
2008-01-07 07:27:27 +00:00
|
|
|
if (Op >= II.getNumOperands()) {
|
|
|
|
assert(II.isVariadic() && "Invalid operand # of instruction");
|
2006-07-21 20:57:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-01-07 07:27:27 +00:00
|
|
|
if (II.OpInfo[Op].isLookupPtrRegClass())
|
2008-01-07 02:39:19 +00:00
|
|
|
return TII->getPointerRegClass();
|
2008-02-10 18:45:23 +00:00
|
|
|
return TRI->getRegClass(II.OpInfo[Op].RegClass);
|
2006-07-21 20:57:35 +00:00
|
|
|
}
|
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
|
|
|
|
/// implicit physical register output.
|
2007-09-25 01:54:36 +00:00
|
|
|
void ScheduleDAG::EmitCopyFromReg(SDNode *Node, unsigned ResNo,
|
2008-06-21 15:52:51 +00:00
|
|
|
bool IsClone, unsigned SrcReg,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
unsigned VRBase = 0;
|
2008-02-10 18:45:23 +00:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(SrcReg)) {
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
// Just use the input register directly!
|
2008-07-07 17:46:23 +00:00
|
|
|
SDOperand Op(Node, ResNo);
|
2008-06-21 15:52:51 +00:00
|
|
|
if (IsClone)
|
2008-07-07 17:46:23 +00:00
|
|
|
VRBaseMap.erase(Op);
|
|
|
|
bool isNew = VRBaseMap.insert(std::make_pair(Op, SrcReg)).second;
|
2008-05-14 21:08:07 +00:00
|
|
|
isNew = isNew; // Silence compiler warning.
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
assert(isNew && "Node emitted out of order - early");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the node is only used by a CopyToReg and the dest reg is a vreg, use
|
|
|
|
// the CopyToReg'd destination register instead of creating a new vreg.
|
2007-09-25 01:54:36 +00:00
|
|
|
bool MatchReg = true;
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
|
|
|
UI != E; ++UI) {
|
2008-04-07 10:06:32 +00:00
|
|
|
SDNode *Use = UI->getUser();
|
2007-09-25 01:54:36 +00:00
|
|
|
bool Match = true;
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
if (Use->getOpcode() == ISD::CopyToReg &&
|
|
|
|
Use->getOperand(2).Val == Node &&
|
|
|
|
Use->getOperand(2).ResNo == ResNo) {
|
|
|
|
unsigned DestReg = cast<RegisterSDNode>(Use->getOperand(1))->getReg();
|
2008-02-10 18:45:23 +00:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
VRBase = DestReg;
|
2007-09-25 01:54:36 +00:00
|
|
|
Match = false;
|
|
|
|
} else if (DestReg != SrcReg)
|
|
|
|
Match = false;
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 0, e = Use->getNumOperands(); i != e; ++i) {
|
|
|
|
SDOperand Op = Use->getOperand(i);
|
2007-12-14 08:25:15 +00:00
|
|
|
if (Op.Val != Node || Op.ResNo != ResNo)
|
2007-09-25 01:54:36 +00:00
|
|
|
continue;
|
2008-06-06 12:08:01 +00:00
|
|
|
MVT VT = Node->getValueType(Op.ResNo);
|
2007-09-25 01:54:36 +00:00
|
|
|
if (VT != MVT::Other && VT != MVT::Flag)
|
|
|
|
Match = false;
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 01:54:36 +00:00
|
|
|
MatchReg &= Match;
|
|
|
|
if (VRBase)
|
|
|
|
break;
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-09 08:49:15 +00:00
|
|
|
const TargetRegisterClass *SrcRC = 0, *DstRC = 0;
|
2008-03-11 07:19:34 +00:00
|
|
|
SrcRC = TRI->getPhysicalRegisterRegClass(SrcReg, Node->getValueType(ResNo));
|
2008-03-09 08:49:15 +00:00
|
|
|
|
2007-09-25 01:54:36 +00:00
|
|
|
// Figure out the register class to create for the destreg.
|
2008-03-09 08:49:15 +00:00
|
|
|
if (VRBase) {
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
DstRC = MRI.getRegClass(VRBase);
|
2008-03-09 08:49:15 +00:00
|
|
|
} else {
|
2008-04-03 16:36:07 +00:00
|
|
|
DstRC = TLI->getRegClassFor(Node->getValueType(ResNo));
|
2008-03-09 08:49:15 +00:00
|
|
|
}
|
2007-09-25 01:54:36 +00:00
|
|
|
|
|
|
|
// If all uses are reading from the src physical register and copying the
|
|
|
|
// register is either impossible or very expensive, then don't create a copy.
|
2008-03-09 08:49:15 +00:00
|
|
|
if (MatchReg && SrcRC->getCopyCost() < 0) {
|
2007-09-25 01:54:36 +00:00
|
|
|
VRBase = SrcReg;
|
|
|
|
} else {
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
// Create the reg, emit the copy.
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
VRBase = MRI.createVirtualRegister(DstRC);
|
2008-03-09 08:49:15 +00:00
|
|
|
TII->copyRegToReg(*BB, BB->end(), VRBase, SrcReg, DstRC, SrcRC);
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
}
|
|
|
|
|
2008-07-07 17:46:23 +00:00
|
|
|
SDOperand Op(Node, ResNo);
|
2008-06-21 15:52:51 +00:00
|
|
|
if (IsClone)
|
2008-07-07 17:46:23 +00:00
|
|
|
VRBaseMap.erase(Op);
|
|
|
|
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
2008-05-14 21:08:07 +00:00
|
|
|
isNew = isNew; // Silence compiler warning.
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
assert(isNew && "Node emitted out of order - early");
|
|
|
|
}
|
|
|
|
|
2008-04-03 16:36:07 +00:00
|
|
|
/// getDstOfCopyToRegUse - If the only use of the specified result number of
|
|
|
|
/// node is a CopyToReg, return its destination register. Return 0 otherwise.
|
|
|
|
unsigned ScheduleDAG::getDstOfOnlyCopyToRegUse(SDNode *Node,
|
|
|
|
unsigned ResNo) const {
|
|
|
|
if (!Node->hasOneUse())
|
|
|
|
return 0;
|
|
|
|
|
2008-04-07 10:06:32 +00:00
|
|
|
SDNode *Use = Node->use_begin()->getUser();
|
2008-04-03 16:36:07 +00:00
|
|
|
if (Use->getOpcode() == ISD::CopyToReg &&
|
|
|
|
Use->getOperand(2).Val == Node &&
|
|
|
|
Use->getOperand(2).ResNo == ResNo) {
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Use->getOperand(1))->getReg();
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-15 00:03:38 +00:00
|
|
|
void ScheduleDAG::CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
|
2008-04-03 16:36:07 +00:00
|
|
|
const TargetInstrDesc &II,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
2008-04-03 16:36:07 +00:00
|
|
|
assert(Node->getTargetOpcode() != TargetInstrInfo::IMPLICIT_DEF &&
|
|
|
|
"IMPLICIT_DEF should have been handled as a special case elsewhere!");
|
|
|
|
|
2008-01-07 03:13:06 +00:00
|
|
|
for (unsigned i = 0; i < II.getNumDefs(); ++i) {
|
2007-07-10 07:08:32 +00:00
|
|
|
// If the specific node value is only used by a CopyToReg and the dest reg
|
|
|
|
// is a vreg, use the CopyToReg'd destination register instead of creating
|
|
|
|
// a new vreg.
|
|
|
|
unsigned VRBase = 0;
|
|
|
|
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
|
|
|
UI != E; ++UI) {
|
2008-04-07 10:06:32 +00:00
|
|
|
SDNode *Use = UI->getUser();
|
2007-07-10 07:08:32 +00:00
|
|
|
if (Use->getOpcode() == ISD::CopyToReg &&
|
|
|
|
Use->getOperand(2).Val == Node &&
|
|
|
|
Use->getOperand(2).ResNo == i) {
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Use->getOperand(1))->getReg();
|
2008-02-10 18:45:23 +00:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
2007-07-10 07:08:32 +00:00
|
|
|
VRBase = Reg;
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
2007-07-10 07:08:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
// Create the result registers for this node and add the result regs to
|
|
|
|
// the machine instruction.
|
2007-07-10 07:08:32 +00:00
|
|
|
if (VRBase == 0) {
|
2008-04-03 16:36:07 +00:00
|
|
|
const TargetRegisterClass *RC = getInstrOperandRegClass(TRI, TII, II, i);
|
2007-07-10 07:08:32 +00:00
|
|
|
assert(RC && "Isn't a register operand!");
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
VRBase = MRI.createVirtualRegister(RC);
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
2007-07-10 07:08:32 +00:00
|
|
|
}
|
|
|
|
|
2008-07-07 17:46:23 +00:00
|
|
|
SDOperand Op(Node, i);
|
|
|
|
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
2008-05-14 21:08:07 +00:00
|
|
|
isNew = isNew; // Silence compiler warning.
|
2007-07-10 07:08:32 +00:00
|
|
|
assert(isNew && "Node emitted out of order - early");
|
2005-09-26 21:57:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-10 07:25:12 +00:00
|
|
|
/// getVR - Return the virtual register corresponding to the specified result
|
|
|
|
/// of the specified node.
|
2008-04-03 16:36:07 +00:00
|
|
|
unsigned ScheduleDAG::getVR(SDOperand Op,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
2008-04-03 16:36:07 +00:00
|
|
|
if (Op.isTargetOpcode() &&
|
|
|
|
Op.getTargetOpcode() == TargetInstrInfo::IMPLICIT_DEF) {
|
|
|
|
// Add an IMPLICIT_DEF instruction before every use.
|
|
|
|
unsigned VReg = getDstOfOnlyCopyToRegUse(Op.Val, Op.ResNo);
|
|
|
|
// IMPLICIT_DEF can produce any type of result so its TargetInstrDesc
|
|
|
|
// does not include operand register class info.
|
|
|
|
if (!VReg) {
|
|
|
|
const TargetRegisterClass *RC = TLI->getRegClassFor(Op.getValueType());
|
|
|
|
VReg = MRI.createVirtualRegister(RC);
|
|
|
|
}
|
|
|
|
BuildMI(BB, TII->get(TargetInstrInfo::IMPLICIT_DEF), VReg);
|
|
|
|
return VReg;
|
|
|
|
}
|
|
|
|
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned>::iterator I = VRBaseMap.find(Op);
|
2006-03-10 07:25:12 +00:00
|
|
|
assert(I != VRBaseMap.end() && "Node emitted out of order - late");
|
2007-07-10 07:08:32 +00:00
|
|
|
return I->second;
|
2006-03-10 07:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-24 18:54:03 +00:00
|
|
|
/// AddOperand - Add the specified operand to the specified machine instr. II
|
|
|
|
/// specifies the instruction information for the node, and IIOpNum is the
|
|
|
|
/// operand number (in the II) that we are adding. IIOpNum and II are used for
|
|
|
|
/// assertions only.
|
|
|
|
void ScheduleDAG::AddOperand(MachineInstr *MI, SDOperand Op,
|
|
|
|
unsigned IIOpNum,
|
2008-01-07 07:27:27 +00:00
|
|
|
const TargetInstrDesc *II,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
2006-02-24 18:54:03 +00:00
|
|
|
if (Op.isTargetOpcode()) {
|
|
|
|
// Note that this case is redundant with the final else block, but we
|
|
|
|
// include it because it is the most common and it makes the logic
|
|
|
|
// simpler here.
|
|
|
|
assert(Op.getValueType() != MVT::Other &&
|
|
|
|
Op.getValueType() != MVT::Flag &&
|
|
|
|
"Chain and flag operands should occur at end of operand list!");
|
|
|
|
// Get/emit the operand.
|
2006-03-10 07:25:12 +00:00
|
|
|
unsigned VReg = getVR(Op, VRBaseMap);
|
2008-01-07 07:27:27 +00:00
|
|
|
const TargetInstrDesc &TID = MI->getDesc();
|
2008-04-03 16:36:07 +00:00
|
|
|
bool isOptDef = IIOpNum < TID.getNumOperands() &&
|
|
|
|
TID.OpInfo[IIOpNum].isOptionalDef();
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(VReg, isOptDef));
|
2006-02-24 18:54:03 +00:00
|
|
|
|
|
|
|
// Verify that it is right.
|
2008-02-10 18:45:23 +00:00
|
|
|
assert(TargetRegisterInfo::isVirtualRegister(VReg) && "Not a vreg?");
|
2008-03-11 00:59:28 +00:00
|
|
|
#ifndef NDEBUG
|
2006-02-24 18:54:03 +00:00
|
|
|
if (II) {
|
2008-03-11 00:59:28 +00:00
|
|
|
// There may be no register class for this operand if it is a variadic
|
|
|
|
// argument (RC will be NULL in this case). In this case, we just assume
|
|
|
|
// the regclass is ok.
|
2006-07-21 20:57:35 +00:00
|
|
|
const TargetRegisterClass *RC =
|
2008-02-10 18:45:23 +00:00
|
|
|
getInstrOperandRegClass(TRI, TII, *II, IIOpNum);
|
2008-03-11 03:14:42 +00:00
|
|
|
assert((RC || II->isVariadic()) && "Expected reg class info!");
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
const TargetRegisterClass *VRC = MRI.getRegClass(VReg);
|
2008-03-11 00:59:28 +00:00
|
|
|
if (RC && VRC != RC) {
|
2007-02-15 18:17:56 +00:00
|
|
|
cerr << "Register class of operand and regclass of use don't agree!\n";
|
|
|
|
cerr << "Operand = " << IIOpNum << "\n";
|
2007-02-17 06:38:37 +00:00
|
|
|
cerr << "Op->Val = "; Op.Val->dump(&DAG); cerr << "\n";
|
2007-02-15 18:17:56 +00:00
|
|
|
cerr << "MI = "; MI->print(cerr);
|
|
|
|
cerr << "VReg = " << VReg << "\n";
|
|
|
|
cerr << "VReg RegClass size = " << VRC->getSize()
|
2007-02-15 18:19:15 +00:00
|
|
|
<< ", align = " << VRC->getAlignment() << "\n";
|
2007-02-15 18:17:56 +00:00
|
|
|
cerr << "Expected RegClass size = " << RC->getSize()
|
2007-02-15 18:19:15 +00:00
|
|
|
<< ", align = " << RC->getAlignment() << "\n";
|
2007-02-15 18:17:56 +00:00
|
|
|
cerr << "Fatal error, aborting.\n";
|
|
|
|
abort();
|
|
|
|
}
|
2006-02-24 18:54:03 +00:00
|
|
|
}
|
2008-03-11 00:59:28 +00:00
|
|
|
#endif
|
2007-12-30 00:51:11 +00:00
|
|
|
} else if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateImm(C->getValue()));
|
2008-02-14 08:57:00 +00:00
|
|
|
} else if (ConstantFPSDNode *F = dyn_cast<ConstantFPSDNode>(Op)) {
|
2008-04-20 00:41:09 +00:00
|
|
|
ConstantFP *CFP = ConstantFP::get(F->getValueAPF());
|
2008-02-14 08:57:00 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateFPImm(CFP));
|
2007-12-30 00:51:11 +00:00
|
|
|
} else if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(Op)) {
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(R->getReg(), false));
|
2007-12-30 00:51:11 +00:00
|
|
|
} else if (GlobalAddressSDNode *TGA = dyn_cast<GlobalAddressSDNode>(Op)) {
|
|
|
|
MI->addOperand(MachineOperand::CreateGA(TGA->getGlobal(),TGA->getOffset()));
|
|
|
|
} else if (BasicBlockSDNode *BB = dyn_cast<BasicBlockSDNode>(Op)) {
|
|
|
|
MI->addOperand(MachineOperand::CreateMBB(BB->getBasicBlock()));
|
|
|
|
} else if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op)) {
|
|
|
|
MI->addOperand(MachineOperand::CreateFI(FI->getIndex()));
|
|
|
|
} else if (JumpTableSDNode *JT = dyn_cast<JumpTableSDNode>(Op)) {
|
|
|
|
MI->addOperand(MachineOperand::CreateJTI(JT->getIndex()));
|
|
|
|
} else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op)) {
|
2006-02-25 09:54:52 +00:00
|
|
|
int Offset = CP->getOffset();
|
2006-02-24 18:54:03 +00:00
|
|
|
unsigned Align = CP->getAlignment();
|
2006-09-12 21:00:35 +00:00
|
|
|
const Type *Type = CP->getType();
|
2006-02-24 18:54:03 +00:00
|
|
|
// MachineConstantPool wants an explicit alignment.
|
|
|
|
if (Align == 0) {
|
2007-01-24 07:03:39 +00:00
|
|
|
Align = TM.getTargetData()->getPreferredTypeAlignmentShift(Type);
|
2007-01-22 23:13:55 +00:00
|
|
|
if (Align == 0) {
|
2007-02-15 03:39:18 +00:00
|
|
|
// Alignment of vector types. FIXME!
|
Executive summary: getTypeSize -> getTypeStoreSize / getABITypeSize.
The meaning of getTypeSize was not clear - clarifying it is important
now that we have x86 long double and arbitrary precision integers.
The issue with long double is that it requires 80 bits, and this is
not a multiple of its alignment. This gives a primitive type for
which getTypeSize differed from getABITypeSize. For arbitrary precision
integers it is even worse: there is the minimum number of bits needed to
hold the type (eg: 36 for an i36), the maximum number of bits that will
be overwriten when storing the type (40 bits for i36) and the ABI size
(i.e. the storage size rounded up to a multiple of the alignment; 64 bits
for i36).
This patch removes getTypeSize (not really - it is still there but
deprecated to allow for a gradual transition). Instead there is:
(1) getTypeSizeInBits - a number of bits that suffices to hold all
values of the type. For a primitive type, this is the minimum number
of bits. For an i36 this is 36 bits. For x86 long double it is 80.
This corresponds to gcc's TYPE_PRECISION.
(2) getTypeStoreSizeInBits - the maximum number of bits that is
written when storing the type (or read when reading it). For an
i36 this is 40 bits, for an x86 long double it is 80 bits. This
is the size alias analysis is interested in (getTypeStoreSize
returns the number of bytes). There doesn't seem to be anything
corresponding to this in gcc.
(3) getABITypeSizeInBits - this is getTypeStoreSizeInBits rounded
up to a multiple of the alignment. For an i36 this is 64, for an
x86 long double this is 96 or 128 depending on the OS. This is the
spacing between consecutive elements when you form an array out of
this type (getABITypeSize returns the number of bytes). This is
TYPE_SIZE in gcc.
Since successive elements in a SequentialType (arrays, pointers
and vectors) need to be aligned, the spacing between them will be
given by getABITypeSize. This means that the size of an array
is the length times the getABITypeSize. It also means that GEP
computations need to use getABITypeSize when computing offsets.
Furthermore, if an alloca allocates several elements at once then
these too need to be aligned, so the size of the alloca has to be
the number of elements multiplied by getABITypeSize. Logically
speaking this doesn't have to be the case when allocating just
one element, but it is simpler to also use getABITypeSize in this
case. So alloca's and mallocs should use getABITypeSize. Finally,
since gcc's only notion of size is that given by getABITypeSize, if
you want to output assembler etc the same as gcc then getABITypeSize
is the size you want.
Since a store will overwrite no more than getTypeStoreSize bytes,
and a read will read no more than that many bytes, this is the
notion of size appropriate for alias analysis calculations.
In this patch I have corrected all type size uses except some of
those in ScalarReplAggregates, lib/Codegen, lib/Target (the hard
cases). I will get around to auditing these too at some point,
but I could do with some help.
Finally, I made one change which I think wise but others might
consider pointless and suboptimal: in an unpacked struct the
amount of space allocated for a field is now given by the ABI
size rather than getTypeStoreSize. I did this because every
other place that reserves memory for a type (eg: alloca) now
uses getABITypeSize, and I didn't want to make an exception
for unpacked structs, i.e. I did it to make things more uniform.
This only effects structs containing long doubles and arbitrary
precision integers. If someone wants to pack these types more
tightly they can always use a packed struct.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@43620 91177308-0d34-0410-b5e6-96231b3b80d8
2007-11-01 20:53:16 +00:00
|
|
|
Align = TM.getTargetData()->getABITypeSize(Type);
|
2007-01-22 23:13:55 +00:00
|
|
|
Align = Log2_64(Align);
|
2006-03-20 01:51:46 +00:00
|
|
|
}
|
2006-02-24 18:54:03 +00:00
|
|
|
}
|
|
|
|
|
2006-09-12 21:00:35 +00:00
|
|
|
unsigned Idx;
|
|
|
|
if (CP->isMachineConstantPoolEntry())
|
|
|
|
Idx = ConstPool->getConstantPoolIndex(CP->getMachineCPVal(), Align);
|
|
|
|
else
|
|
|
|
Idx = ConstPool->getConstantPoolIndex(CP->getConstVal(), Align);
|
2007-12-30 00:51:11 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateCPI(Idx, Offset));
|
|
|
|
} else if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op)) {
|
|
|
|
MI->addOperand(MachineOperand::CreateES(ES->getSymbol()));
|
2006-02-24 18:54:03 +00:00
|
|
|
} else {
|
|
|
|
assert(Op.getValueType() != MVT::Other &&
|
|
|
|
Op.getValueType() != MVT::Flag &&
|
|
|
|
"Chain and flag operands should occur at end of operand list!");
|
2006-03-10 07:25:12 +00:00
|
|
|
unsigned VReg = getVR(Op, VRBaseMap);
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(VReg, false));
|
2006-02-24 18:54:03 +00:00
|
|
|
|
2008-03-09 08:49:15 +00:00
|
|
|
// Verify that it is right. Note that the reg class of the physreg and the
|
|
|
|
// vreg don't necessarily need to match, but the target copy insertion has
|
|
|
|
// to be able to handle it. This handles things like copies from ST(0) to
|
|
|
|
// an FP vreg on x86.
|
2008-02-10 18:45:23 +00:00
|
|
|
assert(TargetRegisterInfo::isVirtualRegister(VReg) && "Not a vreg?");
|
2008-03-11 03:14:42 +00:00
|
|
|
if (II && !II->isVariadic()) {
|
2008-03-09 08:49:15 +00:00
|
|
|
assert(getInstrOperandRegClass(TRI, TII, *II, IIOpNum) &&
|
|
|
|
"Don't have operand info for this instruction!");
|
2006-02-24 18:54:03 +00:00
|
|
|
}
|
2008-07-02 09:23:51 +00:00
|
|
|
}
|
2006-02-24 18:54:03 +00:00
|
|
|
}
|
|
|
|
|
2008-04-07 19:35:22 +00:00
|
|
|
void ScheduleDAG::AddMemOperand(MachineInstr *MI, const MachineMemOperand &MO) {
|
2008-07-07 23:14:23 +00:00
|
|
|
MI->addMemOperand(*MF, MO);
|
2008-02-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
/// getSubRegisterRegClass - Returns the register class of specified register
|
|
|
|
/// class' "SubIdx"'th sub-register class.
|
|
|
|
static const TargetRegisterClass*
|
|
|
|
getSubRegisterRegClass(const TargetRegisterClass *TRC, unsigned SubIdx) {
|
2007-07-26 08:12:07 +00:00
|
|
|
// Pick the register class of the subregister
|
2008-02-10 18:45:23 +00:00
|
|
|
TargetRegisterInfo::regclass_iterator I =
|
|
|
|
TRC->subregclasses_begin() + SubIdx-1;
|
2007-07-26 08:12:07 +00:00
|
|
|
assert(I < TRC->subregclasses_end() &&
|
|
|
|
"Invalid subregister index for register class");
|
|
|
|
return *I;
|
|
|
|
}
|
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
/// getSuperRegisterRegClass - Returns the register class of a superreg A whose
|
|
|
|
/// "SubIdx"'th sub-register class is the specified register class and whose
|
|
|
|
/// type matches the specified type.
|
|
|
|
static const TargetRegisterClass*
|
|
|
|
getSuperRegisterRegClass(const TargetRegisterClass *TRC,
|
|
|
|
unsigned SubIdx, MVT VT) {
|
2007-07-26 08:12:07 +00:00
|
|
|
// Pick the register class of the superegister for this type
|
2008-02-10 18:45:23 +00:00
|
|
|
for (TargetRegisterInfo::regclass_iterator I = TRC->superregclasses_begin(),
|
2007-07-26 08:12:07 +00:00
|
|
|
E = TRC->superregclasses_end(); I != E; ++I)
|
|
|
|
if ((*I)->hasType(VT) && getSubRegisterRegClass(*I, SubIdx) == TRC)
|
|
|
|
return *I;
|
|
|
|
assert(false && "Couldn't find the register class");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitSubregNode - Generate machine code for subreg nodes.
|
|
|
|
///
|
|
|
|
void ScheduleDAG::EmitSubregNode(SDNode *Node,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
2007-07-26 08:12:07 +00:00
|
|
|
unsigned VRBase = 0;
|
|
|
|
unsigned Opc = Node->getTargetOpcode();
|
2008-03-16 03:12:01 +00:00
|
|
|
|
|
|
|
// If the node is only used by a CopyToReg and the dest reg is a vreg, use
|
|
|
|
// the CopyToReg'd destination register instead of creating a new vreg.
|
|
|
|
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
|
|
|
UI != E; ++UI) {
|
2008-04-07 10:06:32 +00:00
|
|
|
SDNode *Use = UI->getUser();
|
2008-03-16 03:12:01 +00:00
|
|
|
if (Use->getOpcode() == ISD::CopyToReg &&
|
|
|
|
Use->getOperand(2).Val == Node) {
|
|
|
|
unsigned DestReg = cast<RegisterSDNode>(Use->getOperand(1))->getReg();
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
|
|
|
VRBase = DestReg;
|
|
|
|
break;
|
2007-07-26 08:12:07 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-16 03:12:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Opc == TargetInstrInfo::EXTRACT_SUBREG) {
|
2007-07-26 08:12:07 +00:00
|
|
|
unsigned SubIdx = cast<ConstantSDNode>(Node->getOperand(1))->getValue();
|
|
|
|
|
|
|
|
// Create the extract_subreg machine instruction.
|
2008-07-07 23:14:23 +00:00
|
|
|
MachineInstr *MI = BuildMI(*MF, TII->get(TargetInstrInfo::EXTRACT_SUBREG));
|
2007-07-26 08:12:07 +00:00
|
|
|
|
|
|
|
// Figure out the register class to create for the destreg.
|
|
|
|
unsigned VReg = getVR(Node->getOperand(0), VRBaseMap);
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
const TargetRegisterClass *TRC = MRI.getRegClass(VReg);
|
2007-07-26 08:12:07 +00:00
|
|
|
const TargetRegisterClass *SRC = getSubRegisterRegClass(TRC, SubIdx);
|
|
|
|
|
|
|
|
if (VRBase) {
|
|
|
|
// Grab the destination register
|
2008-05-14 20:07:51 +00:00
|
|
|
#ifndef NDEBUG
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
const TargetRegisterClass *DRC = MRI.getRegClass(VRBase);
|
2008-01-31 07:09:08 +00:00
|
|
|
assert(SRC && DRC && SRC == DRC &&
|
2007-07-26 08:12:07 +00:00
|
|
|
"Source subregister and destination must have the same class");
|
2008-05-14 20:07:51 +00:00
|
|
|
#endif
|
2007-07-26 08:12:07 +00:00
|
|
|
} else {
|
|
|
|
// Create the reg
|
2008-01-31 07:09:08 +00:00
|
|
|
assert(SRC && "Couldn't find source register class");
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
VRBase = MRI.createVirtualRegister(SRC);
|
2007-07-26 08:12:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add def, source, and subreg index
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
2007-07-26 08:12:07 +00:00
|
|
|
AddOperand(MI, Node->getOperand(0), 0, 0, VRBaseMap);
|
2007-12-30 00:51:11 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateImm(SubIdx));
|
2008-04-03 16:36:07 +00:00
|
|
|
BB->push_back(MI);
|
2008-03-16 03:12:01 +00:00
|
|
|
} else if (Opc == TargetInstrInfo::INSERT_SUBREG ||
|
|
|
|
Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
2008-03-11 10:09:17 +00:00
|
|
|
SDOperand N0 = Node->getOperand(0);
|
|
|
|
SDOperand N1 = Node->getOperand(1);
|
|
|
|
SDOperand N2 = Node->getOperand(2);
|
|
|
|
unsigned SubReg = getVR(N1, VRBaseMap);
|
|
|
|
unsigned SubIdx = cast<ConstantSDNode>(N2)->getValue();
|
2007-07-26 08:12:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Figure out the register class to create for the destreg.
|
|
|
|
const TargetRegisterClass *TRC = 0;
|
|
|
|
if (VRBase) {
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
TRC = MRI.getRegClass(VRBase);
|
2007-07-26 08:12:07 +00:00
|
|
|
} else {
|
2008-07-02 09:23:51 +00:00
|
|
|
TRC = getSuperRegisterRegClass(MRI.getRegClass(SubReg), SubIdx,
|
2007-07-26 08:12:07 +00:00
|
|
|
Node->getValueType(0));
|
|
|
|
assert(TRC && "Couldn't determine register class for insert_subreg");
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
VRBase = MRI.createVirtualRegister(TRC); // Create the reg
|
2007-07-26 08:12:07 +00:00
|
|
|
}
|
|
|
|
|
2008-03-16 03:12:01 +00:00
|
|
|
// Create the insert_subreg or subreg_to_reg machine instruction.
|
2008-07-07 23:14:23 +00:00
|
|
|
MachineInstr *MI = BuildMI(*MF, TII->get(Opc));
|
2007-12-30 00:41:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateReg(VRBase, true));
|
2008-03-11 10:09:17 +00:00
|
|
|
|
2008-03-16 03:12:01 +00:00
|
|
|
// If creating a subreg_to_reg, then the first input operand
|
|
|
|
// is an implicit value immediate, otherwise it's a register
|
|
|
|
if (Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
|
|
|
const ConstantSDNode *SD = cast<ConstantSDNode>(N0);
|
2008-03-11 10:09:17 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateImm(SD->getValue()));
|
2008-03-16 03:12:01 +00:00
|
|
|
} else
|
2008-03-11 10:09:17 +00:00
|
|
|
AddOperand(MI, N0, 0, 0, VRBaseMap);
|
|
|
|
// Add the subregster being inserted
|
|
|
|
AddOperand(MI, N1, 0, 0, VRBaseMap);
|
2007-12-30 00:51:11 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateImm(SubIdx));
|
2008-04-03 16:36:07 +00:00
|
|
|
BB->push_back(MI);
|
2007-07-26 08:12:07 +00:00
|
|
|
} else
|
2008-03-16 03:12:01 +00:00
|
|
|
assert(0 && "Node is not insert_subreg, extract_subreg, or subreg_to_reg");
|
2007-07-26 08:12:07 +00:00
|
|
|
|
2008-07-07 17:46:23 +00:00
|
|
|
SDOperand Op(Node, 0);
|
|
|
|
bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second;
|
2008-05-14 21:08:07 +00:00
|
|
|
isNew = isNew; // Silence compiler warning.
|
2007-07-26 08:12:07 +00:00
|
|
|
assert(isNew && "Node emitted out of order - early");
|
|
|
|
}
|
|
|
|
|
2005-09-30 19:15:27 +00:00
|
|
|
/// EmitNode - Generate machine code for an node and needed dependencies.
|
|
|
|
///
|
2008-06-21 15:52:51 +00:00
|
|
|
void ScheduleDAG::EmitNode(SDNode *Node, bool IsClone,
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> &VRBaseMap) {
|
2005-09-30 19:15:27 +00:00
|
|
|
// If machine instruction
|
|
|
|
if (Node->isTargetOpcode()) {
|
|
|
|
unsigned Opc = Node->getTargetOpcode();
|
2007-07-26 08:12:07 +00:00
|
|
|
|
|
|
|
// Handle subreg insert/extract specially
|
|
|
|
if (Opc == TargetInstrInfo::EXTRACT_SUBREG ||
|
2008-03-16 03:12:01 +00:00
|
|
|
Opc == TargetInstrInfo::INSERT_SUBREG ||
|
|
|
|
Opc == TargetInstrInfo::SUBREG_TO_REG) {
|
2007-07-26 08:12:07 +00:00
|
|
|
EmitSubregNode(Node, VRBaseMap);
|
|
|
|
return;
|
|
|
|
}
|
2008-04-03 16:36:07 +00:00
|
|
|
|
|
|
|
if (Opc == TargetInstrInfo::IMPLICIT_DEF)
|
|
|
|
// We want a unique VR for each IMPLICIT_DEF use.
|
|
|
|
return;
|
2007-07-26 08:12:07 +00:00
|
|
|
|
2008-01-07 07:27:27 +00:00
|
|
|
const TargetInstrDesc &II = TII->get(Opc);
|
2005-09-30 19:15:27 +00:00
|
|
|
unsigned NumResults = CountResults(Node);
|
|
|
|
unsigned NodeOperands = CountOperands(Node);
|
2008-02-16 00:36:48 +00:00
|
|
|
unsigned MemOperandsEnd = ComputeMemOperandsEnd(Node);
|
2008-01-07 03:13:06 +00:00
|
|
|
bool HasPhysRegOuts = (NumResults > II.getNumDefs()) &&
|
|
|
|
II.getImplicitDefs() != 0;
|
2005-09-30 19:15:27 +00:00
|
|
|
#ifndef NDEBUG
|
2008-05-14 20:07:51 +00:00
|
|
|
unsigned NumMIOperands = NodeOperands + NumResults;
|
2008-01-07 03:13:06 +00:00
|
|
|
assert((II.getNumOperands() == NumMIOperands ||
|
2008-01-07 05:19:29 +00:00
|
|
|
HasPhysRegOuts || II.isVariadic()) &&
|
2005-09-30 19:15:27 +00:00
|
|
|
"#operands for dag node doesn't match .td file!");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Create the new machine instruction.
|
2008-07-07 23:14:23 +00:00
|
|
|
MachineInstr *MI = BuildMI(*MF, II);
|
2005-09-30 19:15:27 +00:00
|
|
|
|
|
|
|
// Add result register values for things that are defined by this
|
|
|
|
// instruction.
|
2007-07-10 07:08:32 +00:00
|
|
|
if (NumResults)
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
CreateVirtualRegisters(Node, MI, II, VRBaseMap);
|
2005-09-30 19:15:27 +00:00
|
|
|
|
|
|
|
// Emit all of the actual operands of this instruction, adding them to the
|
|
|
|
// instruction as appropriate.
|
2006-02-24 18:54:03 +00:00
|
|
|
for (unsigned i = 0; i != NodeOperands; ++i)
|
2008-01-07 03:13:06 +00:00
|
|
|
AddOperand(MI, Node->getOperand(i), i+II.getNumDefs(), &II, VRBaseMap);
|
2006-05-12 01:58:24 +00:00
|
|
|
|
2008-02-06 22:27:42 +00:00
|
|
|
// Emit all of the memory operands of this instruction
|
2008-02-16 00:36:48 +00:00
|
|
|
for (unsigned i = NodeOperands; i != MemOperandsEnd; ++i)
|
2008-02-06 22:27:42 +00:00
|
|
|
AddMemOperand(MI, cast<MemOperandSDNode>(Node->getOperand(i))->MO);
|
|
|
|
|
2006-05-12 01:58:24 +00:00
|
|
|
// Commute node if it has been determined to be profitable.
|
|
|
|
if (CommuteSet.count(Node)) {
|
|
|
|
MachineInstr *NewMI = TII->commuteInstruction(MI);
|
|
|
|
if (NewMI == 0)
|
2006-12-07 20:04:42 +00:00
|
|
|
DOUT << "Sched: COMMUTING FAILED!\n";
|
2006-05-12 01:58:24 +00:00
|
|
|
else {
|
2006-12-07 20:04:42 +00:00
|
|
|
DOUT << "Sched: COMMUTED TO: " << *NewMI;
|
2006-05-31 18:03:39 +00:00
|
|
|
if (MI != NewMI) {
|
2008-07-07 23:14:23 +00:00
|
|
|
MF->DeleteMachineInstr(MI);
|
2006-05-31 18:03:39 +00:00
|
|
|
MI = NewMI;
|
|
|
|
}
|
2008-02-28 07:40:24 +00:00
|
|
|
++NumCommutes;
|
2006-05-12 01:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-01 09:10:45 +00:00
|
|
|
if (II.usesCustomDAGSchedInsertionHook())
|
2008-01-30 19:35:32 +00:00
|
|
|
// Insert this instruction into the basic block using a target
|
|
|
|
// specific inserter which may returns a new basic block.
|
2008-04-03 16:36:07 +00:00
|
|
|
BB = TLI->EmitInstrWithCustomInserter(MI, BB);
|
2008-01-30 19:35:32 +00:00
|
|
|
else
|
|
|
|
BB->push_back(MI);
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
|
|
|
|
// Additional results must be an physical register def.
|
|
|
|
if (HasPhysRegOuts) {
|
2008-01-07 03:13:06 +00:00
|
|
|
for (unsigned i = II.getNumDefs(); i < NumResults; ++i) {
|
|
|
|
unsigned Reg = II.getImplicitDefs()[i - II.getNumDefs()];
|
2007-08-02 05:29:38 +00:00
|
|
|
if (Node->hasAnyUseOfValue(i))
|
2008-06-21 15:52:51 +00:00
|
|
|
EmitCopyFromReg(Node, i, IsClone, Reg, VRBaseMap);
|
Instead of adding copyfromreg's to handle physical definitions. Now isel can
simply specify them as results and let scheduledag handle them. That
is, instead of
SDOperand Flag = DAG.getTargetNode(Opc, MVT::i32, MVT::Flag, ...)
SDOperand Result = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, Flag)
Just write:
SDOperand Result = DAG.getTargetNode(Opc, MVT::i32, MVT::i32, ...)
And let scheduledag emit the move from X86::EAX to a virtual register.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40710 91177308-0d34-0410-b5e6-96231b3b80d8
2007-08-02 00:28:15 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-02 09:23:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Node->getOpcode()) {
|
|
|
|
default:
|
2006-07-11 18:25:13 +00:00
|
|
|
#ifndef NDEBUG
|
2008-07-02 09:23:51 +00:00
|
|
|
Node->dump(&DAG);
|
2006-07-11 18:25:13 +00:00
|
|
|
#endif
|
2008-07-02 09:23:51 +00:00
|
|
|
assert(0 && "This target-independent node should have been selected!");
|
|
|
|
break;
|
|
|
|
case ISD::EntryToken:
|
|
|
|
assert(0 && "EntryToken should have been excluded from the schedule!");
|
|
|
|
break;
|
|
|
|
case ISD::TokenFactor: // fall thru
|
|
|
|
break;
|
|
|
|
case ISD::CopyToReg: {
|
|
|
|
unsigned SrcReg;
|
|
|
|
SDOperand SrcVal = Node->getOperand(2);
|
|
|
|
if (RegisterSDNode *R = dyn_cast<RegisterSDNode>(SrcVal))
|
|
|
|
SrcReg = R->getReg();
|
|
|
|
else
|
|
|
|
SrcReg = getVR(SrcVal, VRBaseMap);
|
2008-03-09 09:15:31 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
unsigned DestReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
|
|
|
if (SrcReg == DestReg) // Coalesced away the copy? Ignore.
|
|
|
|
break;
|
2008-03-09 09:15:31 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
const TargetRegisterClass *SrcTRC = 0, *DstTRC = 0;
|
|
|
|
// Get the register classes of the src/dst.
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(SrcReg))
|
|
|
|
SrcTRC = MRI.getRegClass(SrcReg);
|
|
|
|
else
|
|
|
|
SrcTRC = TRI->getPhysicalRegisterRegClass(SrcReg,SrcVal.getValueType());
|
|
|
|
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(DestReg))
|
|
|
|
DstTRC = MRI.getRegClass(DestReg);
|
|
|
|
else
|
|
|
|
DstTRC = TRI->getPhysicalRegisterRegClass(DestReg,
|
2008-03-11 07:19:34 +00:00
|
|
|
Node->getOperand(1).getValueType());
|
2008-07-02 09:23:51 +00:00
|
|
|
TII->copyRegToReg(*BB, BB->end(), DestReg, SrcReg, DstTRC, SrcTRC);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ISD::CopyFromReg: {
|
|
|
|
unsigned SrcReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
|
|
|
EmitCopyFromReg(Node, 0, IsClone, SrcReg, VRBaseMap);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ISD::INLINEASM: {
|
|
|
|
unsigned NumOps = Node->getNumOperands();
|
|
|
|
if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag)
|
|
|
|
--NumOps; // Ignore the flag operand.
|
2006-01-26 23:28:04 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
// Create the inline asm machine instruction.
|
2008-07-07 23:14:23 +00:00
|
|
|
MachineInstr *MI = BuildMI(*MF, TII->get(TargetInstrInfo::INLINEASM));
|
2006-01-26 23:28:04 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
// Add the asm string as an external symbol operand.
|
|
|
|
const char *AsmStr =
|
|
|
|
cast<ExternalSymbolSDNode>(Node->getOperand(1))->getSymbol();
|
|
|
|
MI->addOperand(MachineOperand::CreateES(AsmStr));
|
2006-01-26 23:28:04 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
// Add all of the operand registers to the instruction.
|
|
|
|
for (unsigned i = 2; i != NumOps;) {
|
|
|
|
unsigned Flags = cast<ConstantSDNode>(Node->getOperand(i))->getValue();
|
|
|
|
unsigned NumVals = Flags >> 3;
|
2006-02-23 19:21:04 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
MI->addOperand(MachineOperand::CreateImm(Flags));
|
|
|
|
++i; // Skip the ID value.
|
2006-02-23 19:21:04 +00:00
|
|
|
|
2008-07-02 09:23:51 +00:00
|
|
|
switch (Flags & 7) {
|
|
|
|
default: assert(0 && "Bad flags!");
|
|
|
|
case 2: // Def of register.
|
|
|
|
for (; NumVals; --NumVals, ++i) {
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
|
|
|
|
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
|
|
|
}
|
|
|
|
break;
|
2008-07-02 23:23:19 +00:00
|
|
|
case 1: // Use of register.
|
|
|
|
case 3: // Immediate.
|
2008-07-02 09:23:51 +00:00
|
|
|
case 4: // Addressing mode.
|
|
|
|
// The addressing mode has been selected, just add all of the
|
|
|
|
// operands to the machine instruction.
|
|
|
|
for (; NumVals; --NumVals, ++i)
|
|
|
|
AddOperand(MI, Node->getOperand(i), 0, 0, VRBaseMap);
|
|
|
|
break;
|
2006-01-26 23:28:04 +00:00
|
|
|
}
|
2005-09-30 19:15:27 +00:00
|
|
|
}
|
2008-07-02 09:23:51 +00:00
|
|
|
BB->push_back(MI);
|
|
|
|
break;
|
|
|
|
}
|
2005-09-30 19:15:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-05 23:51:47 +00:00
|
|
|
void ScheduleDAG::EmitNoop() {
|
|
|
|
TII->insertNoop(*BB, BB->end());
|
|
|
|
}
|
|
|
|
|
2008-03-09 07:51:01 +00:00
|
|
|
void ScheduleDAG::EmitCrossRCCopy(SUnit *SU,
|
|
|
|
DenseMap<SUnit*, unsigned> &VRBaseMap) {
|
2007-09-26 21:36:17 +00:00
|
|
|
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
if (I->isCtrl) continue; // ignore chain preds
|
|
|
|
if (!I->Dep->Node) {
|
|
|
|
// Copy to physical register.
|
|
|
|
DenseMap<SUnit*, unsigned>::iterator VRI = VRBaseMap.find(I->Dep);
|
|
|
|
assert(VRI != VRBaseMap.end() && "Node emitted out of order - late");
|
|
|
|
// Find the destination physical register.
|
|
|
|
unsigned Reg = 0;
|
|
|
|
for (SUnit::const_succ_iterator II = SU->Succs.begin(),
|
|
|
|
EE = SU->Succs.end(); II != EE; ++II) {
|
|
|
|
if (I->Reg) {
|
|
|
|
Reg = I->Reg;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(I->Reg && "Unknown physical register!");
|
2007-12-31 06:32:00 +00:00
|
|
|
TII->copyRegToReg(*BB, BB->end(), Reg, VRI->second,
|
2007-09-26 21:36:17 +00:00
|
|
|
SU->CopyDstRC, SU->CopySrcRC);
|
|
|
|
} else {
|
|
|
|
// Copy from physical register.
|
|
|
|
assert(I->Reg && "Unknown physical register!");
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
unsigned VRBase = MRI.createVirtualRegister(SU->CopyDstRC);
|
2008-07-07 17:46:23 +00:00
|
|
|
bool isNew = VRBaseMap.insert(std::make_pair(SU, VRBase)).second;
|
2008-05-14 21:08:07 +00:00
|
|
|
isNew = isNew; // Silence compiler warning.
|
2007-09-26 21:36:17 +00:00
|
|
|
assert(isNew && "Node emitted out of order - early");
|
2007-12-31 06:32:00 +00:00
|
|
|
TII->copyRegToReg(*BB, BB->end(), VRBase, I->Reg,
|
2007-09-26 21:36:17 +00:00
|
|
|
SU->CopyDstRC, SU->CopySrcRC);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
/// EmitLiveInCopy - Emit a copy for a live in physical register. If the
|
|
|
|
/// physical register has only a single copy use, then coalesced the copy
|
2008-03-14 00:14:55 +00:00
|
|
|
/// if possible.
|
|
|
|
void ScheduleDAG::EmitLiveInCopy(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator &InsertPos,
|
|
|
|
unsigned VirtReg, unsigned PhysReg,
|
|
|
|
const TargetRegisterClass *RC,
|
|
|
|
DenseMap<MachineInstr*, unsigned> &CopyRegMap){
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
unsigned NumUses = 0;
|
|
|
|
MachineInstr *UseMI = NULL;
|
|
|
|
for (MachineRegisterInfo::use_iterator UI = MRI.use_begin(VirtReg),
|
|
|
|
UE = MRI.use_end(); UI != UE; ++UI) {
|
|
|
|
UseMI = &*UI;
|
|
|
|
if (++NumUses > 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the number of uses is not one, or the use is not a move instruction,
|
2008-03-14 00:14:55 +00:00
|
|
|
// don't coalesce. Also, only coalesce away a virtual register to virtual
|
|
|
|
// register copy.
|
|
|
|
bool Coalesced = false;
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
unsigned SrcReg, DstReg;
|
2008-03-14 00:14:55 +00:00
|
|
|
if (NumUses == 1 &&
|
|
|
|
TII->isMoveInstr(*UseMI, SrcReg, DstReg) &&
|
|
|
|
TargetRegisterInfo::isVirtualRegister(DstReg)) {
|
|
|
|
VirtReg = DstReg;
|
|
|
|
Coalesced = true;
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 00:14:55 +00:00
|
|
|
// Now find an ideal location to insert the copy.
|
|
|
|
MachineBasicBlock::iterator Pos = InsertPos;
|
|
|
|
while (Pos != MBB->begin()) {
|
|
|
|
MachineInstr *PrevMI = prior(Pos);
|
|
|
|
DenseMap<MachineInstr*, unsigned>::iterator RI = CopyRegMap.find(PrevMI);
|
|
|
|
// copyRegToReg might emit multiple instructions to do a copy.
|
|
|
|
unsigned CopyDstReg = (RI == CopyRegMap.end()) ? 0 : RI->second;
|
|
|
|
if (CopyDstReg && !TRI->regsOverlap(CopyDstReg, PhysReg))
|
|
|
|
// This is what the BB looks like right now:
|
|
|
|
// r1024 = mov r0
|
|
|
|
// ...
|
|
|
|
// r1 = mov r1024
|
|
|
|
//
|
|
|
|
// We want to insert "r1025 = mov r1". Inserting this copy below the
|
|
|
|
// move to r1024 makes it impossible for that move to be coalesced.
|
|
|
|
//
|
|
|
|
// r1025 = mov r1
|
|
|
|
// r1024 = mov r0
|
|
|
|
// ...
|
|
|
|
// r1 = mov 1024
|
|
|
|
// r2 = mov 1025
|
|
|
|
break; // Woot! Found a good location.
|
|
|
|
--Pos;
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 00:14:55 +00:00
|
|
|
TII->copyRegToReg(*MBB, Pos, VirtReg, PhysReg, RC, RC);
|
|
|
|
CopyRegMap.insert(std::make_pair(prior(Pos), VirtReg));
|
|
|
|
if (Coalesced) {
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
if (&*InsertPos == UseMI) ++InsertPos;
|
|
|
|
MBB->erase(UseMI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EmitLiveInCopies - If this is the first basic block in the function,
|
|
|
|
/// and if it has live ins that need to be copied into vregs, emit the
|
|
|
|
/// copies into the top of the block.
|
|
|
|
void ScheduleDAG::EmitLiveInCopies(MachineBasicBlock *MBB) {
|
2008-03-14 00:14:55 +00:00
|
|
|
DenseMap<MachineInstr*, unsigned> CopyRegMap;
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
MachineBasicBlock::iterator InsertPos = MBB->begin();
|
|
|
|
for (MachineRegisterInfo::livein_iterator LI = MRI.livein_begin(),
|
|
|
|
E = MRI.livein_end(); LI != E; ++LI)
|
|
|
|
if (LI->second) {
|
|
|
|
const TargetRegisterClass *RC = MRI.getRegClass(LI->second);
|
2008-03-14 00:14:55 +00:00
|
|
|
EmitLiveInCopy(MBB, InsertPos, LI->second, LI->first, RC, CopyRegMap);
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-11 23:55:42 +00:00
|
|
|
/// EmitSchedule - Emit the machine code in scheduled order.
|
|
|
|
void ScheduleDAG::EmitSchedule() {
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
bool isEntryBB = &MF->front() == BB;
|
|
|
|
|
|
|
|
if (isEntryBB && !SchedLiveInCopies) {
|
|
|
|
// If this is the first basic block in the function, and if it has live ins
|
|
|
|
// that need to be copied into vregs, emit the copies into the top of the
|
|
|
|
// block before emitting the code for the block.
|
|
|
|
for (MachineRegisterInfo::livein_iterator LI = MRI.livein_begin(),
|
|
|
|
E = MRI.livein_end(); LI != E; ++LI)
|
2007-09-26 06:25:56 +00:00
|
|
|
if (LI->second) {
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
const TargetRegisterClass *RC = MRI.getRegClass(LI->second);
|
2008-01-30 19:35:32 +00:00
|
|
|
TII->copyRegToReg(*MF->begin(), MF->begin()->end(), LI->second,
|
2007-09-26 06:25:56 +00:00
|
|
|
LI->first, RC, RC);
|
|
|
|
}
|
2006-05-16 06:10:58 +00:00
|
|
|
}
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
|
2006-05-16 06:10:58 +00:00
|
|
|
// Finally, emit the code for all of the scheduled instructions.
|
2008-04-16 16:15:27 +00:00
|
|
|
DenseMap<SDOperand, unsigned> VRBaseMap;
|
2007-09-26 21:36:17 +00:00
|
|
|
DenseMap<SUnit*, unsigned> CopyVRBaseMap;
|
2006-05-11 23:55:42 +00:00
|
|
|
for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
|
2008-04-03 16:36:07 +00:00
|
|
|
SUnit *SU = Sequence[i];
|
|
|
|
if (!SU) {
|
2006-05-11 23:55:42 +00:00
|
|
|
// Null SUnit* is a noop.
|
|
|
|
EmitNoop();
|
2008-04-03 16:36:07 +00:00
|
|
|
continue;
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
2008-04-03 16:36:07 +00:00
|
|
|
for (unsigned j = 0, ee = SU->FlaggedNodes.size(); j != ee; ++j)
|
2008-06-21 15:52:51 +00:00
|
|
|
EmitNode(SU->FlaggedNodes[j], SU->OrigNode != SU, VRBaseMap);
|
2008-04-03 16:36:07 +00:00
|
|
|
if (!SU->Node)
|
|
|
|
EmitCrossRCCopy(SU, CopyVRBaseMap);
|
|
|
|
else
|
2008-06-21 15:52:51 +00:00
|
|
|
EmitNode(SU->Node, SU->OrigNode != SU, VRBaseMap);
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
Experimental scheduler change to schedule / coalesce the copies added for function livein's. Take 2008-03-10-RegAllocInfLoop.ll, the schedule looks like this after these copies are inserted:
entry: 0x12049d0, LLVM BB @0x1201fd0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1028<def> = MOV32rr %EAX
%reg1029<def> = MOV32rr %EDX
%reg1030<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x1201910 + 0]
%reg1025<def> = MOV32rr %reg1029
%reg1026<def> = MOV32rr %reg1030
%reg1024<def> = MOV32rr %reg1028
The copies unnecessarily increase register pressure and it will end up requiring a physical register to be spilled.
With -schedule-livein-copies:
entry: 0x12049d0, LLVM BB @0x1201fa0, ID#0:
Live Ins: %EAX %EDX %ECX
%reg1031<def> = MOVPC32r 0
%reg1032<def> = ADD32ri %reg1031, <es:_GLOBAL_OFFSET_TABLE_>, %EFLAGS<imp-def>
%reg1024<def> = MOV32rr %EAX
%reg1025<def> = MOV32rr %EDX
%reg1026<def> = MOV32rr %ECX
%reg1027<def> = MOV8rm %reg0, 1, %reg0, 0, Mem:LD(1,1) [0x12018e0 + 0]
Much better!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48307 91177308-0d34-0410-b5e6-96231b3b80d8
2008-03-12 22:19:41 +00:00
|
|
|
|
|
|
|
if (isEntryBB && SchedLiveInCopies)
|
|
|
|
EmitLiveInCopies(MF->begin());
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// dump - dump the schedule.
|
|
|
|
void ScheduleDAG::dumpSchedule() const {
|
|
|
|
for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
|
|
|
|
if (SUnit *SU = Sequence[i])
|
|
|
|
SU->dump(&DAG);
|
|
|
|
else
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << "**** NOOP ****\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-21 02:32:06 +00:00
|
|
|
/// Run - perform scheduling.
|
|
|
|
///
|
|
|
|
MachineBasicBlock *ScheduleDAG::Run() {
|
|
|
|
Schedule();
|
|
|
|
return BB;
|
2005-08-18 18:45:24 +00:00
|
|
|
}
|
2006-01-23 07:01:07 +00:00
|
|
|
|
2006-05-11 23:55:42 +00:00
|
|
|
/// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or
|
|
|
|
/// a group of nodes flagged together.
|
|
|
|
void SUnit::dump(const SelectionDAG *G) const {
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << "SU(" << NodeNum << "): ";
|
2007-09-26 21:36:17 +00:00
|
|
|
if (Node)
|
|
|
|
Node->dump(G);
|
|
|
|
else
|
|
|
|
cerr << "CROSS RC COPY ";
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
if (FlaggedNodes.size() != 0) {
|
|
|
|
for (unsigned i = 0, e = FlaggedNodes.size(); i != e; i++) {
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " ";
|
2006-05-11 23:55:42 +00:00
|
|
|
FlaggedNodes[i]->dump(G);
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SUnit::dumpAll(const SelectionDAG *G) const {
|
|
|
|
dump(G);
|
2006-01-23 07:01:07 +00:00
|
|
|
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " # preds left : " << NumPredsLeft << "\n";
|
|
|
|
cerr << " # succs left : " << NumSuccsLeft << "\n";
|
|
|
|
cerr << " Latency : " << Latency << "\n";
|
|
|
|
cerr << " Depth : " << Depth << "\n";
|
|
|
|
cerr << " Height : " << Height << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
|
|
|
|
if (Preds.size() != 0) {
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " Predecessors:\n";
|
2006-08-17 00:09:56 +00:00
|
|
|
for (SUnit::const_succ_iterator I = Preds.begin(), E = Preds.end();
|
|
|
|
I != E; ++I) {
|
2007-09-19 01:38:40 +00:00
|
|
|
if (I->isCtrl)
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " ch #";
|
2006-05-11 23:55:42 +00:00
|
|
|
else
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " val #";
|
2007-09-25 01:54:36 +00:00
|
|
|
cerr << I->Dep << " - SU(" << I->Dep->NodeNum << ")";
|
|
|
|
if (I->isSpecial)
|
|
|
|
cerr << " *";
|
|
|
|
cerr << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Succs.size() != 0) {
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " Successors:\n";
|
2006-08-17 00:09:56 +00:00
|
|
|
for (SUnit::const_succ_iterator I = Succs.begin(), E = Succs.end();
|
|
|
|
I != E; ++I) {
|
2007-09-19 01:38:40 +00:00
|
|
|
if (I->isCtrl)
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " ch #";
|
2006-05-11 23:55:42 +00:00
|
|
|
else
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << " val #";
|
2007-09-25 01:54:36 +00:00
|
|
|
cerr << I->Dep << " - SU(" << I->Dep->NodeNum << ")";
|
|
|
|
if (I->isSpecial)
|
|
|
|
cerr << " *";
|
|
|
|
cerr << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
2006-12-07 20:04:42 +00:00
|
|
|
cerr << "\n";
|
2006-05-11 23:55:42 +00:00
|
|
|
}
|