mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-05 02:16:46 +00:00
CreateVirtualRegisters does trivial copy coalescing. If a node def is used by a single CopyToReg, it reuses the virtual register assigned to the CopyToReg. This won't work for SDNode that is a clone or is itself cloned. Disable this optimization for those nodes or it can end up with non-SSA machine instructions.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62356 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a21a8607e4
commit
e57187cbe3
@ -250,6 +250,7 @@ namespace llvm {
|
||||
bool isAvailable : 1; // True once available.
|
||||
bool isScheduled : 1; // True once scheduled.
|
||||
bool isScheduleHigh : 1; // True if preferable to schedule high.
|
||||
bool isCloned : 1; // True if this node has been cloned.
|
||||
private:
|
||||
bool isDepthCurrent : 1; // True if Depth is current.
|
||||
bool isHeightCurrent : 1; // True if Height is current.
|
||||
@ -266,8 +267,8 @@ namespace llvm {
|
||||
Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
|
||||
isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false),
|
||||
isPending(false), isAvailable(false), isScheduled(false),
|
||||
isScheduleHigh(false), isDepthCurrent(false), isHeightCurrent(false),
|
||||
Depth(0), Height(0),
|
||||
isScheduleHigh(false), isCloned(false),
|
||||
isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0),
|
||||
CopyDstRC(NULL), CopySrcRC(NULL) {}
|
||||
|
||||
/// SUnit - Construct an SUnit for post-regalloc scheduling to represent
|
||||
@ -277,8 +278,8 @@ namespace llvm {
|
||||
Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
|
||||
isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false),
|
||||
isPending(false), isAvailable(false), isScheduled(false),
|
||||
isScheduleHigh(false), isDepthCurrent(false), isHeightCurrent(false),
|
||||
Depth(0), Height(0),
|
||||
isScheduleHigh(false), isCloned(false),
|
||||
isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0),
|
||||
CopyDstRC(NULL), CopySrcRC(NULL) {}
|
||||
|
||||
/// setNode - Assign the representative SDNode for this SUnit.
|
||||
|
@ -107,7 +107,7 @@ namespace llvm {
|
||||
/// VRBaseMap contains, for each already emitted node, the first virtual
|
||||
/// register number for the results of the node.
|
||||
///
|
||||
void EmitNode(SDNode *Node, bool IsClone,
|
||||
void EmitNode(SDNode *Node, bool IsClone, bool HasClone,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap);
|
||||
|
||||
virtual MachineBasicBlock *EmitSchedule();
|
||||
@ -144,11 +144,12 @@ namespace llvm {
|
||||
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
|
||||
/// implicit physical register output.
|
||||
void EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone,
|
||||
unsigned SrcReg,
|
||||
bool IsCloned, unsigned SrcReg,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap);
|
||||
|
||||
void CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
|
||||
const TargetInstrDesc &II, bool IsClone,
|
||||
bool IsCloned,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap);
|
||||
|
||||
/// BuildSchedUnits, AddSchedEdges - Helper functions for BuildSchedGraph.
|
||||
|
@ -33,6 +33,7 @@ SUnit *ScheduleDAGSDNodes::Clone(SUnit *Old) {
|
||||
SU->isTwoAddress = Old->isTwoAddress;
|
||||
SU->isCommutable = Old->isCommutable;
|
||||
SU->hasPhysRegDefs = Old->hasPhysRegDefs;
|
||||
Old->isCloned = true;
|
||||
return SU;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@ getInstrOperandRegClass(const TargetRegisterInfo *TRI,
|
||||
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
|
||||
/// implicit physical register output.
|
||||
void ScheduleDAGSDNodes::EmitCopyFromReg(SDNode *Node, unsigned ResNo,
|
||||
bool IsClone, unsigned SrcReg,
|
||||
bool IsClone, bool IsCloned,
|
||||
unsigned SrcReg,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
unsigned VRBase = 0;
|
||||
if (TargetRegisterInfo::isVirtualRegister(SrcReg)) {
|
||||
@ -64,44 +65,45 @@ void ScheduleDAGSDNodes::EmitCopyFromReg(SDNode *Node, unsigned ResNo,
|
||||
// the CopyToReg'd destination register instead of creating a new vreg.
|
||||
bool MatchReg = true;
|
||||
const TargetRegisterClass *UseRC = NULL;
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
bool Match = true;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == ResNo) {
|
||||
unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
||||
VRBase = DestReg;
|
||||
Match = false;
|
||||
} else if (DestReg != SrcReg)
|
||||
Match = false;
|
||||
} else {
|
||||
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
|
||||
SDValue Op = User->getOperand(i);
|
||||
if (Op.getNode() != Node || Op.getResNo() != ResNo)
|
||||
continue;
|
||||
MVT VT = Node->getValueType(Op.getResNo());
|
||||
if (VT == MVT::Other || VT == MVT::Flag)
|
||||
continue;
|
||||
Match = false;
|
||||
if (User->isMachineOpcode()) {
|
||||
const TargetInstrDesc &II = TII->get(User->getMachineOpcode());
|
||||
const TargetRegisterClass *RC =
|
||||
getInstrOperandRegClass(TRI,TII,II,i+II.getNumDefs());
|
||||
if (!UseRC)
|
||||
UseRC = RC;
|
||||
else if (RC)
|
||||
assert(UseRC == RC &&
|
||||
"Multiple uses expecting different register classes!");
|
||||
if (!IsClone && !IsCloned)
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
bool Match = true;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == ResNo) {
|
||||
unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(DestReg)) {
|
||||
VRBase = DestReg;
|
||||
Match = false;
|
||||
} else if (DestReg != SrcReg)
|
||||
Match = false;
|
||||
} else {
|
||||
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
|
||||
SDValue Op = User->getOperand(i);
|
||||
if (Op.getNode() != Node || Op.getResNo() != ResNo)
|
||||
continue;
|
||||
MVT VT = Node->getValueType(Op.getResNo());
|
||||
if (VT == MVT::Other || VT == MVT::Flag)
|
||||
continue;
|
||||
Match = false;
|
||||
if (User->isMachineOpcode()) {
|
||||
const TargetInstrDesc &II = TII->get(User->getMachineOpcode());
|
||||
const TargetRegisterClass *RC =
|
||||
getInstrOperandRegClass(TRI,TII,II,i+II.getNumDefs());
|
||||
if (!UseRC)
|
||||
UseRC = RC;
|
||||
else if (RC)
|
||||
assert(UseRC == RC &&
|
||||
"Multiple uses expecting different register classes!");
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchReg &= Match;
|
||||
if (VRBase)
|
||||
break;
|
||||
}
|
||||
MatchReg &= Match;
|
||||
if (VRBase)
|
||||
break;
|
||||
}
|
||||
|
||||
MVT VT = Node->getValueType(ResNo);
|
||||
const TargetRegisterClass *SrcRC = 0, *DstRC = 0;
|
||||
@ -157,7 +159,8 @@ unsigned ScheduleDAGSDNodes::getDstOfOnlyCopyToRegUse(SDNode *Node,
|
||||
}
|
||||
|
||||
void ScheduleDAGSDNodes::CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
|
||||
const TargetInstrDesc &II, bool IsClone,
|
||||
const TargetInstrDesc &II,
|
||||
bool IsClone, bool IsCloned,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
assert(Node->getMachineOpcode() != TargetInstrInfo::IMPLICIT_DEF &&
|
||||
"IMPLICIT_DEF should have been handled as a special case elsewhere!");
|
||||
@ -167,20 +170,22 @@ void ScheduleDAGSDNodes::CreateVirtualRegisters(SDNode *Node, MachineInstr *MI,
|
||||
// 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) {
|
||||
SDNode *User = *UI;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == i) {
|
||||
unsigned Reg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
||||
VRBase = Reg;
|
||||
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
||||
break;
|
||||
|
||||
if (!IsClone && !IsCloned)
|
||||
for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end();
|
||||
UI != E; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
if (User->getOpcode() == ISD::CopyToReg &&
|
||||
User->getOperand(2).getNode() == Node &&
|
||||
User->getOperand(2).getResNo() == i) {
|
||||
unsigned Reg = cast<RegisterSDNode>(User->getOperand(1))->getReg();
|
||||
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
||||
VRBase = Reg;
|
||||
MI->addOperand(MachineOperand::CreateReg(Reg, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the result registers for this node and add the result regs to
|
||||
// the machine instruction.
|
||||
@ -452,7 +457,7 @@ void ScheduleDAGSDNodes::EmitSubregNode(SDNode *Node,
|
||||
|
||||
/// EmitNode - Generate machine code for an node and needed dependencies.
|
||||
///
|
||||
void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone,
|
||||
void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
// If machine instruction
|
||||
if (Node->isMachineOpcode()) {
|
||||
@ -489,7 +494,7 @@ void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone,
|
||||
// Add result register values for things that are defined by this
|
||||
// instruction.
|
||||
if (NumResults)
|
||||
CreateVirtualRegisters(Node, MI, II, IsClone, VRBaseMap);
|
||||
CreateVirtualRegisters(Node, MI, II, IsClone, IsCloned, VRBaseMap);
|
||||
|
||||
// Emit all of the actual operands of this instruction, adding them to the
|
||||
// instruction as appropriate.
|
||||
@ -512,7 +517,7 @@ void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone,
|
||||
for (unsigned i = II.getNumDefs(); i < NumResults; ++i) {
|
||||
unsigned Reg = II.getImplicitDefs()[i - II.getNumDefs()];
|
||||
if (Node->hasAnyUseOfValue(i))
|
||||
EmitCopyFromReg(Node, i, IsClone, Reg, VRBaseMap);
|
||||
EmitCopyFromReg(Node, i, IsClone, IsCloned, Reg, VRBaseMap);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -559,7 +564,7 @@ void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone,
|
||||
}
|
||||
case ISD::CopyFromReg: {
|
||||
unsigned SrcReg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
||||
EmitCopyFromReg(Node, 0, IsClone, SrcReg, VRBaseMap);
|
||||
EmitCopyFromReg(Node, 0, IsClone, IsCloned, SrcReg, VRBaseMap);
|
||||
break;
|
||||
}
|
||||
case ISD::INLINEASM: {
|
||||
@ -636,13 +641,14 @@ MachineBasicBlock *ScheduleDAGSDNodes::EmitSchedule() {
|
||||
}
|
||||
|
||||
SmallVector<SDNode *, 4> FlaggedNodes;
|
||||
for (SDNode *N = SU->getNode()->getFlaggedNode(); N; N = N->getFlaggedNode())
|
||||
for (SDNode *N = SU->getNode()->getFlaggedNode(); N;
|
||||
N = N->getFlaggedNode())
|
||||
FlaggedNodes.push_back(N);
|
||||
while (!FlaggedNodes.empty()) {
|
||||
EmitNode(FlaggedNodes.back(), SU->OrigNode != SU, VRBaseMap);
|
||||
EmitNode(FlaggedNodes.back(), SU->OrigNode != SU, SU->isCloned,VRBaseMap);
|
||||
FlaggedNodes.pop_back();
|
||||
}
|
||||
EmitNode(SU->getNode(), SU->OrigNode != SU, VRBaseMap);
|
||||
EmitNode(SU->getNode(), SU->OrigNode != SU, SU->isCloned, VRBaseMap);
|
||||
}
|
||||
|
||||
return BB;
|
||||
|
50
test/CodeGen/X86/2009-01-16-SchedulerBug.ll
Normal file
50
test/CodeGen/X86/2009-01-16-SchedulerBug.ll
Normal file
@ -0,0 +1,50 @@
|
||||
; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin
|
||||
; rdar://6501631
|
||||
|
||||
%CF = type { %Register }
|
||||
%XXV = type { i32 (...)** }
|
||||
%Register = type { %"struct.XXC::BCFs", i32 }
|
||||
%"struct.XXC::BCFs" = type { i32 }
|
||||
|
||||
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) nounwind
|
||||
|
||||
define fastcc %XXV* @bar(%CF* %call_frame, %XXV** %exception) nounwind {
|
||||
prologue:
|
||||
%param_x = load %XXV** null ; <%XXV*> [#uses=1]
|
||||
%unique_1.i = ptrtoint %XXV* %param_x to i1 ; <i1> [#uses=1]
|
||||
br i1 %unique_1.i, label %NextVerify42, label %FailedVerify
|
||||
|
||||
NextVerify42: ; preds = %prologue
|
||||
%param_y = load %XXV** null ; <%XXV*> [#uses=1]
|
||||
%unique_1.i58 = ptrtoint %XXV* %param_y to i1 ; <i1> [#uses=1]
|
||||
br i1 %unique_1.i58, label %function_setup.cont, label %FailedVerify
|
||||
|
||||
function_setup.cont: ; preds = %NextVerify42
|
||||
br i1 false, label %label13, label %label
|
||||
|
||||
label: ; preds = %function_setup.cont
|
||||
%has_exn = icmp eq %XXV* null, null ; <i1> [#uses=1]
|
||||
br i1 %has_exn, label %kjsNumberLiteral.exit, label %handle_exception
|
||||
|
||||
kjsNumberLiteral.exit: ; preds = %label
|
||||
%0 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 0, i32 0) ; <{ i32, i1 }> [#uses=2]
|
||||
%intAdd = extractvalue { i32, i1 } %0, 0 ; <i32> [#uses=2]
|
||||
%intAddOverflow = extractvalue { i32, i1 } %0, 1 ; <i1> [#uses=1]
|
||||
%toint56 = ashr i32 %intAdd, 1 ; <i32> [#uses=1]
|
||||
%toFP57 = sitofp i32 %toint56 to double ; <double> [#uses=1]
|
||||
br i1 %intAddOverflow, label %rematerializeAdd, label %label13
|
||||
|
||||
label13: ; preds = %kjsNumberLiteral.exit, %function_setup.cont
|
||||
%var_lr1.0 = phi double [ %toFP57, %kjsNumberLiteral.exit ], [ 0.000000e+00, %function_setup.cont ] ; <double> [#uses=0]
|
||||
unreachable
|
||||
|
||||
FailedVerify: ; preds = %NextVerify42, %prologue
|
||||
ret %XXV* null
|
||||
|
||||
rematerializeAdd: ; preds = %kjsNumberLiteral.exit
|
||||
%rematerializedInt = sub i32 %intAdd, 0 ; <i32> [#uses=0]
|
||||
ret %XXV* null
|
||||
|
||||
handle_exception: ; preds = %label
|
||||
ret %XXV* undef
|
||||
}
|
Loading…
Reference in New Issue
Block a user