1//===- TargetFrameLoweringImpl.cpp - Implement target frame interface ------==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Implements the layout of a stack frame on the target machine.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ADT/BitVector.h"
14#include "llvm/CodeGen/MachineFrameInfo.h"
15#include "llvm/CodeGen/MachineFunction.h"
16#include "llvm/CodeGen/MachineRegisterInfo.h"
17#include "llvm/CodeGen/TargetFrameLowering.h"
18#include "llvm/CodeGen/TargetRegisterInfo.h"
19#include "llvm/CodeGen/TargetSubtargetInfo.h"
20#include "llvm/IR/Attributes.h"
21#include "llvm/IR/CallSite.h"
22#include "llvm/IR/CallingConv.h"
23#include "llvm/IR/Function.h"
24#include "llvm/MC/MCRegisterInfo.h"
25#include "llvm/Support/Compiler.h"
26#include "llvm/Target/TargetMachine.h"
27#include "llvm/Target/TargetOptions.h"
28
29using namespace llvm;
30
31TargetFrameLowering::~TargetFrameLowering() = default;
32
33bool TargetFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const {
34  assert(MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
35         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
36         !MF.getFunction().hasFnAttribute(Attribute::UWTable));
37  return false;
38}
39
40/// Returns the displacement from the frame register to the stack
41/// frame of the specified index, along with the frame register used
42/// (in output arg FrameReg). This is the default implementation which
43/// is overridden for some targets.
44int TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF,
45                                             int FI, unsigned &FrameReg) const {
46  const MachineFrameInfo &MFI = MF.getFrameInfo();
47  const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
48
49  // By default, assume all frame indices are referenced via whatever
50  // getFrameRegister() says. The target can override this if it's doing
51  // something different.
52  FrameReg = RI->getFrameRegister(MF);
53
54  return MFI.getObjectOffset(FI) + MFI.getStackSize() -
55         getOffsetOfLocalArea() + MFI.getOffsetAdjustment();
56}
57
58bool TargetFrameLowering::needsFrameIndexResolution(
59    const MachineFunction &MF) const {
60  return MF.getFrameInfo().hasStackObjects();
61}
62
63void TargetFrameLowering::getCalleeSaves(const MachineFunction &MF,
64                                         BitVector &CalleeSaves) const {
65  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
66  CalleeSaves.resize(TRI.getNumRegs());
67
68  const MachineFrameInfo &MFI = MF.getFrameInfo();
69  if (!MFI.isCalleeSavedInfoValid())
70    return;
71
72  for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo())
73    CalleeSaves.set(Info.getReg());
74}
75
76void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
77                                               BitVector &SavedRegs,
78                                               RegScavenger *RS) const {
79  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
80
81  // Resize before the early returns. Some backends expect that
82  // SavedRegs.size() == TRI.getNumRegs() after this call even if there are no
83  // saved registers.
84  SavedRegs.resize(TRI.getNumRegs());
85
86  // When interprocedural register allocation is enabled caller saved registers
87  // are preferred over callee saved registers.
88  if (MF.getTarget().Options.EnableIPRA &&
89      isSafeForNoCSROpt(MF.getFunction()) &&
90      isProfitableForNoCSROpt(MF.getFunction()))
91    return;
92
93  // Get the callee saved register list...
94  const MCPhysReg *CSRegs = MF.getRegInfo().getCalleeSavedRegs();
95
96  // Early exit if there are no callee saved registers.
97  if (!CSRegs || CSRegs[0] == 0)
98    return;
99
100  // In Naked functions we aren't going to save any registers.
101  if (MF.getFunction().hasFnAttribute(Attribute::Naked))
102    return;
103
104  // Noreturn+nounwind functions never restore CSR, so no saves are needed.
105  // Purely noreturn functions may still return through throws, so those must
106  // save CSR for caller exception handlers.
107  //
108  // If the function uses longjmp to break out of its current path of
109  // execution we do not need the CSR spills either: setjmp stores all CSRs
110  // it was called with into the jmp_buf, which longjmp then restores.
111  if (MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
112        MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
113        !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
114        enableCalleeSaveSkip(MF))
115    return;
116
117  // Functions which call __builtin_unwind_init get all their registers saved.
118  bool CallsUnwindInit = MF.callsUnwindInit();
119  const MachineRegisterInfo &MRI = MF.getRegInfo();
120  for (unsigned i = 0; CSRegs[i]; ++i) {
121    unsigned Reg = CSRegs[i];
122    if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
123      SavedRegs.set(Reg);
124  }
125}
126
127unsigned TargetFrameLowering::getStackAlignmentSkew(
128    const MachineFunction &MF) const {
129  // When HHVM function is called, the stack is skewed as the return address
130  // is removed from the stack before we enter the function.
131  if (LLVM_UNLIKELY(MF.getFunction().getCallingConv() == CallingConv::HHVM))
132    return MF.getTarget().getAllocaPointerSize();
133
134  return 0;
135}
136
137bool TargetFrameLowering::isSafeForNoCSROpt(const Function &F) {
138  if (!F.hasLocalLinkage() || F.hasAddressTaken() ||
139      !F.hasFnAttribute(Attribute::NoRecurse))
140    return false;
141  // Function should not be optimized as tail call.
142  for (const User *U : F.users())
143    if (auto CS = ImmutableCallSite(U))
144      if (CS.isTailCall())
145        return false;
146  return true;
147}
148
149int TargetFrameLowering::getInitialCFAOffset(const MachineFunction &MF) const {
150  llvm_unreachable("getInitialCFAOffset() not implemented!");
151}
152
153unsigned TargetFrameLowering::getInitialCFARegister(const MachineFunction &MF)
154    const {
155  llvm_unreachable("getInitialCFARegister() not implemented!");
156}
157