1//===-- XCoreFrameLowering.cpp - Frame info for XCore Target --------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file contains XCore frame information that doesn't fit anywhere else 11// cleanly... 12// 13//===----------------------------------------------------------------------===// 14 15#include "XCoreFrameLowering.h" 16#include "XCore.h" 17#include "XCoreInstrInfo.h" 18#include "XCoreMachineFunctionInfo.h" 19#include "llvm/CodeGen/MachineFrameInfo.h" 20#include "llvm/CodeGen/MachineFunction.h" 21#include "llvm/CodeGen/MachineInstrBuilder.h" 22#include "llvm/CodeGen/MachineModuleInfo.h" 23#include "llvm/CodeGen/MachineRegisterInfo.h" 24#include "llvm/CodeGen/RegisterScavenging.h" 25#include "llvm/IR/DataLayout.h" 26#include "llvm/IR/Function.h" 27#include "llvm/Support/ErrorHandling.h" 28#include "llvm/Target/TargetOptions.h" 29 30using namespace llvm; 31 32// helper functions. FIXME: Eliminate. 33static inline bool isImmUs(unsigned val) { 34 return val <= 11; 35} 36 37static inline bool isImmU6(unsigned val) { 38 return val < (1 << 6); 39} 40 41static inline bool isImmU16(unsigned val) { 42 return val < (1 << 16); 43} 44 45static void loadFromStack(MachineBasicBlock &MBB, 46 MachineBasicBlock::iterator I, 47 unsigned DstReg, int Offset, DebugLoc dl, 48 const TargetInstrInfo &TII) { 49 assert(Offset%4 == 0 && "Misaligned stack offset"); 50 Offset/=4; 51 bool isU6 = isImmU6(Offset); 52 if (!isU6 && !isImmU16(Offset)) 53 report_fatal_error("loadFromStack offset too big " + Twine(Offset)); 54 int Opcode = isU6 ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; 55 BuildMI(MBB, I, dl, TII.get(Opcode), DstReg) 56 .addImm(Offset); 57} 58 59 60static void storeToStack(MachineBasicBlock &MBB, 61 MachineBasicBlock::iterator I, 62 unsigned SrcReg, int Offset, DebugLoc dl, 63 const TargetInstrInfo &TII) { 64 assert(Offset%4 == 0 && "Misaligned stack offset"); 65 Offset/=4; 66 bool isU6 = isImmU6(Offset); 67 if (!isU6 && !isImmU16(Offset)) 68 report_fatal_error("storeToStack offset too big " + Twine(Offset)); 69 int Opcode = isU6 ? XCore::STWSP_ru6 : XCore::STWSP_lru6; 70 BuildMI(MBB, I, dl, TII.get(Opcode)) 71 .addReg(SrcReg) 72 .addImm(Offset); 73} 74 75 76//===----------------------------------------------------------------------===// 77// XCoreFrameLowering: 78//===----------------------------------------------------------------------===// 79 80XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti) 81 : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0) { 82 // Do nothing 83} 84 85bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const { 86 return MF.getTarget().Options.DisableFramePointerElim(MF) || 87 MF.getFrameInfo()->hasVarSizedObjects(); 88} 89 90void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { 91 MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB 92 MachineBasicBlock::iterator MBBI = MBB.begin(); 93 MachineFrameInfo *MFI = MF.getFrameInfo(); 94 MachineModuleInfo *MMI = &MF.getMMI(); 95 const XCoreInstrInfo &TII = 96 *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); 97 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); 98 DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 99 100 bool FP = hasFP(MF); 101 const AttributeSet &PAL = MF.getFunction()->getAttributes(); 102 103 if (PAL.hasAttrSomewhere(Attribute::Nest)) 104 loadFromStack(MBB, MBBI, XCore::R11, 0, dl, TII); 105 106 // Work out frame sizes. 107 int FrameSize = MFI->getStackSize(); 108 assert(FrameSize%4 == 0 && "Misaligned frame size"); 109 FrameSize/=4; 110 111 bool isU6 = isImmU6(FrameSize); 112 113 if (!isU6 && !isImmU16(FrameSize)) { 114 // FIXME could emit multiple instructions. 115 report_fatal_error("emitPrologue Frame size too big: " + Twine(FrameSize)); 116 } 117 bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(MF); 118 119 bool saveLR = XFI->getUsesLR(); 120 // Do we need to allocate space on the stack? 121 if (FrameSize) { 122 int Opcode; 123 if (saveLR && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0)) { 124 Opcode = (isU6) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6; 125 MBB.addLiveIn(XCore::LR); 126 saveLR = false; 127 } else { 128 Opcode = (isU6) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; 129 } 130 BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize); 131 132 if (emitFrameMoves) { 133 134 // Show update of SP. 135 MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); 136 BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); 137 } 138 } 139 if (saveLR) { 140 int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot()); 141 storeToStack(MBB, MBBI, XCore::LR, LRSpillOffset + FrameSize*4, dl, TII); 142 MBB.addLiveIn(XCore::LR); 143 144 if (emitFrameMoves) { 145 MCSymbol *SaveLRLabel = MMI->getContext().CreateTempSymbol(); 146 BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLRLabel); 147 } 148 } 149 150 if (FP) { 151 // Save R10 to the stack. 152 int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot()); 153 storeToStack(MBB, MBBI, XCore::R10, FPSpillOffset + FrameSize*4, dl, TII); 154 // R10 is live-in. It is killed at the spill. 155 MBB.addLiveIn(XCore::R10); 156 if (emitFrameMoves) { 157 MCSymbol *SaveR10Label = MMI->getContext().CreateTempSymbol(); 158 BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveR10Label); 159 } 160 // Set the FP from the SP. 161 unsigned FramePtr = XCore::R10; 162 BuildMI(MBB, MBBI, dl, TII.get(XCore::LDAWSP_ru6), FramePtr) 163 .addImm(0); 164 if (emitFrameMoves) { 165 // Show FP is now valid. 166 MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); 167 BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); 168 } 169 } 170} 171 172void XCoreFrameLowering::emitEpilogue(MachineFunction &MF, 173 MachineBasicBlock &MBB) const { 174 MachineFrameInfo *MFI = MF.getFrameInfo(); 175 MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 176 const XCoreInstrInfo &TII = 177 *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); 178 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); 179 DebugLoc dl = MBBI->getDebugLoc(); 180 181 bool FP = hasFP(MF); 182 if (FP) { 183 // Restore the stack pointer. 184 unsigned FramePtr = XCore::R10; 185 BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)) 186 .addReg(FramePtr); 187 } 188 189 // Work out frame sizes. 190 int FrameSize = MFI->getStackSize(); 191 192 assert(FrameSize%4 == 0 && "Misaligned frame size"); 193 194 FrameSize/=4; 195 196 bool isU6 = isImmU6(FrameSize); 197 198 if (!isU6 && !isImmU16(FrameSize)) { 199 // FIXME could emit multiple instructions. 200 report_fatal_error("emitEpilogue Frame size too big: " + Twine(FrameSize)); 201 } 202 203 if (FP) { 204 // Restore R10 205 int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot()); 206 FPSpillOffset += FrameSize*4; 207 loadFromStack(MBB, MBBI, XCore::R10, FPSpillOffset, dl, TII); 208 } 209 210 bool restoreLR = XFI->getUsesLR(); 211 if (restoreLR && 212 (FrameSize == 0 || MFI->getObjectOffset(XFI->getLRSpillSlot()) != 0)) { 213 int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot()); 214 LRSpillOffset += FrameSize*4; 215 loadFromStack(MBB, MBBI, XCore::LR, LRSpillOffset, dl, TII); 216 restoreLR = false; 217 } 218 219 if (FrameSize) { 220 if (restoreLR) { 221 // Fold prologue into return instruction 222 assert(MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0); 223 assert(MBBI->getOpcode() == XCore::RETSP_u6 224 || MBBI->getOpcode() == XCore::RETSP_lu6); 225 int Opcode = (isU6) ? XCore::RETSP_u6 : XCore::RETSP_lu6; 226 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize); 227 for (unsigned i = 3, e = MBBI->getNumOperands(); i < e; ++i) 228 MIB->addOperand(MBBI->getOperand(i)); // copy any variadic operands 229 MBB.erase(MBBI); 230 } else { 231 int Opcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; 232 BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(FrameSize); 233 } 234 } 235} 236 237bool XCoreFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, 238 MachineBasicBlock::iterator MI, 239 const std::vector<CalleeSavedInfo> &CSI, 240 const TargetRegisterInfo *TRI) const { 241 if (CSI.empty()) 242 return true; 243 244 MachineFunction *MF = MBB.getParent(); 245 const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); 246 247 XCoreFunctionInfo *XFI = MF->getInfo<XCoreFunctionInfo>(); 248 bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(*MF); 249 250 DebugLoc DL; 251 if (MI != MBB.end()) DL = MI->getDebugLoc(); 252 253 for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin(); 254 it != CSI.end(); ++it) { 255 // Add the callee-saved register as live-in. It's killed at the spill. 256 MBB.addLiveIn(it->getReg()); 257 258 unsigned Reg = it->getReg(); 259 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 260 TII.storeRegToStackSlot(MBB, MI, Reg, true, 261 it->getFrameIdx(), RC, TRI); 262 if (emitFrameMoves) { 263 MCSymbol *SaveLabel = MF->getContext().CreateTempSymbol(); 264 BuildMI(MBB, MI, DL, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLabel); 265 XFI->getSpillLabels().push_back(std::make_pair(SaveLabel, *it)); 266 } 267 } 268 return true; 269} 270 271bool XCoreFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, 272 MachineBasicBlock::iterator MI, 273 const std::vector<CalleeSavedInfo> &CSI, 274 const TargetRegisterInfo *TRI) const{ 275 MachineFunction *MF = MBB.getParent(); 276 const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); 277 278 bool AtStart = MI == MBB.begin(); 279 MachineBasicBlock::iterator BeforeI = MI; 280 if (!AtStart) 281 --BeforeI; 282 for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin(); 283 it != CSI.end(); ++it) { 284 unsigned Reg = it->getReg(); 285 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); 286 TII.loadRegFromStackSlot(MBB, MI, it->getReg(), it->getFrameIdx(), 287 RC, TRI); 288 assert(MI != MBB.begin() && 289 "loadRegFromStackSlot didn't insert any code!"); 290 // Insert in reverse order. loadRegFromStackSlot can insert multiple 291 // instructions. 292 if (AtStart) 293 MI = MBB.begin(); 294 else { 295 MI = BeforeI; 296 ++MI; 297 } 298 } 299 return true; 300} 301 302// This function eliminates ADJCALLSTACKDOWN, 303// ADJCALLSTACKUP pseudo instructions 304void XCoreFrameLowering:: 305eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, 306 MachineBasicBlock::iterator I) const { 307 const XCoreInstrInfo &TII = 308 *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); 309 if (!hasReservedCallFrame(MF)) { 310 // Turn the adjcallstackdown instruction into 'extsp <amt>' and the 311 // adjcallstackup instruction into 'ldaw sp, sp[<amt>]' 312 MachineInstr *Old = I; 313 uint64_t Amount = Old->getOperand(0).getImm(); 314 if (Amount != 0) { 315 // We need to keep the stack aligned properly. To do this, we round the 316 // amount of space needed for the outgoing arguments up to the next 317 // alignment boundary. 318 unsigned Align = getStackAlignment(); 319 Amount = (Amount+Align-1)/Align*Align; 320 321 assert(Amount%4 == 0); 322 Amount /= 4; 323 324 bool isU6 = isImmU6(Amount); 325 if (!isU6 && !isImmU16(Amount)) { 326 // FIX could emit multiple instructions in this case. 327#ifndef NDEBUG 328 errs() << "eliminateCallFramePseudoInstr size too big: " 329 << Amount << "\n"; 330#endif 331 llvm_unreachable(0); 332 } 333 334 MachineInstr *New; 335 if (Old->getOpcode() == XCore::ADJCALLSTACKDOWN) { 336 int Opcode = isU6 ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; 337 New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode)) 338 .addImm(Amount); 339 } else { 340 assert(Old->getOpcode() == XCore::ADJCALLSTACKUP); 341 int Opcode = isU6 ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; 342 New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode), XCore::SP) 343 .addImm(Amount); 344 } 345 346 // Replace the pseudo instruction with a new instruction... 347 MBB.insert(I, New); 348 } 349 } 350 351 MBB.erase(I); 352} 353 354void 355XCoreFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, 356 RegScavenger *RS) const { 357 MachineFrameInfo *MFI = MF.getFrameInfo(); 358 const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); 359 bool LRUsed = MF.getRegInfo().isPhysRegUsed(XCore::LR); 360 const TargetRegisterClass *RC = &XCore::GRRegsRegClass; 361 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); 362 if (LRUsed) { 363 MF.getRegInfo().setPhysRegUnused(XCore::LR); 364 365 bool isVarArg = MF.getFunction()->isVarArg(); 366 int FrameIdx; 367 if (! isVarArg) { 368 // A fixed offset of 0 allows us to save / restore LR using entsp / retsp. 369 FrameIdx = MFI->CreateFixedObject(RC->getSize(), 0, true); 370 } else { 371 FrameIdx = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), 372 false); 373 } 374 XFI->setUsesLR(FrameIdx); 375 XFI->setLRSpillSlot(FrameIdx); 376 } 377 if (RegInfo->requiresRegisterScavenging(MF)) { 378 // Reserve a slot close to SP or frame pointer. 379 RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), 380 RC->getAlignment(), 381 false)); 382 } 383 if (hasFP(MF)) { 384 // A callee save register is used to hold the FP. 385 // This needs saving / restoring in the epilogue / prologue. 386 XFI->setFPSpillSlot(MFI->CreateStackObject(RC->getSize(), 387 RC->getAlignment(), 388 false)); 389 } 390} 391