mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-21 06:30:16 +00:00
Add Thumb1 support for virtual frame indices.
rdar://8277890 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111533 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c546c75459
commit
74d7b0af58
@ -1385,13 +1385,6 @@ needsFrameBaseReg(MachineInstr *MI, unsigned operand) const {
|
||||
|
||||
// FIXME: For testing, return true for all loads/stores and false for
|
||||
// everything else. We want to create lots of base regs to shake out bugs.
|
||||
//
|
||||
// FIXME: This is Thumb2/ARM only for now to keep it simpler.
|
||||
ARMFunctionInfo *AFI =
|
||||
MI->getParent()->getParent()->getInfo<ARMFunctionInfo>();
|
||||
if (AFI->isThumb1OnlyFunction())
|
||||
return false;
|
||||
|
||||
unsigned Opc = MI->getOpcode();
|
||||
|
||||
switch (Opc) {
|
||||
@ -1401,6 +1394,7 @@ needsFrameBaseReg(MachineInstr *MI, unsigned operand) const {
|
||||
case ARM::t2STRi12: case ARM::t2STRi8:
|
||||
case ARM::VLDRS: case ARM::VLDRD:
|
||||
case ARM::VSTRS: case ARM::VSTRD:
|
||||
case ARM::tSTRspi: case ARM::tLDRspi:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -1414,14 +1408,14 @@ materializeFrameBaseRegister(MachineBasicBlock::iterator I,
|
||||
unsigned BaseReg, int FrameIdx) const {
|
||||
ARMFunctionInfo *AFI =
|
||||
I->getParent()->getParent()->getInfo<ARMFunctionInfo>();
|
||||
unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri;
|
||||
assert(!AFI->isThumb1OnlyFunction() &&
|
||||
"This materializeFrameBaseRegister does not support Thumb1!");
|
||||
unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri :
|
||||
(AFI->isThumb1OnlyFunction() ? ARM::tADDrSPi : ARM::t2ADDri);
|
||||
|
||||
MachineInstrBuilder MIB =
|
||||
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII.get(ADDriOpc), BaseReg)
|
||||
.addFrameIndex(FrameIdx).addImm(0);
|
||||
AddDefaultCC(AddDefaultPred(MIB));
|
||||
if (!AFI->isThumb1OnlyFunction())
|
||||
AddDefaultCC(AddDefaultPred(MIB));
|
||||
}
|
||||
|
||||
void
|
||||
@ -1469,13 +1463,14 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI,
|
||||
unsigned NumBits = 0;
|
||||
unsigned Scale = 1;
|
||||
unsigned ImmIdx = 0;
|
||||
int InstrOffs;
|
||||
int InstrOffs = 0;;
|
||||
switch(AddrMode) {
|
||||
case ARMII::AddrModeT2_i8:
|
||||
case ARMII::AddrModeT2_i12:
|
||||
// i8 supports only negative, and i12 supports only positive, so
|
||||
// based on Offset sign, consider the appropriate instruction
|
||||
Offset += MI->getOperand(i+1).getImm();
|
||||
InstrOffs = MI->getOperand(i+1).getImm();
|
||||
Scale = 1;
|
||||
if (Offset < 0) {
|
||||
NumBits = 8;
|
||||
Offset = -Offset;
|
||||
@ -1509,6 +1504,13 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI,
|
||||
NumBits = 8;
|
||||
break;
|
||||
}
|
||||
case ARMII::AddrModeT1_s: {
|
||||
ImmIdx = i+1;
|
||||
InstrOffs = MI->getOperand(ImmIdx).getImm();
|
||||
NumBits = 5;
|
||||
Scale = 4;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unsupported addressing mode!");
|
||||
break;
|
||||
|
@ -363,14 +363,173 @@ static void removeOperands(MachineInstr &MI, unsigned i) {
|
||||
MI.RemoveOperand(Op);
|
||||
}
|
||||
|
||||
int Thumb1RegisterInfo::
|
||||
rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||
unsigned FrameReg, int Offset,
|
||||
unsigned MOVOpc, unsigned ADDriOpc, unsigned SUBriOpc) const
|
||||
{
|
||||
// if/when eliminateFrameIndex() conforms with ARMBaseRegisterInfo
|
||||
// version then can pull out Thumb1 specific parts here
|
||||
return 0;
|
||||
bool Thumb1RegisterInfo::
|
||||
rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
|
||||
unsigned FrameReg, int &Offset,
|
||||
const ARMBaseInstrInfo &TII) const {
|
||||
MachineInstr &MI = *II;
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
DebugLoc dl = MI.getDebugLoc();
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
const TargetInstrDesc &Desc = MI.getDesc();
|
||||
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
|
||||
|
||||
if (Opcode == ARM::tADDrSPi) {
|
||||
Offset += MI.getOperand(FrameRegIdx+1).getImm();
|
||||
|
||||
// Can't use tADDrSPi if it's based off the frame pointer.
|
||||
unsigned NumBits = 0;
|
||||
unsigned Scale = 1;
|
||||
if (FrameReg != ARM::SP) {
|
||||
Opcode = ARM::tADDi3;
|
||||
MI.setDesc(TII.get(Opcode));
|
||||
NumBits = 3;
|
||||
} else {
|
||||
NumBits = 8;
|
||||
Scale = 4;
|
||||
assert((Offset & 3) == 0 &&
|
||||
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
|
||||
}
|
||||
|
||||
unsigned PredReg;
|
||||
if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
|
||||
// Turn it into a move.
|
||||
MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
||||
// Remove offset and remaining explicit predicate operands.
|
||||
do MI.RemoveOperand(FrameRegIdx+1);
|
||||
while (MI.getNumOperands() > FrameRegIdx+1 &&
|
||||
(!MI.getOperand(FrameRegIdx+1).isReg() ||
|
||||
!MI.getOperand(FrameRegIdx+1).isImm()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Common case: small offset, fits into instruction.
|
||||
unsigned Mask = (1 << NumBits) - 1;
|
||||
if (((Offset / Scale) & ~Mask) == 0) {
|
||||
// Replace the FrameIndex with sp / fp
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, FrameRegIdx);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg)
|
||||
.addImm(Offset / Scale));
|
||||
} else {
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset / Scale);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned DestReg = MI.getOperand(0).getReg();
|
||||
unsigned Bytes = (Offset > 0) ? Offset : -Offset;
|
||||
unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, NumBits, Scale);
|
||||
// MI would expand into a large number of instructions. Don't try to
|
||||
// simplify the immediate.
|
||||
if (NumMIs > 2) {
|
||||
emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII,
|
||||
*this, dl);
|
||||
MBB.erase(II);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Offset > 0) {
|
||||
// Translate r0 = add sp, imm to
|
||||
// r0 = add sp, 255*4
|
||||
// r0 = add r0, (imm - 255*4)
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, FrameRegIdx);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask));
|
||||
} else {
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Mask);
|
||||
}
|
||||
Offset = (Offset - Mask * Scale);
|
||||
MachineBasicBlock::iterator NII = llvm::next(II);
|
||||
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
|
||||
*this, dl);
|
||||
} else {
|
||||
// Translate r0 = add sp, -imm to
|
||||
// r0 = -imm (this is then translated into a series of instructons)
|
||||
// r0 = add r0, sp
|
||||
emitThumbConstant(MBB, II, DestReg, Offset, TII, *this, dl);
|
||||
|
||||
MI.setDesc(TII.get(ARM::tADDhirr));
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(DestReg, false, false, true);
|
||||
MI.getOperand(FrameRegIdx+1).ChangeToRegister(FrameReg, false);
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(MIB);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
unsigned ImmIdx = 0;
|
||||
int InstrOffs = 0;
|
||||
unsigned NumBits = 0;
|
||||
unsigned Scale = 1;
|
||||
switch (AddrMode) {
|
||||
case ARMII::AddrModeT1_s: {
|
||||
ImmIdx = FrameRegIdx+1;
|
||||
InstrOffs = MI.getOperand(ImmIdx).getImm();
|
||||
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
|
||||
Scale = 4;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unsupported addressing mode!");
|
||||
break;
|
||||
}
|
||||
|
||||
Offset += InstrOffs * Scale;
|
||||
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
|
||||
|
||||
// Common case: small offset, fits into instruction.
|
||||
MachineOperand &ImmOp = MI.getOperand(ImmIdx);
|
||||
int ImmedOffset = Offset / Scale;
|
||||
unsigned Mask = (1 << NumBits) - 1;
|
||||
if ((unsigned)Offset <= Mask * Scale) {
|
||||
// Replace the FrameIndex with sp
|
||||
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
||||
ImmOp.ChangeToImmediate(ImmedOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
|
||||
if (AddrMode == ARMII::AddrModeT1_s) {
|
||||
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
|
||||
// a different base register.
|
||||
NumBits = 5;
|
||||
Mask = (1 << NumBits) - 1;
|
||||
}
|
||||
// If this is a thumb spill / restore, we will be using a constpool load to
|
||||
// materialize the offset.
|
||||
if (AddrMode == ARMII::AddrModeT1_s && isThumSpillRestore)
|
||||
ImmOp.ChangeToImmediate(0);
|
||||
else {
|
||||
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
|
||||
ImmedOffset = ImmedOffset & Mask;
|
||||
ImmOp.ChangeToImmediate(ImmedOffset);
|
||||
Offset &= ~(Mask*Scale);
|
||||
}
|
||||
}
|
||||
return Offset == 0;
|
||||
}
|
||||
|
||||
void
|
||||
Thumb1RegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I,
|
||||
unsigned BaseReg, int64_t Offset) const {
|
||||
MachineInstr &MI = *I;
|
||||
int Off = Offset; // ARM doesn't need the general 64-bit offsets
|
||||
unsigned i = 0;
|
||||
|
||||
while (!MI.getOperand(i).isFI()) {
|
||||
++i;
|
||||
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
|
||||
}
|
||||
bool Done = false;
|
||||
Done = rewriteFrameIndex(MI, i, BaseReg, Off, TII);
|
||||
assert (Done && "Unable to resolve frame index!");
|
||||
}
|
||||
|
||||
/// saveScavengerRegister - Spill the register so it can be used by the
|
||||
@ -458,154 +617,20 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
const TargetInstrDesc &Desc = MI.getDesc();
|
||||
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
|
||||
|
||||
if (Opcode == ARM::tADDrSPi) {
|
||||
Offset += MI.getOperand(i+1).getImm();
|
||||
|
||||
// Can't use tADDrSPi if it's based off the frame pointer.
|
||||
unsigned NumBits = 0;
|
||||
unsigned Scale = 1;
|
||||
if (FrameReg != ARM::SP) {
|
||||
Opcode = ARM::tADDi3;
|
||||
MI.setDesc(TII.get(Opcode));
|
||||
NumBits = 3;
|
||||
} else {
|
||||
NumBits = 8;
|
||||
Scale = 4;
|
||||
assert((Offset & 3) == 0 &&
|
||||
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
|
||||
}
|
||||
|
||||
unsigned PredReg;
|
||||
if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
|
||||
// Turn it into a move.
|
||||
MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
// Remove offset and remaining explicit predicate operands.
|
||||
do MI.RemoveOperand(i+1);
|
||||
while (MI.getNumOperands() > i+1 &&
|
||||
(!MI.getOperand(i+1).isReg() || !MI.getOperand(i+1).isImm()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Common case: small offset, fits into instruction.
|
||||
unsigned Mask = (1 << NumBits) - 1;
|
||||
if (((Offset / Scale) & ~Mask) == 0) {
|
||||
// Replace the FrameIndex with sp / fp
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, i);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg)
|
||||
.addImm(Offset / Scale));
|
||||
} else {
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Offset / Scale);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned DestReg = MI.getOperand(0).getReg();
|
||||
unsigned Bytes = (Offset > 0) ? Offset : -Offset;
|
||||
unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, NumBits, Scale);
|
||||
// MI would expand into a large number of instructions. Don't try to
|
||||
// simplify the immediate.
|
||||
if (NumMIs > 2) {
|
||||
emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII,
|
||||
*this, dl);
|
||||
MBB.erase(II);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Offset > 0) {
|
||||
// Translate r0 = add sp, imm to
|
||||
// r0 = add sp, 255*4
|
||||
// r0 = add r0, (imm - 255*4)
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
removeOperands(MI, i);
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask));
|
||||
} else {
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
MI.getOperand(i+1).ChangeToImmediate(Mask);
|
||||
}
|
||||
Offset = (Offset - Mask * Scale);
|
||||
MachineBasicBlock::iterator NII = llvm::next(II);
|
||||
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
|
||||
*this, dl);
|
||||
} else {
|
||||
// Translate r0 = add sp, -imm to
|
||||
// r0 = -imm (this is then translated into a series of instructons)
|
||||
// r0 = add r0, sp
|
||||
emitThumbConstant(MBB, II, DestReg, Offset, TII, *this, dl);
|
||||
|
||||
MI.setDesc(TII.get(ARM::tADDhirr));
|
||||
MI.getOperand(i).ChangeToRegister(DestReg, false, false, true);
|
||||
MI.getOperand(i+1).ChangeToRegister(FrameReg, false);
|
||||
if (Opcode == ARM::tADDi3) {
|
||||
MachineInstrBuilder MIB(&MI);
|
||||
AddDefaultPred(MIB);
|
||||
}
|
||||
}
|
||||
// Modify MI as necessary to handle as much of 'Offset' as possible
|
||||
assert(AFI->isThumbFunction() &&
|
||||
"This eliminateFrameIndex only supports Thumb1!");
|
||||
if (rewriteFrameIndex(MI, i, FrameReg, Offset, TII))
|
||||
return 0;
|
||||
} else {
|
||||
unsigned ImmIdx = 0;
|
||||
int InstrOffs = 0;
|
||||
unsigned NumBits = 0;
|
||||
unsigned Scale = 1;
|
||||
switch (AddrMode) {
|
||||
case ARMII::AddrModeT1_s: {
|
||||
ImmIdx = i+1;
|
||||
InstrOffs = MI.getOperand(ImmIdx).getImm();
|
||||
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
|
||||
Scale = 4;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unsupported addressing mode!");
|
||||
break;
|
||||
}
|
||||
|
||||
Offset += InstrOffs * Scale;
|
||||
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
|
||||
|
||||
// Common case: small offset, fits into instruction.
|
||||
MachineOperand &ImmOp = MI.getOperand(ImmIdx);
|
||||
int ImmedOffset = Offset / Scale;
|
||||
unsigned Mask = (1 << NumBits) - 1;
|
||||
if ((unsigned)Offset <= Mask * Scale) {
|
||||
// Replace the FrameIndex with sp
|
||||
MI.getOperand(i).ChangeToRegister(FrameReg, false);
|
||||
ImmOp.ChangeToImmediate(ImmedOffset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
|
||||
if (AddrMode == ARMII::AddrModeT1_s) {
|
||||
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
|
||||
// a different base register.
|
||||
NumBits = 5;
|
||||
Mask = (1 << NumBits) - 1;
|
||||
}
|
||||
// If this is a thumb spill / restore, we will be using a constpool load to
|
||||
// materialize the offset.
|
||||
if (AddrMode == ARMII::AddrModeT1_s && isThumSpillRestore)
|
||||
ImmOp.ChangeToImmediate(0);
|
||||
else {
|
||||
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
|
||||
ImmedOffset = ImmedOffset & Mask;
|
||||
ImmOp.ChangeToImmediate(ImmedOffset);
|
||||
Offset &= ~(Mask*Scale);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, the immediate doesn't fit into the instruction. We folded
|
||||
// as much as possible above, handle the rest, providing a register that is
|
||||
// SP+LargeImm.
|
||||
assert(Offset && "This code isn't needed if offset already handled!");
|
||||
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
const TargetInstrDesc &Desc = MI.getDesc();
|
||||
|
||||
// Remove predicate first.
|
||||
int PIdx = MI.findFirstPredOperandIdx();
|
||||
if (PIdx != -1)
|
||||
|
@ -44,13 +44,14 @@ public:
|
||||
MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const;
|
||||
|
||||
// rewrite MI to access 'Offset' bytes from the FP. Return the offset that
|
||||
// could not be handled directly in MI.
|
||||
int rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||
unsigned FrameReg, int Offset,
|
||||
unsigned MOVOpc, unsigned ADDriOpc,
|
||||
unsigned SUBriOpc) const;
|
||||
|
||||
// rewrite MI to access 'Offset' bytes from the FP. Update Offset to be
|
||||
// however much remains to be handled. Return 'true' if no further
|
||||
// work is required.
|
||||
bool rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
|
||||
unsigned FrameReg, int &Offset,
|
||||
const ARMBaseInstrInfo &TII) const;
|
||||
void resolveFrameIndex(MachineBasicBlock::iterator I,
|
||||
unsigned BaseReg, int64_t Offset) const;
|
||||
bool saveScavengerRegister(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I,
|
||||
MachineBasicBlock::iterator &UseMI,
|
||||
|
Loading…
x
Reference in New Issue
Block a user