//===-- LiveRangeInfo.cpp -------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  Live range construction for coloring-based register allocation for LLVM.
//
//===----------------------------------------------------------------------===//

#include "IGNode.h"
#include "LiveRangeInfo.h"
#include "RegAllocCommon.h"
#include "RegClass.h"
#include "llvm/Function.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "../SparcV9RegInfo.h"
#include "llvm/ADT/SetOperations.h"
#include <iostream>

namespace llvm {

unsigned V9LiveRange::getRegClassID() const { return getRegClass()->getID(); }

LiveRangeInfo::LiveRangeInfo(const Function *F, const TargetMachine &tm,
                             std::vector<RegClass *> &RCL)
  : Meth(F), TM(tm), RegClassList(RCL), MRI(*tm.getRegInfo()) { }


LiveRangeInfo::~LiveRangeInfo() {
  for (LiveRangeMapType::iterator MI = LiveRangeMap.begin();
       MI != LiveRangeMap.end(); ++MI) {

    if (MI->first && MI->second) {
      V9LiveRange *LR = MI->second;

      // we need to be careful in deleting LiveRanges in LiveRangeMap
      // since two/more Values in the live range map can point to the same
      // live range. We have to make the other entries NULL when we delete
      // a live range.

      for (V9LiveRange::iterator LI = LR->begin(); LI != LR->end(); ++LI)
        LiveRangeMap[*LI] = 0;

      delete LR;
    }
  }
}


//---------------------------------------------------------------------------
// union two live ranges into one. The 2nd LR is deleted. Used for coalescing.
// Note: the caller must make sure that L1 and L2 are distinct and both
// LRs don't have suggested colors
//---------------------------------------------------------------------------

void LiveRangeInfo::unionAndUpdateLRs(V9LiveRange *L1, V9LiveRange *L2) {
  assert(L1 != L2 && (!L1->hasSuggestedColor() || !L2->hasSuggestedColor()));
  assert(! (L1->hasColor() && L2->hasColor()) ||
         L1->getColor() == L2->getColor());

  L2->insert (L1->begin(), L1->end());   // add elements of L2 to L1

  for(V9LiveRange::iterator L2It = L2->begin(); L2It != L2->end(); ++L2It) {
    L1->insert(*L2It);                  // add the var in L2 to L1
    LiveRangeMap[*L2It] = L1;           // now the elements in L2 should map
                                        //to L1
  }

  // set call interference for L1 from L2
  if (L2->isCallInterference())
    L1->setCallInterference();

  // add the spill costs
  L1->addSpillCost(L2->getSpillCost());

  // If L2 has a color, give L1 that color.  Note that L1 may have had the same
  // color or none, but would not have a different color as asserted above.
  if (L2->hasColor())
    L1->setColor(L2->getColor());

  // Similarly, if LROfUse(L2) has a suggested color, the new range
  // must have the same color.
  if (L2->hasSuggestedColor())
    L1->setSuggestedColor(L2->getSuggestedColor());

  delete L2;                        // delete L2 as it is no longer needed
}


//---------------------------------------------------------------------------
// Method for creating a single live range for a definition.
// The definition must be represented by a virtual register (a Value).
// Note: this function does *not* check that no live range exists for def.
//---------------------------------------------------------------------------

V9LiveRange*
LiveRangeInfo::createNewLiveRange(const Value* Def, bool isCC /* = false*/)
{
  V9LiveRange* DefRange = new V9LiveRange();  // Create a new live range,
  DefRange->insert(Def);                  // add Def to it,
  LiveRangeMap[Def] = DefRange;           // and update the map.

  // set the register class of the new live range
  DefRange->setRegClass(RegClassList[MRI.getRegClassIDOfType(Def->getType(),
                                                             isCC)]);

  if (DEBUG_RA >= RA_DEBUG_LiveRanges) {
    std::cerr << "  Creating a LR for def ";
    if (isCC) std::cerr << " (CC Register!)";
    std::cerr << " : " << RAV(Def) << "\n";
  }
  return DefRange;
}


V9LiveRange*
LiveRangeInfo::createOrAddToLiveRange(const Value* Def, bool isCC /* = false*/)
{
  V9LiveRange *DefRange = LiveRangeMap[Def];

  // check if the LR is already there (because of multiple defs)
  if (!DefRange) {
    DefRange = createNewLiveRange(Def, isCC);
  } else {                          // live range already exists
    DefRange->insert(Def);          // add the operand to the range
    LiveRangeMap[Def] = DefRange;   // make operand point to merged set
    if (DEBUG_RA >= RA_DEBUG_LiveRanges)
      std::cerr << "   Added to existing LR for def: " << RAV(Def) << "\n";
  }
  return DefRange;
}


//---------------------------------------------------------------------------
// Method for constructing all live ranges in a function. It creates live
// ranges for all values defined in the instruction stream. Also, it
// creates live ranges for all incoming arguments of the function.
//---------------------------------------------------------------------------
void LiveRangeInfo::constructLiveRanges() {

  if (DEBUG_RA >= RA_DEBUG_LiveRanges)
    std::cerr << "Constructing Live Ranges ...\n";

  // first find the live ranges for all incoming args of the function since
  // those LRs start from the start of the function
  for (Function::const_arg_iterator AI = Meth->arg_begin(); AI != Meth->arg_end(); ++AI)
    createNewLiveRange(AI, /*isCC*/ false);

  // Now suggest hardware registers for these function args
  MRI.suggestRegs4MethodArgs(Meth, *this);

  // Now create LRs for machine instructions.  A new LR will be created
  // only for defs in the machine instr since, we assume that all Values are
  // defined before they are used. However, there can be multiple defs for
  // the same Value in machine instructions.
  //
  // Also, find CALL and RETURN instructions, which need extra work.
  //
  MachineFunction &MF = MachineFunction::get(Meth);
  for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) {
    MachineBasicBlock &MBB = *BBI;

    // iterate over all the machine instructions in BB
    for(MachineBasicBlock::iterator MInstIterator = MBB.begin();
        MInstIterator != MBB.end(); ++MInstIterator) {
      MachineInstr *MInst = MInstIterator;

      // If the machine instruction is a  call/return instruction, add it to
      // CallRetInstrList for processing its args, ret value, and ret addr.
      //
      if(TM.getInstrInfo()->isReturn(MInst->getOpcode()) ||
         TM.getInstrInfo()->isCall(MInst->getOpcode()))
        CallRetInstrList.push_back(MInst);

      // iterate over explicit MI operands and create a new LR
      // for each operand that is defined by the instruction
      for (MachineInstr::val_op_iterator OpI = MInst->begin(),
             OpE = MInst->end(); OpI != OpE; ++OpI)
        if (OpI.isDef()) {
          const Value *Def = *OpI;
          bool isCC = (OpI.getMachineOperand().getType()
                       == MachineOperand::MO_CCRegister);
          V9LiveRange* LR = createOrAddToLiveRange(Def, isCC);

          // If the operand has a pre-assigned register,
          // set it directly in the V9LiveRange
          if (OpI.getMachineOperand().hasAllocatedReg()) {
            unsigned getClassId;
            LR->setColor(MRI.getClassRegNum(OpI.getMachineOperand().getReg(),
                                            getClassId));
          }
        }

      // iterate over implicit MI operands and create a new LR
      // for each operand that is defined by the instruction
      for (unsigned i = 0; i < MInst->getNumImplicitRefs(); ++i)
        if (MInst->getImplicitOp(i).isDef()) {
          const Value *Def = MInst->getImplicitRef(i);
          V9LiveRange* LR = createOrAddToLiveRange(Def, /*isCC*/ false);

          // If the implicit operand has a pre-assigned register,
          // set it directly in the V9LiveRange
          if (MInst->getImplicitOp(i).hasAllocatedReg()) {
            unsigned getClassId;
            LR->setColor(MRI.getClassRegNum(
                                MInst->getImplicitOp(i).getReg(),
                                getClassId));
          }
        }

    } // for all machine instructions in the BB
  } // for all BBs in function

  // Now we have to suggest clors for call and return arg live ranges.
  // Also, if there are implicit defs (e.g., retun value of a call inst)
  // they must be added to the live range list
  //
  suggestRegs4CallRets();

  if( DEBUG_RA >= RA_DEBUG_LiveRanges)
    std::cerr << "Initial Live Ranges constructed!\n";
}


//---------------------------------------------------------------------------
// If some live ranges must be colored with specific hardware registers
// (e.g., for outgoing call args), suggesting of colors for such live
// ranges is done using target specific function. Those functions are called
// from this function. The target specific methods must:
//    1) suggest colors for call and return args.
//    2) create new LRs for implicit defs in machine instructions
//---------------------------------------------------------------------------
void LiveRangeInfo::suggestRegs4CallRets() {
  std::vector<MachineInstr*>::iterator It = CallRetInstrList.begin();
  for( ; It != CallRetInstrList.end(); ++It) {
    MachineInstr *MInst = *It;
    MachineOpCode OpCode = MInst->getOpcode();

    if (TM.getInstrInfo()->isReturn(OpCode))
      MRI.suggestReg4RetValue(MInst, *this);
    else if (TM.getInstrInfo()->isCall(OpCode))
      MRI.suggestRegs4CallArgs(MInst, *this);
    else
      assert( 0 && "Non call/ret instr in CallRetInstrList" );
  }
}


//--------------------------------------------------------------------------
// The following method coalesces live ranges when possible. This method
// must be called after the interference graph has been constructed.


/* Algorithm:
   for each BB in function
     for each machine instruction (inst)
       for each definition (def) in inst
         for each operand (op) of inst that is a use
           if the def and op are of the same register type
             if the def and op do not interfere //i.e., not simultaneously live
               if (degree(LR of def) + degree(LR of op)) <= # avail regs
                 if both LRs do not have suggested colors
                    merge2IGNodes(def, op) // i.e., merge 2 LRs

*/
//---------------------------------------------------------------------------


// Checks if live range LR interferes with any node assigned or suggested to
// be assigned the specified color
//
inline bool InterferesWithColor(const V9LiveRange& LR, unsigned color) {
  IGNode* lrNode = LR.getUserIGNode();
  for (unsigned n=0, NN = lrNode->getNumOfNeighbors(); n < NN; n++) {
    V9LiveRange *neighLR = lrNode->getAdjIGNode(n)->getParentLR();
    if (neighLR->hasColor() && neighLR->getColor() == color)
      return true;
    if (neighLR->hasSuggestedColor() && neighLR->getSuggestedColor() == color)
      return true;
  }
  return false;
}

// Cannot coalesce if any of the following is true:
// (1) Both LRs have suggested colors (should be "different suggested colors"?)
// (2) Both LR1 and LR2 have colors and the colors are different
//    (but if the colors are the same, it is definitely safe to coalesce)
// (3) LR1 has color and LR2 interferes with any LR that has the same color
// (4) LR2 has color and LR1 interferes with any LR that has the same color
//
inline bool InterfsPreventCoalescing(const V9LiveRange& LROfDef,
                                     const V9LiveRange& LROfUse) {
  // (4) if they have different suggested colors, cannot coalesce
  if (LROfDef.hasSuggestedColor() && LROfUse.hasSuggestedColor())
    return true;

  // if neither has a color, nothing more to do.
  if (! LROfDef.hasColor() && ! LROfUse.hasColor())
    return false;

  // (2, 3) if L1 has color...
  if (LROfDef.hasColor()) {
    if (LROfUse.hasColor())
      return (LROfUse.getColor() != LROfDef.getColor());
    return InterferesWithColor(LROfUse, LROfDef.getColor());
  }

  // (4) else only LROfUse has a color: check if that could interfere
  return InterferesWithColor(LROfDef, LROfUse.getColor());
}


void LiveRangeInfo::coalesceLRs()
{
  if(DEBUG_RA >= RA_DEBUG_LiveRanges)
    std::cerr << "\nCoalescing LRs ...\n";

  MachineFunction &MF = MachineFunction::get(Meth);
  for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) {
    MachineBasicBlock &MBB = *BBI;

    // iterate over all the machine instructions in BB
    for(MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII){
      const MachineInstr *MI = MII;

      if( DEBUG_RA >= RA_DEBUG_LiveRanges) {
        std::cerr << " *Iterating over machine instr ";
        MI->dump();
        std::cerr << "\n";
      }

      // iterate over  MI operands to find defs
      for(MachineInstr::const_val_op_iterator DefI = MI->begin(),
            DefE = MI->end(); DefI != DefE; ++DefI) {
        if (DefI.isDef()) { // this operand is modified
          V9LiveRange *LROfDef = getLiveRangeForValue( *DefI );
          RegClass *RCOfDef = LROfDef->getRegClass();

          MachineInstr::const_val_op_iterator UseI = MI->begin(),
            UseE = MI->end();
          for( ; UseI != UseE; ++UseI) { // for all uses
            V9LiveRange *LROfUse = getLiveRangeForValue( *UseI );
            if (!LROfUse) {             // if LR of use is not found
              //don't warn about labels
              if (!isa<BasicBlock>(*UseI) && DEBUG_RA >= RA_DEBUG_LiveRanges)
                std::cerr << " !! Warning: No LR for use " << RAV(*UseI)<< "\n";
              continue;                 // ignore and continue
            }

            if (LROfUse == LROfDef)     // nothing to merge if they are same
              continue;

            if (MRI.getRegTypeForLR(LROfDef) ==
                MRI.getRegTypeForLR(LROfUse)) {
              // If the two RegTypes are the same
              if (!RCOfDef->getInterference(LROfDef, LROfUse) ) {

                unsigned CombinedDegree =
                  LROfDef->getUserIGNode()->getNumOfNeighbors() +
                  LROfUse->getUserIGNode()->getNumOfNeighbors();

                if (CombinedDegree > RCOfDef->getNumOfAvailRegs()) {
                  // get more precise estimate of combined degree
                  CombinedDegree = LROfDef->getUserIGNode()->
                    getCombinedDegree(LROfUse->getUserIGNode());
                }

                if (CombinedDegree <= RCOfDef->getNumOfAvailRegs()) {
                  // if both LRs do not have different pre-assigned colors
                  // and both LRs do not have suggested colors
                  if (! InterfsPreventCoalescing(*LROfDef, *LROfUse)) {
                    RCOfDef->mergeIGNodesOfLRs(LROfDef, LROfUse);
                    unionAndUpdateLRs(LROfDef, LROfUse);
                  }

                } // if combined degree is less than # of regs
              } // if def and use do not interfere
            }// if reg classes are the same
          } // for all uses
        } // if def
      } // for all defs
    } // for all machine instructions
  } // for all BBs

  if (DEBUG_RA >= RA_DEBUG_LiveRanges)
    std::cerr << "\nCoalescing Done!\n";
}

/*--------------------------- Debug code for printing ---------------*/


void LiveRangeInfo::printLiveRanges() {
  LiveRangeMapType::iterator HMI = LiveRangeMap.begin();   // hash map iterator
  std::cerr << "\nPrinting Live Ranges from Hash Map:\n";
  for( ; HMI != LiveRangeMap.end(); ++HMI) {
    if (HMI->first && HMI->second) {
      std::cerr << " Value* " << RAV(HMI->first) << "\t: ";
      if (IGNode* igNode = HMI->second->getUserIGNode())
        std::cerr << "LR# " << igNode->getIndex();
      else
        std::cerr << "LR# " << "<no-IGNode>";
      std::cerr << "\t:Values = " << *HMI->second << "\n";
    }
  }
}

} // End llvm namespace
