/*******************************************************\
* Copyright (C) 2006, ApS s.r.o Brno, AllRightsReserved *
\*******************************************************/

#include "CodasipGenFrameLowering.h"
#include "CodasipInstrInfo.h"
#include "CodasipMachineFunction.h"
#include "CodasipTargetMachine.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/ADT/Twine.h"

using namespace llvm;

CodasipGenFrameLowering::CodasipGenFrameLowering(const CodasipTargetMachine &tm)
: TargetFrameLowering(StackGrowsDown,4,0), TII(*tm.getInstrInfo()) {}

bool CodasipGenFrameLowering::hasFP(const MachineFunction &MF) const
{
  // note: this is used by hasReservedCallFrame as well
  return MF.getFrameInfo()->hasVarSizedObjects();
}

void CodasipGenFrameLowering::emitPrologue(MachineFunction &MF) const
{
  MachineBasicBlock &MB = MF.front();
  MachineBasicBlock::iterator II = MB.begin();
  DebugLoc dl;
  if (II != MB.end()) dl = II->getDebugLoc();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  int Offset = MFI->getStackSize();
  // todo: make more efficient
  // save RAR (maybe simply ra as well later?)
  BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(-4);
  BuildMI(MB,II,dl, TII.get(Codasip::i_load_store__opc_store__rmem__rmem__simm16____SPEC_op0_0)).addReg(Codasip::gpregs_7).addReg(Codasip::gpregs_0);
  // save base index
  BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(-4);
  BuildMI(MB,II,dl, TII.get(Codasip::i_load_store__opc_store__rmem__rmem__simm16____SPEC_op0_0)).addReg(Codasip::gpregs_1).addReg(Codasip::gpregs_0);
  // set a new one
  BuildMI(MB,II,dl, TII.get(Codasip::i_2_reg_ops__opc_mov__rmem__rmem__), Codasip::gpregs_1).addReg(Codasip::gpregs_0);
  // allocate space?
  if (Offset)
  {
    if ((Offset&4294934528)!=4294934528 && (Offset&4294934528)!=0)
    {
      for (;Offset>0; Offset-=32767) {
        int off = (Offset>32767? 32767: Offset);
        BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(-off);
      }
    }
    else
    {
      BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(-Offset);
    }
  }
  // backup argument registers?
  if (MF.getFunction()->isVarArg())
  {
    CodasipFunctionInfo *finfo = MF.getInfo<CodasipFunctionInfo>();
    unsigned off;
    static const unsigned gpregs_args[] = {
      Codasip::gpregs_2, Codasip::gpregs_3, Codasip::gpregs_4, Codasip::gpregs_5, Codasip::gpregs_6, 
    };
    off = 5-finfo->ArgsInfo.Count_gpregs;
    for (int i=0; i<finfo->ArgsInfo.Count_gpregs; ++i) {
      BuildMI(MB,II,dl, TII.get(Codasip::i_load_store__opc_store__rmem__rmem__simm16__)).addReg(gpregs_args[i+off]).addFrameIndex(finfo->ArgsInfo.FI_gpregs).addImm(i*4);
    }
  }
}

void CodasipGenFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MB) const
{
  MachineBasicBlock::iterator II = prior(MB.end());
  DebugLoc dl = II->getDebugLoc();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  int Offset = MFI->getStackSize();
  // deallocate space?
  if ((Offset&4294934528)!=4294934528 && (Offset&4294934528)!=0)
  {
    for (;Offset>0; Offset-=32767) {
      int off = (Offset>32767? 32767: Offset);
      BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(off);
    }
  }
  else
  {
    BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(Offset);
  }
  // restore base index
  BuildMI(MB,II,dl, TII.get(Codasip::i_load_store__opc_load__rmem__rmem__simm16____SPEC_op0_0), Codasip::gpregs_1).addReg(Codasip::gpregs_0);
  BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(4);
  // restore RAR
  BuildMI(MB,II,dl, TII.get(Codasip::i_load_store__opc_load__rmem__rmem__simm16____SPEC_op0_0), Codasip::gpregs_7).addReg(Codasip::gpregs_0);
  BuildMI(MB,II,dl, TII.get(Codasip::i_arithm_imm__opc_addi__rmem__rmem__uimm16__), Codasip::gpregs_0).addReg(Codasip::gpregs_0).addImm(4);
}

