| //===-- SPUTargetMachine.cpp - Define TargetMachine for Cell SPU ----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Top-level implementation for the Cell SPU target. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SPU.h" |
| #include "SPUFrameLowering.h" |
| #include "SPUInstrBuilder.h" |
| #include "SPUInstrInfo.h" |
| #include "llvm/Function.h" |
| #include "llvm/CodeGen/MachineFrameInfo.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/MachineModuleInfo.h" |
| #include "llvm/CodeGen/MachineRegisterInfo.h" |
| #include "llvm/CodeGen/RegisterScavenging.h" |
| #include "llvm/Target/TargetData.h" |
| #include "llvm/Target/TargetOptions.h" |
| #include "llvm/Support/CommandLine.h" |
| using namespace llvm; |
| |
| //===----------------------------------------------------------------------===// |
| // SPUFrameLowering: |
| //===----------------------------------------------------------------------===// |
| |
| SPUFrameLowering::SPUFrameLowering(const SPUSubtarget &sti) |
| : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 16, 0), |
| Subtarget(sti) { |
| LR[0].first = SPU::R0; |
| LR[0].second = 16; |
| } |
| |
| |
| //-------------------------------------------------------------------------- |
| // hasFP - Return true if the specified function actually has a dedicated frame |
| // pointer register. This is true if the function needs a frame pointer and has |
| // a non-zero stack size. |
| bool SPUFrameLowering::hasFP(const MachineFunction &MF) const { |
| const MachineFrameInfo *MFI = MF.getFrameInfo(); |
| |
| return MFI->getStackSize() && |
| (DisableFramePointerElim(MF) || MFI->hasVarSizedObjects()); |
| } |
| |
| |
| /// determineFrameLayout - Determine the size of the frame and maximum call |
| /// frame size. |
| void SPUFrameLowering::determineFrameLayout(MachineFunction &MF) const { |
| MachineFrameInfo *MFI = MF.getFrameInfo(); |
| |
| // Get the number of bytes to allocate from the FrameInfo |
| unsigned FrameSize = MFI->getStackSize(); |
| |
| // Get the alignments provided by the target, and the maximum alignment |
| // (if any) of the fixed frame objects. |
| unsigned TargetAlign = getStackAlignment(); |
| unsigned Align = std::max(TargetAlign, MFI->getMaxAlignment()); |
| assert(isPowerOf2_32(Align) && "Alignment is not power of 2"); |
| unsigned AlignMask = Align - 1; |
| |
| // Get the maximum call frame size of all the calls. |
| unsigned maxCallFrameSize = MFI->getMaxCallFrameSize(); |
| |
| // If we have dynamic alloca then maxCallFrameSize needs to be aligned so |
| // that allocations will be aligned. |
| if (MFI->hasVarSizedObjects()) |
| maxCallFrameSize = (maxCallFrameSize + AlignMask) & ~AlignMask; |
| |
| // Update maximum call frame size. |
| MFI->setMaxCallFrameSize(maxCallFrameSize); |
| |
| // Include call frame size in total. |
| FrameSize += maxCallFrameSize; |
| |
| // Make sure the frame is aligned. |
| FrameSize = (FrameSize + AlignMask) & ~AlignMask; |
| |
| // Update frame info. |
| MFI->setStackSize(FrameSize); |
| } |
| |
| void SPUFrameLowering::emitPrologue(MachineFunction &MF) const { |
| MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB |
| MachineBasicBlock::iterator MBBI = MBB.begin(); |
| MachineFrameInfo *MFI = MF.getFrameInfo(); |
| const SPUInstrInfo &TII = |
| *static_cast<const SPUInstrInfo*>(MF.getTarget().getInstrInfo()); |
| MachineModuleInfo &MMI = MF.getMMI(); |
| DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); |
| |
| // Prepare for debug frame info. |
| bool hasDebugInfo = MMI.hasDebugInfo(); |
| MCSymbol *FrameLabel = 0; |
| |
| // Move MBBI back to the beginning of the function. |
| MBBI = MBB.begin(); |
| |
| // Work out frame sizes. |
| determineFrameLayout(MF); |
| int FrameSize = MFI->getStackSize(); |
| |
| assert((FrameSize & 0xf) == 0 |
| && "SPURegisterInfo::emitPrologue: FrameSize not aligned"); |
| |
| // the "empty" frame size is 16 - just the register scavenger spill slot |
| if (FrameSize > 16 || MFI->adjustsStack()) { |
| FrameSize = -(FrameSize + SPUFrameLowering::minStackSize()); |
| if (hasDebugInfo) { |
| // Mark effective beginning of when frame pointer becomes valid. |
| FrameLabel = MMI.getContext().CreateTempSymbol(); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(FrameLabel); |
| } |
| |
| // Adjust stack pointer, spilling $lr -> 16($sp) and $sp -> -FrameSize($sp) |
| // for the ABI |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr32), SPU::R0).addImm(16) |
| .addReg(SPU::R1); |
| if (isInt<10>(FrameSize)) { |
| // Spill $sp to adjusted $sp |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr32), SPU::R1).addImm(FrameSize) |
| .addReg(SPU::R1); |
| // Adjust $sp by required amout |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::AIr32), SPU::R1).addReg(SPU::R1) |
| .addImm(FrameSize); |
| } else if (isInt<16>(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) |
| .addImm(-16) |
| .addReg(SPU::R1); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::ILr32), SPU::R2) |
| .addImm(FrameSize); |
| 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) |
| .addReg(SPU::R1) |
| .addReg(SPU::R2); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::SFIr32), SPU::R2) |
| .addReg(SPU::R2) |
| .addImm(16); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::LQXr128), SPU::R2) |
| .addReg(SPU::R2) |
| .addReg(SPU::R1); |
| } else { |
| report_fatal_error("Unhandled frame size: " + Twine(FrameSize)); |
| } |
| |
| if (hasDebugInfo) { |
| std::vector<MachineMove> &Moves = MMI.getFrameMoves(); |
| |
| // Show update of SP. |
| MachineLocation SPDst(MachineLocation::VirtualFP); |
| MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize); |
| Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); |
| |
| // Add callee saved registers to move list. |
| const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); |
| for (unsigned I = 0, E = CSI.size(); I != E; ++I) { |
| int Offset = MFI->getObjectOffset(CSI[I].getFrameIdx()); |
| unsigned Reg = CSI[I].getReg(); |
| if (Reg == SPU::R0) continue; |
| MachineLocation CSDst(MachineLocation::VirtualFP, Offset); |
| MachineLocation CSSrc(Reg); |
| Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc)); |
| } |
| |
| // Mark effective beginning of when frame pointer is ready. |
| MCSymbol *ReadyLabel = MMI.getContext().CreateTempSymbol(); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(ReadyLabel); |
| |
| MachineLocation FPDst(SPU::R1); |
| MachineLocation FPSrc(MachineLocation::VirtualFP); |
| Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc)); |
| } |
| } |
| } |
| |
| void SPUFrameLowering::emitEpilogue(MachineFunction &MF, |
| MachineBasicBlock &MBB) const { |
| MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
| const SPUInstrInfo &TII = |
| *static_cast<const SPUInstrInfo*>(MF.getTarget().getInstrInfo()); |
| const MachineFrameInfo *MFI = MF.getFrameInfo(); |
| int FrameSize = MFI->getStackSize(); |
| int LinkSlotOffset = SPUFrameLowering::stackSlotSize(); |
| DebugLoc dl = MBBI->getDebugLoc(); |
| |
| assert(MBBI->getOpcode() == SPU::RET && |
| "Can only insert epilog into returning blocks"); |
| assert((FrameSize & 0xf) == 0 && "FrameSize not aligned"); |
| |
| // the "empty" frame size is 16 - just the register scavenger spill slot |
| if (FrameSize > 16 || MFI->adjustsStack()) { |
| FrameSize = FrameSize + SPUFrameLowering::minStackSize(); |
| if (isInt<10>(FrameSize + LinkSlotOffset)) { |
| // Reload $lr, adjust $sp by required amount |
| // Note: We do this to slightly improve dual issue -- not by much, but it |
| // is an opportunity for dual issue. |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::LQDr128), SPU::R0) |
| .addImm(FrameSize + LinkSlotOffset) |
| .addReg(SPU::R1); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::AIr32), SPU::R1) |
| .addReg(SPU::R1) |
| .addImm(FrameSize); |
| } else if (FrameSize <= (1 << 16) - 1 && FrameSize >= -(1 << 16)) { |
| // 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) |
| .addImm(16) |
| .addReg(SPU::R1); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::ILr32), SPU::R2) |
| .addImm(FrameSize); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::Ar32), SPU::R1) |
| .addReg(SPU::R1) |
| .addReg(SPU::R2); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::LQDr128), SPU::R0) |
| .addImm(16) |
| .addReg(SPU::R1); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::SFIr32), SPU::R2). |
| addReg(SPU::R2) |
| .addImm(16); |
| BuildMI(MBB, MBBI, dl, TII.get(SPU::LQXr128), SPU::R2) |
| .addReg(SPU::R2) |
| .addReg(SPU::R1); |
| } else { |
| report_fatal_error("Unhandled frame size: " + Twine(FrameSize)); |
| } |
| } |
| } |
| |
| void SPUFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, |
| RegScavenger *RS) const{ |
| // Mark LR and SP unused, since the prolog spills them to stack and |
| // we don't want anyone else to spill them for us. |
| // |
| // Also, unless R2 is really used someday, don't spill it automatically. |
| 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)); |
| } |