mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222571 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			350 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- HexagonFrameLowering.cpp - Define frame lowering ------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "HexagonFrameLowering.h"
 | |
| #include "Hexagon.h"
 | |
| #include "HexagonInstrInfo.h"
 | |
| #include "HexagonMachineFunctionInfo.h"
 | |
| #include "HexagonRegisterInfo.h"
 | |
| #include "HexagonSubtarget.h"
 | |
| #include "HexagonTargetMachine.h"
 | |
| #include "llvm/ADT/BitVector.h"
 | |
| #include "llvm/ADT/STLExtras.h"
 | |
| #include "llvm/CodeGen/AsmPrinter.h"
 | |
| #include "llvm/CodeGen/MachineFrameInfo.h"
 | |
| #include "llvm/CodeGen/MachineFunction.h"
 | |
| #include "llvm/CodeGen/MachineFunctionPass.h"
 | |
| #include "llvm/CodeGen/MachineInstrBuilder.h"
 | |
| #include "llvm/CodeGen/MachineModuleInfo.h"
 | |
| #include "llvm/CodeGen/MachineRegisterInfo.h"
 | |
| #include "llvm/CodeGen/RegisterScavenging.h"
 | |
| #include "llvm/IR/Function.h"
 | |
| #include "llvm/IR/Type.h"
 | |
| #include "llvm/MC/MCAsmInfo.h"
 | |
| #include "llvm/MC/MachineLocation.h"
 | |
| #include "llvm/Support/CommandLine.h"
 | |
| #include "llvm/Target/TargetInstrInfo.h"
 | |
| #include "llvm/Target/TargetMachine.h"
 | |
| #include "llvm/Target/TargetOptions.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| static cl::opt<bool> DisableDeallocRet(
 | |
|                        "disable-hexagon-dealloc-ret",
 | |
|                        cl::Hidden,
 | |
|                        cl::desc("Disable Dealloc Return for Hexagon target"));
 | |
| 
 | |
| /// determineFrameLayout - Determine the size of the frame and maximum call
 | |
| /// frame size.
 | |
| void HexagonFrameLowering::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.
 | |
|   unsigned TargetAlign = MF.getTarget()
 | |
|                              .getSubtargetImpl()
 | |
|                              ->getFrameLowering()
 | |
|                              ->getStackAlignment();
 | |
|   // 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 = RoundUpToAlignment(maxCallFrameSize, TargetAlign);
 | |
| 
 | |
|   // Update maximum call frame size.
 | |
|   MFI->setMaxCallFrameSize(maxCallFrameSize);
 | |
| 
 | |
|   // Include call frame size in total.
 | |
|   FrameSize += maxCallFrameSize;
 | |
| 
 | |
|   // Make sure the frame is aligned.
 | |
|   FrameSize = RoundUpToAlignment(FrameSize, TargetAlign);
 | |
| 
 | |
|   // Update frame info.
 | |
|   MFI->setStackSize(FrameSize);
 | |
| }
 | |
| 
 | |
| 
 | |
| void HexagonFrameLowering::emitPrologue(MachineFunction &MF) const {
 | |
|   MachineBasicBlock &MBB = MF.front();
 | |
|   MachineFrameInfo *MFI = MF.getFrameInfo();
 | |
|   MachineBasicBlock::iterator MBBI = MBB.begin();
 | |
|   const HexagonRegisterInfo *QRI = static_cast<const HexagonRegisterInfo *>(
 | |
|       MF.getSubtarget().getRegisterInfo());
 | |
|   DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
 | |
|   determineFrameLayout(MF);
 | |
| 
 | |
|   // Get the number of bytes to allocate from the FrameInfo.
 | |
|   int NumBytes = (int) MFI->getStackSize();
 | |
| 
 | |
|   // LLVM expects allocframe not to be the first instruction in the
 | |
|   // basic block.
 | |
|   MachineBasicBlock::iterator InsertPt = MBB.begin();
 | |
| 
 | |
|   //
 | |
|   // ALLOCA adjust regs.  Iterate over ADJDYNALLOC nodes and change the offset.
 | |
|   //
 | |
|   HexagonMachineFunctionInfo *FuncInfo =
 | |
|     MF.getInfo<HexagonMachineFunctionInfo>();
 | |
|   const std::vector<MachineInstr*>& AdjustRegs =
 | |
|     FuncInfo->getAllocaAdjustInsts();
 | |
|   for (std::vector<MachineInstr*>::const_iterator i = AdjustRegs.begin(),
 | |
|          e = AdjustRegs.end();
 | |
|        i != e; ++i) {
 | |
|     MachineInstr* MI = *i;
 | |
|     assert((MI->getOpcode() == Hexagon::ADJDYNALLOC) &&
 | |
|            "Expected adjust alloca node");
 | |
| 
 | |
|     MachineOperand& MO = MI->getOperand(2);
 | |
|     assert(MO.isImm() && "Expected immediate");
 | |
|     MO.setImm(MFI->getMaxCallFrameSize());
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Only insert ALLOCFRAME if we need to.
 | |
|   //
 | |
|   if (hasFP(MF)) {
 | |
|     // Check for overflow.
 | |
|     // Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
 | |
|     const int ALLOCFRAME_MAX = 16384;
 | |
|     const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
 | |
| 
 | |
|     if (NumBytes >= ALLOCFRAME_MAX) {
 | |
|       // Emit allocframe(#0).
 | |
|       BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(0);
 | |
| 
 | |
|       // Subtract offset from frame pointer.
 | |
|       BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::CONST32_Int_Real),
 | |
|                                       HEXAGON_RESERVED_REG_1).addImm(NumBytes);
 | |
|       BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::A2_sub),
 | |
|                                       QRI->getStackRegister()).
 | |
|                                       addReg(QRI->getStackRegister()).
 | |
|                                       addReg(HEXAGON_RESERVED_REG_1);
 | |
|     } else {
 | |
|       BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(NumBytes);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| // Returns true if MBB has a machine instructions that indicates a tail call
 | |
| // in the block.
 | |
| bool HexagonFrameLowering::hasTailCall(MachineBasicBlock &MBB) const {
 | |
|   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
 | |
|   unsigned RetOpcode = MBBI->getOpcode();
 | |
| 
 | |
|   return RetOpcode == Hexagon::TCRETURNtg || RetOpcode == Hexagon::TCRETURNtext;
 | |
| }
 | |
| 
 | |
| void HexagonFrameLowering::emitEpilogue(MachineFunction &MF,
 | |
|                                      MachineBasicBlock &MBB) const {
 | |
|   MachineBasicBlock::iterator MBBI = std::prev(MBB.end());
 | |
|   DebugLoc dl = MBBI->getDebugLoc();
 | |
|   //
 | |
|   // Only insert deallocframe if we need to.  Also at -O0.  See comment
 | |
|   // in emitPrologue above.
 | |
|   //
 | |
|   if (hasFP(MF) || MF.getTarget().getOptLevel() == CodeGenOpt::None) {
 | |
|     MachineBasicBlock::iterator MBBI = std::prev(MBB.end());
 | |
|     MachineBasicBlock::iterator MBBI_end = MBB.end();
 | |
| 
 | |
|     const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
 | |
|     // Handle EH_RETURN.
 | |
|     if (MBBI->getOpcode() == Hexagon::EH_RETURN_JMPR) {
 | |
|       assert(MBBI->getOperand(0).isReg() && "Offset should be in register!");
 | |
|       BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME));
 | |
|       BuildMI(MBB, MBBI, dl, TII.get(Hexagon::A2_add),
 | |
|               Hexagon::R29).addReg(Hexagon::R29).addReg(Hexagon::R28);
 | |
|       return;
 | |
|     }
 | |
|     // Replace 'jumpr r31' instruction with dealloc_return for V4 and higher
 | |
|     // versions.
 | |
|     if (MF.getTarget().getSubtarget<HexagonSubtarget>().hasV4TOps() &&
 | |
|         MBBI->getOpcode() == Hexagon::JMPret && !DisableDeallocRet) {
 | |
|       // Check for RESTORE_DEALLOC_RET_JMP_V4 call. Don't emit an extra DEALLOC
 | |
|       // instruction if we encounter it.
 | |
|       MachineBasicBlock::iterator BeforeJMPR =
 | |
|         MBB.begin() == MBBI ? MBBI : std::prev(MBBI);
 | |
|       if (BeforeJMPR != MBBI &&
 | |
|           BeforeJMPR->getOpcode() == Hexagon::RESTORE_DEALLOC_RET_JMP_V4) {
 | |
|         // Remove the JMPR node.
 | |
|         MBB.erase(MBBI);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       // Add dealloc_return.
 | |
|       MachineInstrBuilder MIB =
 | |
|         BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4));
 | |
|       // Transfer the function live-out registers.
 | |
|       MIB->copyImplicitOps(*MBB.getParent(), &*MBBI);
 | |
|       // Remove the JUMPR node.
 | |
|       MBB.erase(MBBI);
 | |
|     } else { // Add deallocframe for V2 and V3, and V4 tail calls.
 | |
|       // Check for RESTORE_DEALLOC_BEFORE_TAILCALL_V4. We don't need an extra
 | |
|       // DEALLOCFRAME instruction after it.
 | |
|       MachineBasicBlock::iterator Term = MBB.getFirstTerminator();
 | |
|       MachineBasicBlock::iterator I =
 | |
|         Term == MBB.begin() ?  MBB.end() : std::prev(Term);
 | |
|       if (I != MBB.end() &&
 | |
|           I->getOpcode() == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4)
 | |
|         return;
 | |
| 
 | |
|       BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
 | |
|   const MachineFrameInfo *MFI = MF.getFrameInfo();
 | |
|   const HexagonMachineFunctionInfo *FuncInfo =
 | |
|     MF.getInfo<HexagonMachineFunctionInfo>();
 | |
|   return (MFI->hasCalls() || (MFI->getStackSize() > 0) ||
 | |
|           FuncInfo->hasClobberLR() );
 | |
| }
 | |
| 
 | |
| static inline
 | |
| unsigned uniqueSuperReg(unsigned Reg, const TargetRegisterInfo *TRI) {
 | |
|   MCSuperRegIterator SRI(Reg, TRI);
 | |
|   assert(SRI.isValid() && "Expected a superreg");
 | |
|   unsigned SuperReg = *SRI;
 | |
|   ++SRI;
 | |
|   assert(!SRI.isValid() && "Expected exactly one superreg");
 | |
|   return SuperReg;
 | |
| }
 | |
| 
 | |
| bool
 | |
| HexagonFrameLowering::spillCalleeSavedRegisters(
 | |
|                                         MachineBasicBlock &MBB,
 | |
|                                         MachineBasicBlock::iterator MI,
 | |
|                                         const std::vector<CalleeSavedInfo> &CSI,
 | |
|                                         const TargetRegisterInfo *TRI) const {
 | |
|   MachineFunction *MF = MBB.getParent();
 | |
|   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
 | |
| 
 | |
|   if (CSI.empty()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // We can only schedule double loads if we spill contiguous callee-saved regs
 | |
|   // For instance, we cannot scheduled double-word loads if we spill r24,
 | |
|   // r26, and r27.
 | |
|   // Hexagon_TODO: We can try to double-word align odd registers for -O2 and
 | |
|   // above.
 | |
|   bool ContiguousRegs = true;
 | |
| 
 | |
|   for (unsigned i = 0; i < CSI.size(); ++i) {
 | |
|     unsigned Reg = CSI[i].getReg();
 | |
| 
 | |
|     //
 | |
|     // Check if we can use a double-word store.
 | |
|     //
 | |
|     unsigned SuperReg = uniqueSuperReg(Reg, TRI);
 | |
|     bool CanUseDblStore = false;
 | |
|     const TargetRegisterClass* SuperRegClass = nullptr;
 | |
| 
 | |
|     if (ContiguousRegs && (i < CSI.size()-1)) {
 | |
|       unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
 | |
|       SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
 | |
|       CanUseDblStore = (SuperRegNext == SuperReg);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if (CanUseDblStore) {
 | |
|       TII.storeRegToStackSlot(MBB, MI, SuperReg, true,
 | |
|                               CSI[i+1].getFrameIdx(), SuperRegClass, TRI);
 | |
|       MBB.addLiveIn(SuperReg);
 | |
|       ++i;
 | |
|     } else {
 | |
|       // Cannot use a double-word store.
 | |
|       ContiguousRegs = false;
 | |
|       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
 | |
|       TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i].getFrameIdx(), RC,
 | |
|                               TRI);
 | |
|       MBB.addLiveIn(Reg);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool HexagonFrameLowering::restoreCalleeSavedRegisters(
 | |
|                                         MachineBasicBlock &MBB,
 | |
|                                         MachineBasicBlock::iterator MI,
 | |
|                                         const std::vector<CalleeSavedInfo> &CSI,
 | |
|                                         const TargetRegisterInfo *TRI) const {
 | |
| 
 | |
|   MachineFunction *MF = MBB.getParent();
 | |
|   const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
 | |
| 
 | |
|   if (CSI.empty()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // We can only schedule double loads if we spill contiguous callee-saved regs
 | |
|   // For instance, we cannot scheduled double-word loads if we spill r24,
 | |
|   // r26, and r27.
 | |
|   // Hexagon_TODO: We can try to double-word align odd registers for -O2 and
 | |
|   // above.
 | |
|   bool ContiguousRegs = true;
 | |
| 
 | |
|   for (unsigned i = 0; i < CSI.size(); ++i) {
 | |
|     unsigned Reg = CSI[i].getReg();
 | |
| 
 | |
|     //
 | |
|     // Check if we can use a double-word load.
 | |
|     //
 | |
|     unsigned SuperReg = uniqueSuperReg(Reg, TRI);
 | |
|     const TargetRegisterClass* SuperRegClass = nullptr;
 | |
|     bool CanUseDblLoad = false;
 | |
|     if (ContiguousRegs && (i < CSI.size()-1)) {
 | |
|       unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
 | |
|       SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
 | |
|       CanUseDblLoad = (SuperRegNext == SuperReg);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if (CanUseDblLoad) {
 | |
|       TII.loadRegFromStackSlot(MBB, MI, SuperReg, CSI[i+1].getFrameIdx(),
 | |
|                                SuperRegClass, TRI);
 | |
|       MBB.addLiveIn(SuperReg);
 | |
|       ++i;
 | |
|     } else {
 | |
|       // Cannot use a double-word load.
 | |
|       ContiguousRegs = false;
 | |
|       const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
 | |
|       TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI);
 | |
|       MBB.addLiveIn(Reg);
 | |
|     }
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void HexagonFrameLowering::
 | |
| eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
 | |
|                               MachineBasicBlock::iterator I) const {
 | |
|   MachineInstr &MI = *I;
 | |
| 
 | |
|   if (MI.getOpcode() == Hexagon::ADJCALLSTACKDOWN) {
 | |
|     // Hexagon_TODO: add code
 | |
|   } else if (MI.getOpcode() == Hexagon::ADJCALLSTACKUP) {
 | |
|     // Hexagon_TODO: add code
 | |
|   } else {
 | |
|     llvm_unreachable("Cannot handle this call frame pseudo instruction");
 | |
|   }
 | |
|   MBB.erase(I);
 | |
| }
 | |
| 
 | |
| int HexagonFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
 | |
|                                               int FI) const {
 | |
|   return MF.getFrameInfo()->getObjectOffset(FI);
 | |
| }
 |