//==- AArch64FrameLowering.h - Define frame lowering for AArch64 -*- C++ -*--=//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements the AArch64-specific parts of the TargetFrameLowering
// class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_AARCH64_FRAMEINFO_H
#define LLVM_AARCH64_FRAMEINFO_H

#include "AArch64Subtarget.h"
#include "llvm/Target/TargetFrameLowering.h"

namespace llvm {
class AArch64Subtarget;

class AArch64FrameLowering : public TargetFrameLowering {
private:
  // In order to unify the spilling and restoring of callee-saved registers into
  // emitFrameMemOps, we need to be able to specify which instructions to use
  // for the relevant memory operations on each register class. An array of the
  // following struct is populated and passed in to achieve this.
  struct LoadStoreMethod {
    const TargetRegisterClass *RegClass; // E.g. GPR64RegClass

    // The preferred instruction.
    unsigned PairOpcode; // E.g. LSPair64_STR

    // Sometimes only a single register can be handled at once.
    unsigned SingleOpcode; // E.g. LS64_STR
  };
protected:
  const AArch64Subtarget &STI;

public:
  explicit AArch64FrameLowering(const AArch64Subtarget &sti)
    : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 16, 0, 16),
      STI(sti) {
  }

  /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
  /// the function.
  virtual void emitPrologue(MachineFunction &MF) const;
  virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;

  /// Decides how much stack adjustment to perform in each phase of the prologue
  /// and epilogue.
  void splitSPAdjustments(uint64_t Total, uint64_t &Initial,
                          uint64_t &Residual) const;

  int64_t resolveFrameIndexReference(MachineFunction &MF, int FrameIndex,
                                     unsigned &FrameReg, int SPAdj,
                                     bool IsCalleeSaveOp) const;

  virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
                                                    RegScavenger *RS) const;

  virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator MI,
                                        const std::vector<CalleeSavedInfo> &CSI,
                                        const TargetRegisterInfo *TRI) const;
  virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
                                        MachineBasicBlock::iterator MI,
                                        const std::vector<CalleeSavedInfo> &CSI,
                                        const TargetRegisterInfo *TRI) const;

  void eliminateCallFramePseudoInstr(MachineFunction &MF,
                                     MachineBasicBlock &MBB,
                                     MachineBasicBlock::iterator MI) const;

  /// If the register is X30 (i.e. LR) and the return address is used in the
  /// function then the callee-save store doesn't actually kill the register,
  /// otherwise it does.
  bool determinePrologueDeath(MachineBasicBlock &MBB, unsigned Reg) const;

  /// This function emits the loads or stores required during prologue and
  /// epilogue as efficiently as possible.
  ///
  /// The operations involved in setting up and tearing down the frame are
  /// similar enough to warrant a shared function, particularly as discrepancies
  /// between the two would be disastrous.
  void emitFrameMemOps(bool isStore, MachineBasicBlock &MBB,
                       MachineBasicBlock::iterator MI,
                       const std::vector<CalleeSavedInfo> &CSI,
                       const TargetRegisterInfo *TRI,
                       LoadStoreMethod PossibleClasses[],
                       unsigned NumClasses) const;


  virtual bool hasFP(const MachineFunction &MF) const;

  virtual bool useFPForAddressing(const MachineFunction &MF) const;

  /// On AA
  virtual bool hasReservedCallFrame(const MachineFunction &MF) const;

};

} // End llvm namespace

#endif
