Compiler projects using llvm
//===-- M68kFrameLowering.h - Define frame lowering for M68k ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the M68k declaration of TargetFrameLowering class.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_M68K_M68KFRAMELOWERING_H
#define LLVM_LIB_TARGET_M68K_M68KFRAMELOWERING_H

#include "M68k.h"

#include "llvm/CodeGen/TargetFrameLowering.h"

namespace llvm {
class MachineInstrBuilder;
class MCCFIInstruction;
class M68kSubtarget;
class M68kRegisterInfo;
struct Align;

class M68kFrameLowering : public TargetFrameLowering {
  // Cached subtarget predicates.
  const M68kSubtarget &STI;
  const TargetInstrInfo &TII;
  const M68kRegisterInfo *TRI;

  /// Stack slot size in bytes.
  unsigned SlotSize;

  unsigned StackPtr;

  /// If we're forcing a stack realignment we can't rely on just the frame
  /// info, we need to know the ABI stack alignment as well in case we have a
  /// call out.  Otherwise just make sure we have some alignment - we'll go
  /// with the minimum SlotSize.
  uint64_t calculateMaxStackAlign(const MachineFunction &MF) const;

  /// Adjusts the stack pointer using LEA, SUB, or ADD.
  MachineInstrBuilder BuildStackAdjustment(MachineBasicBlock &MBB,
                                           MachineBasicBlock::iterator MBBI,
                                           const DebugLoc &DL, int64_t Offset,
                                           bool InEpilogue) const;

  /// Aligns the stack pointer by ANDing it with -MaxAlign.
  void BuildStackAlignAND(MachineBasicBlock &MBB,
                          MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
                          unsigned Reg, uint64_t MaxAlign) const;

  /// Wraps up getting a CFI index and building a MachineInstr for it.
  void BuildCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
                const DebugLoc &DL, const MCCFIInstruction &CFIInst) const;

  void emitPrologueCalleeSavedFrameMoves(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MBBI,
                                         const DebugLoc &DL) const;

  unsigned getPSPSlotOffsetFromSP(const MachineFunction &MF) const;

public:
  explicit M68kFrameLowering(const M68kSubtarget &sti, Align Alignment);

  static const M68kFrameLowering *create(const M68kSubtarget &ST);

  /// This method is called during prolog/epilog code insertion to eliminate
  /// call frame setup and destroy pseudo instructions (but only if the Target
  /// is using them).  It is responsible for eliminating these instructions,
  /// replacing them with concrete instructions.  This method need only be
  /// implemented if using call frame setup/destroy pseudo instructions.
  /// Returns an iterator pointing to the instruction after the replaced one.
  MachineBasicBlock::iterator
  eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                MachineBasicBlock::iterator MI) const override;

  /// Insert prolog code into the function.
  void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;

  /// Insert epilog code into the function.
  void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;

  /// This method determines which of the registers reported by
  /// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
  /// The default implementation checks populates the \p SavedRegs bitset with
  /// all registers which are modified in the function, targets may override
  /// this function to save additional registers.
  /// This method also sets up the register scavenger ensuring there is a free
  /// register or a frameindex available.
  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                            RegScavenger *RS = nullptr) const override;

  /// Allows target to override spill slot assignment logic.  If implemented,
  /// assignCalleeSavedSpillSlots() should assign frame slots to all CSI
  /// entries and return true.  If this method returns false, spill slots will
  /// be assigned using generic implementation.  assignCalleeSavedSpillSlots()
  /// may add, delete or rearrange elements of CSI.
  bool
  assignCalleeSavedSpillSlots(MachineFunction &MF,
                              const TargetRegisterInfo *TRI,
                              std::vector<CalleeSavedInfo> &CSI) const override;

  /// Issues instruction(s) to spill all callee saved registers and returns
  /// true if it isn't possible / profitable to do so by issuing a series of
  /// store instructions via storeRegToStackSlot(). Returns false otherwise.
  bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI,
                                 ArrayRef<CalleeSavedInfo> CSI,
                                 const TargetRegisterInfo *TRI) const override;

  /// Issues instruction(s) to restore all callee saved registers and returns
  /// true if it isn't possible / profitable to do so by issuing a series of
  /// load instructions via loadRegToStackSlot().  Returns false otherwise.
  bool
  restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator MI,
                              MutableArrayRef<CalleeSavedInfo> CSI,
                              const TargetRegisterInfo *TRI) const override;

  /// Return true if the specified function should have a dedicated frame
  /// pointer register.  This is true if the function has variable sized
  /// allocas, if it needs dynamic stack realignment, if frame pointer
  /// elimination is disabled, or if the frame address is taken.
  bool hasFP(const MachineFunction &MF) const override;

  /// Under normal circumstances, when a frame pointer is not required, we
  /// reserve argument space for call sites in the function immediately on
  /// entry to the current function. This eliminates the need for add/sub sp
  /// brackets around call sites. Returns true if the call frame is included as
  /// part of the stack frame.
  bool hasReservedCallFrame(const MachineFunction &MF) const override;

  /// If there is a reserved call frame, the call frame pseudos can be
  /// simplified.  Having a FP, as in the default implementation, is not
  /// sufficient here since we can't always use it.  Use a more nuanced
  /// condition.
  bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;

  // Do we need to perform FI resolution for this function. Normally, this is
  // required only when the function has any stack objects. However, FI
  // resolution actually has another job, not apparent from the title - it
  // resolves callframe setup/destroy that were not simplified earlier.
  //
  // So, this is required for M68k functions that have push sequences even
  // when there are no stack objects.
  bool needsFrameIndexResolution(const MachineFunction &MF) const override;

  /// This method should return the base register and offset used to reference
  /// a frame index location. The offset is returned directly, and the base
  /// register is returned via FrameReg.
  StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                     Register &FrameReg) const override;

  /// Check the instruction before/after the passed instruction. If
  /// it is an ADD/SUB/LEA instruction it is deleted argument and the
  /// stack adjustment is returned as a positive value for ADD/LEA and
  /// a negative for SUB.
  int mergeSPUpdates(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
                     bool doMergeWithPrevious) const;

  /// Emit a series of instructions to increment / decrement the stack
  /// pointer by a constant value.
  void emitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
                    int64_t NumBytes, bool InEpilogue) const;
};
} // namespace llvm

#endif // LLVM_LIB_TARGET_M68K_M68KFRAMELOWERING_H