//===------------ FernandoPrintCGF.cpp - Printing prototype ---------------===//
//
//              Register Allocation via Coloring of Chordal Graphs 
//
// This file was developed by Fernando Magno Quintao Pereira, fernando at ucla
// dot edu, and it prints the control flow graph in the dot format.
//
// Date: May 6rd, 2006
//
//===----------------------------------------------------------------------===//
//
// This file prints all the instructions in the given machine function in the
// dot format, so that it can be visualized using Graphviz. To use it,
// add the definition of FernandoCfgID to llvm/CodeGen/Passes.h, and add
// this pass as a required pass to the PNE class (PHIElimination.cpp).
// Eg.: addRequired(FernandoCfgID). Then, compile the modified files, and
// link them into llc: makellvm llc in the $LLVM_HOME/lib/CodeGen directory.
//
//===----------------------------------------------------------------------===//

// Function
#include "llvm/Function.h"

// FernandoPassID
#include "llvm/CodeGen/Passes.h"

// MachineInstr
#include "llvm/CodeGen/MachineInstr.h"

// BasicBlock
#include "llvm/BasicBlock.h"

// MachineBasicBlock
#include "llvm/CodeGen/MachineFunctionPass.h"

// MRegisterInfo
#include "llvm/Target/MRegisterInfo.h"

// TargetInstrInfo
#include "llvm/Target/TargetInstrInfo.h"

// TargetMachine
#include "llvm/Target/TargetMachine.h"

// cerr
#include <iostream>

// ostringstream
#include <sstream>

using namespace llvm;

namespace {

  #define INST_LEN 20
  #define OPRT_LEN 8

  class FernandoPrintCGF : public MachineFunctionPass {

    /// All target-specific information can be accessed through this interface.
    const TargetMachine *TM;

    /// Information about the bank of registers implemented by the actual
    /// machine can be accessed through this interface.
    const MRegisterInfo *RegInfo;

    public:
      virtual void getAnalysisUsage(AnalysisUsage &AU) const {
        AU.setPreservesAll();
      }

      virtual const char *getPassName() const {
        return "Print machine instructions.";
      }

    private:
      /// runOnMachineFunction - Prints information about each basic block.
      bool runOnMachineFunction(MachineFunction &Fn);

      /// AllocateBasicBlock - For the given basic block, prints the name
      /// of the basic block, and information about each of the
      /// instructions.
      void PrintBasicBlock(MachineBasicBlock &MBB);

      /// Prints the virtual registers used and defined by the instruction.
      void PrintOperands(MachineInstr *MI);

      /// Prints the name of the register.
      int PrintRegister(MachineOperand &MO);

      /// Prints the name, number, and neat header for the basic block.
      void PrintEdges(MachineBasicBlock &MBB);

      /// Fills str with n characters like 'c', where n = size(str) + packSize.
      /// It returns the number of characters printed.
      int PrintPackedStr(const char * str, int packSize, char c);
      int PrintPackedStr(std::string str, int packSize, char c);

      /// Gives the name of the basic block
      std::string getBBName(MachineBasicBlock &MBB) {
        const BasicBlock *BB = MBB.getBasicBlock();
        std::ostringstream aux;
        std::string bbName;
        aux << BB->getName();
        return aux.str();
      }
  };

  RegisterPass<FernandoPrintCGF> W("FERNANDO_print_cfg", "Fernando print CFG.");

}


// the external declaration of FernandoCfgID is in llvm/CodeGen/Passes.h
const PassInfo *llvm::FernandoCfgID = W.getPassInfo();


void FernandoPrintCGF::PrintBasicBlock(MachineBasicBlock &MBB) {
  PrintEdges(MBB);
  std::string blockName = getBBName(MBB);
  std::cerr << "\"" << blockName << "\"" << " [ label=\"";

  // loop over each instruction
  MachineBasicBlock::iterator MII = MBB.begin();
  const TargetInstrInfo &TII = *TM->getInstrInfo();
  while (MII != MBB.end()) {
    MachineInstr *MI = MII++;
    const TargetInstrDescriptor &TID = TII.get(MI->getOpcode());
    PrintPackedStr(TID.Name, INST_LEN, ' ');
    PrintOperands(MI);
    std::cerr << "  \\l";
  }
  std::cerr << "\"]\n";
}


int FernandoPrintCGF::PrintPackedStr(std::string str, int packSize, char c) {
  int strSize = str.size();
  int incSize = strSize < packSize ? packSize - strSize : 0 ;
  std::string strAux(incSize, c);
  std::cerr << str << strAux;
  return (strSize > packSize) ? strSize : packSize ;
}


int FernandoPrintCGF::PrintPackedStr(const char * str, int packSize, char c) {
  int strSize = strlen(str);
  int incSize = strSize < packSize ? packSize - strSize : 0 ;
  std::string strAux(incSize, c);
  std::cerr << str << strAux;
  return (strSize > packSize) ? strSize : packSize ;
}


void FernandoPrintCGF::PrintEdges(MachineBasicBlock &MBB) {
  const BasicBlock *BB = MBB.getBasicBlock();
  std::string bbName = "\"" + getBBName(MBB) + "\"";

  // Prints all the successors:
  for(MachineBasicBlock::succ_iterator succ = MBB.succ_begin();
      succ != MBB.succ_end();
      succ++) {
    MachineBasicBlock* mbb = *succ;
    const BasicBlock *bb = mbb->getBasicBlock();
    std::cerr << bbName << " -> " << "\"" << bb->getName() << "\"" << "\n";
  }
}


int FernandoPrintCGF::PrintRegister(MachineOperand &MO) {
  int returnValue = 0;
  std::ostringstream aux;
  std::string result;
  if (MO.getReg()) {
    if(MRegisterInfo::isPhysicalRegister(MO.getReg())) {
      aux << RegInfo->getName(MO.getReg());
    }
    else {
      aux << "t" << MO.getReg();
    }
  }
  result = aux.str();
  returnValue = PrintPackedStr(result, OPRT_LEN, '-');
  return returnValue;
}


void FernandoPrintCGF::PrintOperands(MachineInstr *MI) {
  bool isFirst = true;
  int column = INST_LEN;
  int colChange = 0;
  // first, print all the definitions
  for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
    MachineOperand& MO = MI->getOperand(i);
    if (MO.isDef() && MO.isRegister() && MO.getReg()) {
      if(isFirst) {
        colChange += PrintRegister(MO);
        isFirst = false;
      } else {
        std::cerr << ", ";
        colChange += PrintRegister(MO);
      }
    }
  }
  if(colChange == 0) {
    PrintPackedStr("", OPRT_LEN, '-');
  }
  // next, print all the uses
  std::cerr << " := ";
  isFirst = true;
  for (unsigned i = 0; i != MI->getNumOperands(); ++i) {
    MachineOperand& MO = MI->getOperand(i);
    if (MO.isUse() && MO.isRegister() && MO.getReg()) {
      if(isFirst) {
        PrintRegister(MO);
        isFirst = false;
      } else {
        std::cerr << ", ";
        PrintRegister(MO);
      }
    }
  }
}


bool FernandoPrintCGF::runOnMachineFunction(MachineFunction &Fn) {

  // prints header information: graph name, node shape, etc
  std::cerr << "digraph foo {\n\n";
  std::cerr << "node [\n";
  std::cerr << "  fontname = \"Courier\"\n";
  std::cerr << "  fontsize = \"10\"\n";
  std::cerr << "  shape = \"box\"\n";
  std::cerr << "]\n\n";

  // prints the label (title) of the graph:
  const Function *F = Fn.getFunction();
  std::cerr << "label=\"CFG for function " << F->getName() << "\"\n\n";

  // prints each basic block:
  TM = &Fn.getTarget();
  RegInfo = TM->getRegisterInfo();
  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
    MBB != MBBe; ++MBB)
    PrintBasicBlock(*MBB);

  std::cerr << "}\n";
  return false;
}
