//! Predicate test for an unsigned 10-bit value
/*!
\param Value The input value to be tested
-
- This predicate tests for an unsigned 10-bit value, returning the 10-bit value
- as a short if true.
*/
inline bool isU10Constant(short Value) {
return (Value == (Value & 0x3ff));
return (Value == (Value & 0x3ff));
}
+ //! Predicate test for a signed 14-bit value
+ /*!
+ \param Value The input value to be tested
+ */
+ template<typename T>
+ inline bool isS14Constant(T Value);
+
+ template<>
+ inline bool isS14Constant<short>(short Value) {
+ return (Value >= -(1 << 13) && Value <= (1 << 13) - 1);
+ }
+
+ template<>
+ inline bool isS14Constant<int>(int Value) {
+ return (Value >= -(1 << 13) && Value <= (1 << 13) - 1);
+ }
+
+ template<>
+ inline bool isS14Constant<uint32_t>(uint32_t Value) {
+ return (Value <= ((1 << 13) - 1));
+ }
+
+ template<>
+ inline bool isS14Constant<int64_t>(int64_t Value) {
+ return (Value >= -(1 << 13) && Value <= (1 << 13) - 1);
+ }
+
+ template<>
+ inline bool isS14Constant<uint64_t>(uint64_t Value) {
+ return (Value <= ((1 << 13) - 1));
+ }
+
+ //! Predicate test for a signed 16-bit value
+ /*!
+ \param Value The input value to be tested
+ */
+ template<typename T>
+ inline bool isS16Constant(T Value);
+
+ template<>
+ inline bool isS16Constant<short>(short Value) {
+ return true;
+ }
+
+ template<>
+ inline bool isS16Constant<int>(int Value) {
+ return (Value >= -(1 << 15) && Value <= (1 << 15) - 1);
+ }
+
+ template<>
+ inline bool isS16Constant<uint32_t>(uint32_t Value) {
+ return (Value <= ((1 << 15) - 1));
+ }
+
+ template<>
+ inline bool isS16Constant<int64_t>(int64_t Value) {
+ return (Value >= -(1 << 15) && Value <= (1 << 15) - 1);
+ }
+
+ template<>
+ inline bool isS16Constant<uint64_t>(uint64_t Value) {
+ return (Value <= ((1 << 15) - 1));
+ }
+
extern Target TheCellSPUTarget;
}
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo *MFI = MF.getFrameInfo();
+ DebugLoc dl = II->getDebugLoc();
while (!MI.getOperand(i).isFI()) {
++i;
// Replace the FrameIndex with base register with $sp (aka $r1)
SPOp.ChangeToRegister(SPU::R1, false);
- if (Offset > SPUFrameInfo::maxFrameOffset()
- || Offset < SPUFrameInfo::minFrameOffset()) {
- errs() << "Large stack adjustment ("
- << Offset
- << ") in SPURegisterInfo::eliminateFrameIndex.";
+
+ // if 'Offset' doesn't fit to the D-form instruction's
+ // immediate, convert the instruction to X-form
+ // if the instruction is not an AI (which takes a s10 immediate), assume
+ // it is a load/store that can take a s14 immediate
+ if ( (MI.getOpcode() == SPU::AIr32 && !isS10Constant(Offset))
+ || !isS14Constant(Offset) ) {
+ int newOpcode = convertDFormToXForm(MI.getOpcode());
+ unsigned tmpReg = findScratchRegister(II, RS, &SPU::R32CRegClass, SPAdj);
+ BuildMI(MBB, II, dl, TII.get(SPU::ILr32), tmpReg )
+ .addImm(Offset);
+ BuildMI(MBB, II, dl, TII.get(newOpcode), MI.getOperand(0).getReg())
+ .addReg(tmpReg, RegState::Kill)
+ .addReg(SPU::R1);
+ // remove the replaced D-form instruction
+ MBB.erase(II);
} else {
MO.ChangeToImmediate(Offset);
}
MF.getRegInfo().setPhysRegUnused(SPU::R0);
MF.getRegInfo().setPhysRegUnused(SPU::R1);
MF.getRegInfo().setPhysRegUnused(SPU::R2);
+
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const TargetRegisterClass *RC = &SPU::R32CRegClass;
+ RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
+
+
}
void SPURegisterInfo::emitPrologue(MachineFunction &MF) const
assert((FrameSize & 0xf) == 0
&& "SPURegisterInfo::emitPrologue: FrameSize not aligned");
- if (FrameSize > 0 || MFI->hasCalls()) {
+ // the "empty" frame size is 16 - just the register scavenger spill slot
+ if (FrameSize > 16 || MFI->hasCalls()) {
FrameSize = -(FrameSize + SPUFrameInfo::minStackSize());
if (hasDebugInfo) {
// Mark effective beginning of when frame pointer becomes valid.
// Adjust $sp by required amout
BuildMI(MBB, MBBI, dl, TII.get(SPU::AIr32), SPU::R1).addReg(SPU::R1)
.addImm(FrameSize);
- } else if (FrameSize <= (1 << 16) - 1 && FrameSize >= -(1 << 16)) {
+ } else if (isS16Constant(FrameSize)) {
// Frame size can be loaded into ILr32n, so temporarily spill $r2 and use
// $r2 to adjust $sp:
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr128), SPU::R2)
.addReg(SPU::R1);
BuildMI(MBB, MBBI, dl, TII.get(SPU::ILr32), SPU::R2)
.addImm(FrameSize);
- BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr32), SPU::R1)
+ BuildMI(MBB, MBBI, dl, TII.get(SPU::STQXr32), SPU::R1)
.addReg(SPU::R2)
.addReg(SPU::R1);
BuildMI(MBB, MBBI, dl, TII.get(SPU::Ar32), SPU::R1)
"Can only insert epilog into returning blocks");
assert((FrameSize & 0xf) == 0
&& "SPURegisterInfo::emitEpilogue: FrameSize not aligned");
- if (FrameSize > 0 || MFI->hasCalls()) {
+
+ // the "empty" frame size is 16 - just the register scavenger spill slot
+ if (FrameSize > 16 || MFI->hasCalls()) {
FrameSize = FrameSize + SPUFrameInfo::minStackSize();
if (isS10Constant(FrameSize + LinkSlotOffset)) {
// Reload $lr, adjust $sp by required amount
.addReg(SPU::R2);
BuildMI(MBB, MBBI, dl, TII.get(SPU::LQDr128), SPU::R0)
.addImm(16)
- .addReg(SPU::R2);
+ .addReg(SPU::R1);
BuildMI(MBB, MBBI, dl, TII.get(SPU::SFIr32), SPU::R2).
addReg(SPU::R2)
.addImm(16);
return SPUGenRegisterInfo::getDwarfRegNumFull(RegNum, 0);
}
+int
+SPURegisterInfo::convertDFormToXForm(int dFormOpcode) const
+{
+ switch(dFormOpcode)
+ {
+ case SPU::AIr32: return SPU::Ar32;
+ case SPU::LQDr32: return SPU::LQXr32;
+ case SPU::LQDr128: return SPU::LQXr128;
+ case SPU::LQDv16i8: return SPU::LQXv16i8;
+ case SPU::LQDv4f32: return SPU::LQXv4f32;
+ case SPU::STQDr32: return SPU::STQXr32;
+ case SPU::STQDr128: return SPU::STQXr128;
+ case SPU::STQDv16i8: return SPU::STQXv16i8;
+ case SPU::STQDv4i32: return SPU::STQXv4i32;
+ case SPU::STQDv4f32: return SPU::STQXv4f32;
+
+ default: assert( false && "Unhandled D to X-form conversion");
+ }
+ // default will assert, but need to return something to keep the
+ // compiler happy.
+ return dFormOpcode;
+}
+
+// TODO this is already copied from PPC. Could this convenience function
+// be moved to the RegScavenger class?
+unsigned
+SPURegisterInfo::findScratchRegister(MachineBasicBlock::iterator II,
+ RegScavenger *RS,
+ const TargetRegisterClass *RC,
+ int SPAdj) const
+{
+ assert(RS && "Register scavenging must be on");
+ unsigned Reg = RS->FindUnusedReg(RC);
+ if (Reg == 0)
+ Reg = RS->scavengeRegister(RC, II, SPAdj);
+ assert( Reg && "Register scavenger failed");
+ return Reg;
+}
+
#include "SPUGenRegisterInfo.inc"