10b57cec5SDimitry Andric //===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains the ARC implementation of the TargetFrameLowering class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "ARCFrameLowering.h" 140b57cec5SDimitry Andric #include "ARCMachineFunctionInfo.h" 150b57cec5SDimitry Andric #include "ARCSubtarget.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterScavenging.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 200b57cec5SDimitry Andric #include "llvm/IR/Function.h" 210b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "arc-frame-lowering" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric static cl::opt<bool> 280b57cec5SDimitry Andric UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden, 290b57cec5SDimitry Andric cl::desc("Use arc callee save/restore functions"), 300b57cec5SDimitry Andric cl::init(true)); 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric static const char *store_funclet_name[] = { 330b57cec5SDimitry Andric "__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18", 340b57cec5SDimitry Andric "__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22", 350b57cec5SDimitry Andric "__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25", 360b57cec5SDimitry Andric }; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric static const char *load_funclet_name[] = { 390b57cec5SDimitry Andric "__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18", 400b57cec5SDimitry Andric "__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22", 410b57cec5SDimitry Andric "__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25", 420b57cec5SDimitry Andric }; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static void generateStackAdjustment(MachineBasicBlock &MBB, 450b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI, 460b57cec5SDimitry Andric const ARCInstrInfo &TII, DebugLoc dl, 470b57cec5SDimitry Andric int Amount, int StackPtr) { 480b57cec5SDimitry Andric unsigned AdjOp; 490b57cec5SDimitry Andric if (!Amount) 500b57cec5SDimitry Andric return; 510b57cec5SDimitry Andric bool Positive; 520b57cec5SDimitry Andric unsigned AbsAmount; 530b57cec5SDimitry Andric if (Amount < 0) { 540b57cec5SDimitry Andric AbsAmount = -Amount; 550b57cec5SDimitry Andric Positive = false; 560b57cec5SDimitry Andric } else { 570b57cec5SDimitry Andric AbsAmount = Amount; 580b57cec5SDimitry Andric Positive = true; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << "," 620b57cec5SDimitry Andric << AbsAmount << "\n"); 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned."); 650b57cec5SDimitry Andric if (isUInt<6>(AbsAmount)) 660b57cec5SDimitry Andric AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6; 670b57cec5SDimitry Andric else if (isInt<12>(AbsAmount)) 680b57cec5SDimitry Andric AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12; 690b57cec5SDimitry Andric else 700b57cec5SDimitry Andric AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr) 730b57cec5SDimitry Andric .addReg(StackPtr) 740b57cec5SDimitry Andric .addImm(AbsAmount); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 775ffd83dbSDimitry Andric static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) { 780b57cec5SDimitry Andric unsigned Last = 0; 790b57cec5SDimitry Andric for (auto Reg : CSI) { 800b57cec5SDimitry Andric assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 && 810b57cec5SDimitry Andric "Unexpected callee saved reg."); 820b57cec5SDimitry Andric if (Reg.getReg() > Last) 830b57cec5SDimitry Andric Last = Reg.getReg(); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric return Last; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF, 890b57cec5SDimitry Andric BitVector &SavedRegs, 900b57cec5SDimitry Andric RegScavenger *RS) const { 910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n"); 920b57cec5SDimitry Andric TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); 930b57cec5SDimitry Andric SavedRegs.set(ARC::BLINK); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric void ARCFrameLowering::adjustStackToMatchRecords( 970b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 980b57cec5SDimitry Andric bool Allocate) const { 990b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent(); 1000b57cec5SDimitry Andric int ScalarAlloc = MF.getFrameInfo().getStackSize(); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric if (Allocate) { 1030b57cec5SDimitry Andric // Allocate by adjusting by the negative of what the record holder tracked 1040b57cec5SDimitry Andric // it tracked a positive offset in a downward growing stack. 1050b57cec5SDimitry Andric ScalarAlloc = -ScalarAlloc; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(), 1090b57cec5SDimitry Andric ScalarAlloc, ARC::SP); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric /// Insert prolog code into the function. 1130b57cec5SDimitry Andric /// For ARC, this inserts a call to a function that puts required callee saved 1140b57cec5SDimitry Andric /// registers onto the stack, when enough callee saved registers are required. 1150b57cec5SDimitry Andric void ARCFrameLowering::emitPrologue(MachineFunction &MF, 1160b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 1170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n"); 1180b57cec5SDimitry Andric auto *AFI = MF.getInfo<ARCFunctionInfo>(); 119*0fca6ea1SDimitry Andric MCContext &Context = MF.getContext(); 1200b57cec5SDimitry Andric const MCRegisterInfo *MRI = Context.getRegisterInfo(); 1210b57cec5SDimitry Andric const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); 1220b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(); 1230b57cec5SDimitry Andric // Debug location must be unknown since the first debug location is used 1240b57cec5SDimitry Andric // to determine the end of the prologue. 1250b57cec5SDimitry Andric DebugLoc dl; 1260b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 1270b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 1280b57cec5SDimitry Andric unsigned Last = determineLastCalleeSave(CSI); 1290b57cec5SDimitry Andric unsigned StackSlotsUsedByFunclet = 0; 1300b57cec5SDimitry Andric bool SavedBlink = false; 1310b57cec5SDimitry Andric unsigned AlreadyAdjusted = 0; 1320b57cec5SDimitry Andric if (MF.getFunction().isVarArg()) { 1330b57cec5SDimitry Andric // Add in the varargs area here first. 1340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Varargs\n"); 1350b57cec5SDimitry Andric unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); 1360b57cec5SDimitry Andric unsigned Opc = ARC::SUB_rrlimm; 1370b57cec5SDimitry Andric if (isUInt<6>(VarArgsBytes)) 1380b57cec5SDimitry Andric Opc = ARC::SUB_rru6; 1390b57cec5SDimitry Andric else if (isInt<12>(VarArgsBytes)) 1400b57cec5SDimitry Andric Opc = ARC::SUB_rrs12; 1410b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP) 1420b57cec5SDimitry Andric .addReg(ARC::SP) 1430b57cec5SDimitry Andric .addImm(VarArgsBytes); 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric if (hasFP(MF)) { 1460b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Saving FP\n"); 1470b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9)) 1480b57cec5SDimitry Andric .addReg(ARC::SP, RegState::Define) 1490b57cec5SDimitry Andric .addReg(ARC::FP) 1500b57cec5SDimitry Andric .addReg(ARC::SP) 1510b57cec5SDimitry Andric .addImm(-4); 1520b57cec5SDimitry Andric AlreadyAdjusted += 4; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric if (UseSaveRestoreFunclet && Last > ARC::R14) { 1550b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Creating store funclet.\n"); 1560b57cec5SDimitry Andric // BL to __save_r13_to_<TRI->getRegAsmName()> 1570b57cec5SDimitry Andric StackSlotsUsedByFunclet = Last - ARC::R12; 1580b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); 1590b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6)) 1600b57cec5SDimitry Andric .addReg(ARC::SP) 1610b57cec5SDimitry Andric .addReg(ARC::SP) 1620b57cec5SDimitry Andric .addImm(4 * StackSlotsUsedByFunclet); 1630b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(ARC::BL)) 1640b57cec5SDimitry Andric .addExternalSymbol(store_funclet_name[Last - ARC::R15]) 1650b57cec5SDimitry Andric .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); 1660b57cec5SDimitry Andric AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1); 1670b57cec5SDimitry Andric SavedBlink = true; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric // If we haven't saved BLINK, but we need to...do that now. 1700b57cec5SDimitry Andric if (MFI.hasCalls() && !SavedBlink) { 1710b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Creating save blink.\n"); 1720b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); 1730b57cec5SDimitry Andric AlreadyAdjusted += 4; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric if (AFI->MaxCallStackReq > 0) 1760b57cec5SDimitry Andric MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq); 1770b57cec5SDimitry Andric // We have already saved some of the stack... 1780b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Adjusting stack by: " 1790b57cec5SDimitry Andric << (MFI.getStackSize() - AlreadyAdjusted) << "\n"); 1800b57cec5SDimitry Andric generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl, 1810b57cec5SDimitry Andric -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric if (hasFP(MF)) { 1840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Setting FP from SP.\n"); 1850b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, 1860b57cec5SDimitry Andric TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6 1870b57cec5SDimitry Andric : ARC::ADD_rrlimm), 1880b57cec5SDimitry Andric ARC::FP) 1890b57cec5SDimitry Andric .addReg(ARC::SP) 1900b57cec5SDimitry Andric .addImm(MFI.getStackSize()); 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // Emit CFI records: 1940b57cec5SDimitry Andric // .cfi_def_cfa_offset StackSize 1950b57cec5SDimitry Andric // .cfi_offset fp, -StackSize 1960b57cec5SDimitry Andric // .cfi_offset blink, -StackSize+4 1970b57cec5SDimitry Andric unsigned CFIIndex = MF.addFrameInst( 1985ffd83dbSDimitry Andric MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize())); 1990b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) 2000b57cec5SDimitry Andric .addCFIIndex(CFIIndex) 2010b57cec5SDimitry Andric .setMIFlags(MachineInstr::FrameSetup); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric int CurOffset = -4; 2040b57cec5SDimitry Andric if (hasFP(MF)) { 2050b57cec5SDimitry Andric CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 2060b57cec5SDimitry Andric nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset)); 2070b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) 2080b57cec5SDimitry Andric .addCFIIndex(CFIIndex) 2090b57cec5SDimitry Andric .setMIFlags(MachineInstr::FrameSetup); 2100b57cec5SDimitry Andric CurOffset -= 4; 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric if (MFI.hasCalls()) { 2140b57cec5SDimitry Andric CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 2150b57cec5SDimitry Andric nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset)); 2160b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) 2170b57cec5SDimitry Andric .addCFIIndex(CFIIndex) 2180b57cec5SDimitry Andric .setMIFlags(MachineInstr::FrameSetup); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric // CFI for the rest of the registers. 2210b57cec5SDimitry Andric for (const auto &Entry : CSI) { 2220b57cec5SDimitry Andric unsigned Reg = Entry.getReg(); 2230b57cec5SDimitry Andric int FI = Entry.getFrameIdx(); 2240b57cec5SDimitry Andric // Skip BLINK and FP. 2250b57cec5SDimitry Andric if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK)) 2260b57cec5SDimitry Andric continue; 2270b57cec5SDimitry Andric CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 2280b57cec5SDimitry Andric nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI))); 2290b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) 2300b57cec5SDimitry Andric .addCFIIndex(CFIIndex) 2310b57cec5SDimitry Andric .setMIFlags(MachineInstr::FrameSetup); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric /// Insert epilog code into the function. 2360b57cec5SDimitry Andric /// For ARC, this inserts a call to a function that restores callee saved 2370b57cec5SDimitry Andric /// registers onto the stack, when enough callee saved registers are required. 2380b57cec5SDimitry Andric void ARCFrameLowering::emitEpilogue(MachineFunction &MF, 2390b57cec5SDimitry Andric MachineBasicBlock &MBB) const { 2400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n"); 2410b57cec5SDimitry Andric auto *AFI = MF.getInfo<ARCFunctionInfo>(); 2420b57cec5SDimitry Andric const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); 2430b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 2440b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 2450b57cec5SDimitry Andric uint64_t StackSize = MF.getFrameInfo().getStackSize(); 2460b57cec5SDimitry Andric bool SavedBlink = false; 2470b57cec5SDimitry Andric unsigned AmountAboveFunclet = 0; 2480b57cec5SDimitry Andric // If we have variable sized frame objects, then we have to move 2490b57cec5SDimitry Andric // the stack pointer to a known spot (fp - StackSize). 2500b57cec5SDimitry Andric // Then, replace the frame pointer by (new) [sp,StackSize-4]. 2510b57cec5SDimitry Andric // Then, move the stack pointer the rest of the way (sp = sp + StackSize). 2520b57cec5SDimitry Andric if (hasFP(MF)) { 2530b57cec5SDimitry Andric unsigned Opc = ARC::SUB_rrlimm; 2540b57cec5SDimitry Andric if (isUInt<6>(StackSize)) 2550b57cec5SDimitry Andric Opc = ARC::SUB_rru6; 2560b57cec5SDimitry Andric BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP) 2570b57cec5SDimitry Andric .addReg(ARC::FP) 2580b57cec5SDimitry Andric .addImm(StackSize); 2590b57cec5SDimitry Andric AmountAboveFunclet += 4; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric // Now, move the stack pointer to the bottom of the save area for the funclet. 2630b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 2640b57cec5SDimitry Andric unsigned Last = determineLastCalleeSave(CSI); 2650b57cec5SDimitry Andric unsigned StackSlotsUsedByFunclet = 0; 2660b57cec5SDimitry Andric // Now, restore the callee save registers. 2670b57cec5SDimitry Andric if (UseSaveRestoreFunclet && Last > ARC::R14) { 2680b57cec5SDimitry Andric // BL to __ld_r13_to_<TRI->getRegAsmName()> 2690b57cec5SDimitry Andric StackSlotsUsedByFunclet = Last - ARC::R12; 2700b57cec5SDimitry Andric AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1); 2710b57cec5SDimitry Andric SavedBlink = true; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric if (MFI.hasCalls() && !SavedBlink) { 2750b57cec5SDimitry Andric AmountAboveFunclet += 4; 2760b57cec5SDimitry Andric SavedBlink = true; 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // Move the stack pointer up to the point of the funclet. 2800b57cec5SDimitry Andric if (unsigned MoveAmount = StackSize - AmountAboveFunclet) { 2810b57cec5SDimitry Andric unsigned Opc = ARC::ADD_rrlimm; 2820b57cec5SDimitry Andric if (isUInt<6>(MoveAmount)) 2830b57cec5SDimitry Andric Opc = ARC::ADD_rru6; 2840b57cec5SDimitry Andric else if (isInt<12>(MoveAmount)) 2850b57cec5SDimitry Andric Opc = ARC::ADD_rrs12; 2860b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP) 2870b57cec5SDimitry Andric .addReg(ARC::SP) 2880b57cec5SDimitry Andric .addImm(StackSize - AmountAboveFunclet); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric if (StackSlotsUsedByFunclet) { 2920b57cec5SDimitry Andric // This part of the adjustment will always be < 64 bytes. 2930b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL)) 2940b57cec5SDimitry Andric .addExternalSymbol(load_funclet_name[Last - ARC::R15]) 2950b57cec5SDimitry Andric .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); 2960b57cec5SDimitry Andric unsigned Opc = ARC::ADD_rrlimm; 2970b57cec5SDimitry Andric if (isUInt<6>(4 * StackSlotsUsedByFunclet)) 2980b57cec5SDimitry Andric Opc = ARC::ADD_rru6; 2990b57cec5SDimitry Andric else if (isInt<12>(4 * StackSlotsUsedByFunclet)) 3000b57cec5SDimitry Andric Opc = ARC::ADD_rrs12; 3010b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP) 3020b57cec5SDimitry Andric .addReg(ARC::SP) 3030b57cec5SDimitry Andric .addImm(4 * (StackSlotsUsedByFunclet)); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric // Now, pop blink if necessary. 3060b57cec5SDimitry Andric if (SavedBlink) { 3070b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK)); 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric // Now, pop fp if necessary. 3100b57cec5SDimitry Andric if (hasFP(MF)) { 3110b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9)) 3120b57cec5SDimitry Andric .addReg(ARC::FP, RegState::Define) 3130b57cec5SDimitry Andric .addReg(ARC::SP, RegState::Define) 3140b57cec5SDimitry Andric .addReg(ARC::SP) 3150b57cec5SDimitry Andric .addImm(4); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Relieve the varargs area if necessary. 3190b57cec5SDimitry Andric if (MF.getFunction().isVarArg()) { 3200b57cec5SDimitry Andric // Add in the varargs area here first. 3210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Varargs\n"); 3220b57cec5SDimitry Andric unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); 3230b57cec5SDimitry Andric unsigned Opc = ARC::ADD_rrlimm; 3240b57cec5SDimitry Andric if (isUInt<6>(VarArgsBytes)) 3250b57cec5SDimitry Andric Opc = ARC::ADD_rru6; 3260b57cec5SDimitry Andric else if (isInt<12>(VarArgsBytes)) 3270b57cec5SDimitry Andric Opc = ARC::ADD_rrs12; 3280b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc)) 3290b57cec5SDimitry Andric .addReg(ARC::SP) 3300b57cec5SDimitry Andric .addReg(ARC::SP) 3310b57cec5SDimitry Andric .addImm(VarArgsBytes); 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric static std::vector<CalleeSavedInfo>::iterator 3360b57cec5SDimitry Andric getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) { 3370b57cec5SDimitry Andric for (auto I = V.begin(), E = V.end(); I != E; ++I) { 3380b57cec5SDimitry Andric if (reg == I->getReg()) 3390b57cec5SDimitry Andric return I; 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric return V.end(); 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric bool ARCFrameLowering::assignCalleeSavedSpillSlots( 3450b57cec5SDimitry Andric MachineFunction &MF, const TargetRegisterInfo *TRI, 3460b57cec5SDimitry Andric std::vector<CalleeSavedInfo> &CSI) const { 3470b57cec5SDimitry Andric // Use this opportunity to assign the spill slots for all of the potential 3480b57cec5SDimitry Andric // callee save registers (blink, fp, r13->r25) that we care about the 3490b57cec5SDimitry Andric // placement for. We can calculate all of that data here. 3500b57cec5SDimitry Andric int CurOffset = -4; 3510b57cec5SDimitry Andric unsigned Last = determineLastCalleeSave(CSI); 3520b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 3530b57cec5SDimitry Andric if (hasFP(MF)) { 3540b57cec5SDimitry Andric // Create a fixed slot at for FP 3550b57cec5SDimitry Andric int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true); 3560b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at " 3570b57cec5SDimitry Andric << CurOffset << "\n"); 3580b57cec5SDimitry Andric (void)StackObj; 3590b57cec5SDimitry Andric CurOffset -= 4; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) { 3620b57cec5SDimitry Andric // Create a fixed slot for BLINK. 3630b57cec5SDimitry Andric int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true); 3640b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj 3650b57cec5SDimitry Andric << ") for BLINK at " << CurOffset << "\n"); 3660b57cec5SDimitry Andric (void)StackObj; 3670b57cec5SDimitry Andric CurOffset -= 4; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Create slots for last down to r13. 3710b57cec5SDimitry Andric for (unsigned Which = Last; Which > ARC::R12; Which--) { 3720b57cec5SDimitry Andric auto RegI = getSavedReg(CSI, Which); 3730b57cec5SDimitry Andric if (RegI == CSI.end() || RegI->getFrameIdx() == 0) { 3740b57cec5SDimitry Andric // Always create the stack slot. If for some reason the register isn't in 3750b57cec5SDimitry Andric // the save list, then don't worry about it. 3760b57cec5SDimitry Andric int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true); 3770b57cec5SDimitry Andric if (RegI != CSI.end()) 3780b57cec5SDimitry Andric RegI->setFrameIdx(FI); 3790b57cec5SDimitry Andric } else 3800b57cec5SDimitry Andric MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset); 3810b57cec5SDimitry Andric CurOffset -= 4; 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric for (auto &I : CSI) { 3840b57cec5SDimitry Andric if (I.getReg() > ARC::R12) 3850b57cec5SDimitry Andric continue; 3860b57cec5SDimitry Andric if (I.getFrameIdx() == 0) { 3870b57cec5SDimitry Andric I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true)); 3880b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx() 3890b57cec5SDimitry Andric << ") for other register at " << CurOffset << "\n"); 3900b57cec5SDimitry Andric } else { 3910b57cec5SDimitry Andric MFI.setObjectOffset(I.getFrameIdx(), CurOffset); 3920b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx() 3930b57cec5SDimitry Andric << ") for other register at " << CurOffset << "\n"); 3940b57cec5SDimitry Andric } 3950b57cec5SDimitry Andric CurOffset -= 4; 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric return true; 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric bool ARCFrameLowering::spillCalleeSavedRegisters( 4010b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 4025ffd83dbSDimitry Andric ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 4030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Spill callee saved registers: " 4040b57cec5SDimitry Andric << MBB.getParent()->getName() << "\n"); 4050b57cec5SDimitry Andric // There are routines for saving at least 3 registers (r13 to r15, etc.) 4060b57cec5SDimitry Andric unsigned Last = determineLastCalleeSave(CSI); 4070b57cec5SDimitry Andric if (UseSaveRestoreFunclet && Last > ARC::R14) { 4080b57cec5SDimitry Andric // Use setObjectOffset for these registers. 4090b57cec5SDimitry Andric // Needs to be in or before processFunctionBeforeFrameFinalized. 4100b57cec5SDimitry Andric // Or, do assignCalleeSaveSpillSlots? 4110b57cec5SDimitry Andric // Will be handled in prolog. 4120b57cec5SDimitry Andric return true; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric return false; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric bool ARCFrameLowering::restoreCalleeSavedRegisters( 4180b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, 4195ffd83dbSDimitry Andric MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { 4200b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Restore callee saved registers: " 4210b57cec5SDimitry Andric << MBB.getParent()->getName() << "\n"); 4220b57cec5SDimitry Andric // There are routines for saving at least 3 registers (r13 to r15, etc.) 4230b57cec5SDimitry Andric unsigned Last = determineLastCalleeSave(CSI); 4240b57cec5SDimitry Andric if (UseSaveRestoreFunclet && Last > ARC::R14) { 4250b57cec5SDimitry Andric // Will be handled in epilog. 4260b57cec5SDimitry Andric return true; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric return false; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric // Adjust local variables that are 4-bytes or larger to 4-byte boundary 4320b57cec5SDimitry Andric void ARCFrameLowering::processFunctionBeforeFrameFinalized( 4330b57cec5SDimitry Andric MachineFunction &MF, RegScavenger *RS) const { 4340b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 4350b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Process function before frame finalized: " 4360b57cec5SDimitry Andric << MF.getName() << "\n"); 4370b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 4380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n"); 4390b57cec5SDimitry Andric const TargetRegisterClass *RC = &ARC::GPR32RegClass; 4400b57cec5SDimitry Andric if (MFI.hasStackObjects()) { 4415ffd83dbSDimitry Andric int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC), 4425ffd83dbSDimitry Andric RegInfo->getSpillAlign(*RC), false); 4430b57cec5SDimitry Andric RS->addScavengingFrameIndex(RegScavFI); 4440b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI 4450b57cec5SDimitry Andric << "\n"); 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric static void emitRegUpdate(MachineBasicBlock &MBB, 4500b57cec5SDimitry Andric MachineBasicBlock::iterator &MBBI, DebugLoc dl, 4510b57cec5SDimitry Andric unsigned Reg, int NumBytes, bool IsAdd, 4520b57cec5SDimitry Andric const ARCInstrInfo *TII) { 4530b57cec5SDimitry Andric unsigned Opc; 4540b57cec5SDimitry Andric if (isUInt<6>(NumBytes)) 4550b57cec5SDimitry Andric Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6; 4560b57cec5SDimitry Andric else if (isInt<12>(NumBytes)) 4570b57cec5SDimitry Andric Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12; 4580b57cec5SDimitry Andric else 4590b57cec5SDimitry Andric Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm; 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg) 4620b57cec5SDimitry Andric .addReg(Reg, RegState::Kill) 4630b57cec5SDimitry Andric .addImm(NumBytes); 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr( 4670b57cec5SDimitry Andric MachineFunction &MF, MachineBasicBlock &MBB, 4680b57cec5SDimitry Andric MachineBasicBlock::iterator I) const { 4690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n"); 4700b57cec5SDimitry Andric const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); 4710b57cec5SDimitry Andric MachineInstr &Old = *I; 4720b57cec5SDimitry Andric DebugLoc dl = Old.getDebugLoc(); 4730b57cec5SDimitry Andric unsigned Amt = Old.getOperand(0).getImm(); 4740b57cec5SDimitry Andric auto *AFI = MF.getInfo<ARCFunctionInfo>(); 4750b57cec5SDimitry Andric if (!hasFP(MF)) { 4760b57cec5SDimitry Andric if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN) 4770b57cec5SDimitry Andric AFI->MaxCallStackReq = Amt; 4780b57cec5SDimitry Andric } else { 4790b57cec5SDimitry Andric if (Amt != 0) { 4800b57cec5SDimitry Andric assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN || 4810b57cec5SDimitry Andric Old.getOpcode() == ARC::ADJCALLSTACKUP) && 4820b57cec5SDimitry Andric "Unknown Frame Pseudo."); 4830b57cec5SDimitry Andric bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP); 4840b57cec5SDimitry Andric emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric return MBB.erase(I); 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric bool ARCFrameLowering::hasFP(const MachineFunction &MF) const { 4910b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 4920b57cec5SDimitry Andric bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) || 4930b57cec5SDimitry Andric MF.getFrameInfo().hasVarSizedObjects() || 4940b57cec5SDimitry Andric MF.getFrameInfo().isFrameAddressTaken() || 495fe6060f1SDimitry Andric RegInfo->hasStackRealignment(MF); 4960b57cec5SDimitry Andric return HasFP; 4970b57cec5SDimitry Andric } 498