Remove SelectionDag early allocation of registers

for earlyclobbers.  Teach Local RA about earlyclobber,
and add some tests for it.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@56592 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dale Johannesen 2008-09-24 23:13:09 +00:00
parent b7679bd0cb
commit 8e3455ba17
6 changed files with 96 additions and 43 deletions

View File

@ -722,6 +722,55 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
}
}
// If any physical regs are earlyclobber, spill any value they might
// have in them, then mark them unallocatable.
// If any virtual regs are earlyclobber, allocate them now (before
// freeing inputs that are killed).
if (MI->getOpcode()==TargetInstrInfo::INLINEASM) {
for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isRegister() && MO.isDef() && MO.isEarlyClobber() &&
MO.getReg()) {
if (TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
unsigned DestVirtReg = MO.getReg();
unsigned DestPhysReg;
// If DestVirtReg already has a value, use it.
if (!(DestPhysReg = getVirt2PhysRegMapSlot(DestVirtReg)))
DestPhysReg = getReg(MBB, MI, DestVirtReg);
MF->getRegInfo().setPhysRegUsed(DestPhysReg);
markVirtRegModified(DestVirtReg);
getVirtRegLastUse(DestVirtReg) =
std::make_pair((MachineInstr*)0, 0);
DOUT << " Assigning " << TRI->getName(DestPhysReg)
<< " to %reg" << DestVirtReg << "\n";
MO.setReg(DestPhysReg); // Assign the earlyclobber register
} else {
unsigned Reg = MO.getReg();
if (PhysRegsUsed[Reg] == -2) continue; // Something like ESP.
// These are extra physical register defs when a sub-register
// is defined (def of a sub-register is a read/mod/write of the
// larger registers). Ignore.
if (isReadModWriteImplicitDef(MI, MO.getReg())) continue;
MF->getRegInfo().setPhysRegUsed(Reg);
spillPhysReg(MBB, MI, Reg, true); // Spill any existing value in reg
PhysRegsUsed[Reg] = 0; // It is free and reserved now
AddToPhysRegsUseOrder(Reg);
for (const unsigned *AliasSet = TRI->getSubRegisters(Reg);
*AliasSet; ++AliasSet) {
if (PhysRegsUsed[*AliasSet] != -2) {
MF->getRegInfo().setPhysRegUsed(*AliasSet);
PhysRegsUsed[*AliasSet] = 0; // It is free and reserved now
AddToPhysRegsUseOrder(*AliasSet);
}
}
}
}
}
}
// Get the used operands into registers. This has the potential to spill
// incoming values if we are out of registers. Note that we completely
// ignore physical register uses here. We assume that if an explicit
@ -778,6 +827,7 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isRegister() && MO.isDef() && !MO.isImplicit() && MO.getReg() &&
!MO.isEarlyClobber() &&
TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
unsigned Reg = MO.getReg();
if (PhysRegsUsed[Reg] == -2) continue; // Something like ESP.
@ -839,6 +889,7 @@ void RALocal::AllocateBasicBlock(MachineBasicBlock &MBB) {
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand& MO = MI->getOperand(i);
if (MO.isRegister() && MO.isDef() && MO.getReg() &&
!MO.isEarlyClobber() &&
TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
unsigned DestVirtReg = MO.getReg();
unsigned DestPhysReg;

View File

@ -4465,12 +4465,10 @@ private:
/// allocation. This produces generally horrible, but correct, code.
///
/// OpInfo describes the operand.
/// HasEarlyClobber is true if there are any early clobber constraints (=&r)
/// or any explicitly clobbered registers.
/// Input and OutputRegs are the set of already allocated physical registers.
///
void SelectionDAGLowering::
GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
GetRegistersForValue(SDISelAsmOperandInfo &OpInfo,
std::set<unsigned> &OutputRegs,
std::set<unsigned> &InputRegs) {
// Compute whether this value requires an input register, an output register,
@ -4481,10 +4479,9 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
case InlineAsm::isOutput:
isOutReg = true;
// If this is an early-clobber output, or if there is an input
// constraint that matches this, we need to reserve the input register
// so no other inputs allocate to it.
isInReg = OpInfo.isEarlyClobber || OpInfo.hasMatchingInput;
// If there is an input constraint that matches this, we need to reserve
// the input register so no other inputs allocate to it.
isInReg = OpInfo.hasMatchingInput;
break;
case InlineAsm::isInput:
isInReg = true;
@ -4551,16 +4548,11 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
std::vector<unsigned> RegClassRegs;
const TargetRegisterClass *RC = PhysReg.second;
if (RC) {
// If this is an early clobber or tied register, our regalloc doesn't know
// how to maintain the constraint. If it isn't, go ahead and create vreg
// If this is a tied register, our regalloc doesn't know how to maintain
// the constraint. If it isn't, go ahead and create vreg
// and let the regalloc do the right thing.
if (!OpInfo.hasMatchingInput && !OpInfo.isEarlyClobber &&
// If there is some other early clobber and this is an input register,
// then we are forced to pre-allocate the input reg so it doesn't
// conflict with the earlyclobber.
!(OpInfo.Type == InlineAsm::isInput && HasEarlyClobber)) {
if (!OpInfo.hasMatchingInput) {
RegVT = *PhysReg.second->vt_begin();
if (OpInfo.ConstraintVT == MVT::Other)
ValueVT = RegVT;
@ -4664,11 +4656,6 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
std::vector<InlineAsm::ConstraintInfo>
ConstraintInfos = IA->ParseConstraints();
// SawEarlyClobber - Keep track of whether we saw an earlyclobber output
// constraint. If so, we can't let the register allocator allocate any input
// registers, because it will not know to avoid the earlyclobbered output reg.
bool SawEarlyClobber = false;
bool hasMemory = hasInlineAsmMemConstraint(ConstraintInfos, TLI);
unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
@ -4744,24 +4731,6 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
// Compute the constraint code and ConstraintType to use.
TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, hasMemory, &DAG);
// Keep track of whether we see an earlyclobber.
SawEarlyClobber |= OpInfo.isEarlyClobber;
// If we see a clobber of a register, it is an early clobber.
if (!SawEarlyClobber &&
OpInfo.Type == InlineAsm::isClobber &&
OpInfo.ConstraintType == TargetLowering::C_Register) {
// Note that we want to ignore things that we don't track here, like
// dirflag, fpsr, flags, etc.
std::pair<unsigned, const TargetRegisterClass*> PhysReg =
TLI.getRegForInlineAsmConstraint(OpInfo.ConstraintCode,
OpInfo.ConstraintVT);
if (PhysReg.first || PhysReg.second) {
// This is a register we know of.
SawEarlyClobber = true;
}
}
// If this is a memory input, and if the operand is not indirect, do what we
// need to to provide an address for the memory input.
if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
@ -4802,7 +4771,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
// If this constraint is for a specific register, allocate it before
// anything else.
if (OpInfo.ConstraintType == TargetLowering::C_Register)
GetRegistersForValue(OpInfo, SawEarlyClobber, OutputRegs, InputRegs);
GetRegistersForValue(OpInfo, OutputRegs, InputRegs);
}
ConstraintInfos.clear();
@ -4815,7 +4784,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
// C_Register operands have already been allocated, Other/Memory don't need
// to be.
if (OpInfo.ConstraintType == TargetLowering::C_RegisterClass)
GetRegistersForValue(OpInfo, SawEarlyClobber, OutputRegs, InputRegs);
GetRegistersForValue(OpInfo, OutputRegs, InputRegs);
}
// AsmNodeOperands - The operands for the ISD::INLINEASM node.

View File

@ -398,7 +398,7 @@ public:
N = NewN;
}
void GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
void GetRegistersForValue(SDISelAsmOperandInfo &OpInfo,
std::set<unsigned> &OutputRegs,
std::set<unsigned> &InputRegs);

View File

@ -1,5 +1,8 @@
; RUN: llvm-as < %s | llc | grep {subfc r2,r5,r4}
; RUN: llvm-as < %s | llc | grep {subfze r4,r3}
; RUN: llvm-as < %s | llc | grep {subfc r3,r5,r4}
; RUN: llvm-as < %s | llc | grep {subfze r4,r2}
; RUN: llvm-as < %s | llc -regalloc=local | grep {subfc r5,r2,r4}
; RUN: llvm-as < %s | llc -regalloc=local | grep {subfze r2,r3}
; The first argument of subfc must not be the same as any other register.
; PR1357

View File

@ -2,6 +2,10 @@
; RUN: llvm-as < %s | llc -march=x86 | not grep "movl %edx, %edx"
; RUN: llvm-as < %s | llc -march=x86 | not grep "movl (%eax), %eax"
; RUN: llvm-as < %s | llc -march=x86 | not grep "movl (%edx), %edx"
; RUN: llvm-as < %s | llc -march=x86 -regalloc=local | not grep "movl %eax, %eax"
; RUN: llvm-as < %s | llc -march=x86 -regalloc=local | not grep "movl %edx, %edx"
; RUN: llvm-as < %s | llc -march=x86 -regalloc=local | not grep "movl (%eax), %eax"
; RUN: llvm-as < %s | llc -march=x86 -regalloc=local | not grep "movl (%edx), %edx"
; %0 must not be put in EAX or EDX.
; In the first asm, $0 and $2 must not be put in EAX.

View File

@ -0,0 +1,26 @@
; RUN: llvm-as < %s | llc -march=x86 | grep "#%ebp %eax %edx 8(%esi) %ebx (%edi)"
; RUN: llvm-as < %s | llc -march=x86 -regalloc=local | grep "#%ecx %eax %edx 8(%edi) %ebx (%esi)"
; The 1st, 2nd, 3rd and 5th registers above must all be different. The registers
; referenced in the 4th and 6th operands must not be the same as the 1st or 5th
; operand. There are many combinations that work; this is what llc puts out now.
; ModuleID = '<stdin>'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
target triple = "i386-apple-darwin8"
%struct.foo = type { i32, i32, i8* }
define i32 @get(%struct.foo* %c, i8* %state) nounwind {
entry:
%0 = getelementptr %struct.foo* %c, i32 0, i32 0 ; <i32*> [#uses=2]
%1 = getelementptr %struct.foo* %c, i32 0, i32 1 ; <i32*> [#uses=2]
%2 = getelementptr %struct.foo* %c, i32 0, i32 2 ; <i8**> [#uses=2]
%3 = load i32* %0, align 4 ; <i32> [#uses=1]
%4 = load i32* %1, align 4 ; <i32> [#uses=1]
%5 = load i8* %state, align 1 ; <i8> [#uses=1]
%asmtmp = tail call { i32, i32, i32, i32 } asm sideeffect "#$0 $1 $2 $3 $4 $5", "=&r,=r,=r,=*m,=&q,=*imr,1,2,*m,5,~{dirflag},~{fpsr},~{flags},~{cx}"(i8** %2, i8* %state, i32 %3, i32 %4, i8** %2, i8 %5) nounwind ; <{ i32, i32, i32, i32 }> [#uses=3]
%asmresult = extractvalue { i32, i32, i32, i32 } %asmtmp, 0 ; <i32> [#uses=1]
%asmresult1 = extractvalue { i32, i32, i32, i32 } %asmtmp, 1 ; <i32> [#uses=1]
store i32 %asmresult1, i32* %0
%asmresult2 = extractvalue { i32, i32, i32, i32 } %asmtmp, 2 ; <i32> [#uses=1]
store i32 %asmresult2, i32* %1
ret i32 %asmresult
}