//===- MappingInfo.cpp - create LLVM info and output to .s file ---------===//
//
// Create Map from LLVM BB and Instructions and Machine Instructions
// and output the information as .byte directives to the .s file
// Currently Sparc specific but will be extended for others later
//
//===--------------------------------------------------------------------===//

#include "llvm/Reoptimizer/Mapping/MappingInfo.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include <map>
using std::vector;


// MappingInfo - This method collects mapping info 
// for the mapping from LLVM to machine code.
//
namespace {
  class getMappingInfoForFunction : public FunctionPass { 
    std::ostream &Out;
  public:
    getMappingInfoForFunction(std::ostream &out) : Out(out){}
    const char* getPassName() const{return "Sparc MappingInformation";}
    bool runOnFunction(Function &FI);
  private:
    std::map<const Function*, unsigned> Fkey; //key of F to num
    std::map<const MachineInstr*, unsigned> BBkey; //key BB to num
    std::map<const MachineInstr*, unsigned> MIkey; //key MI to num
    
    bool doInitialization(Module &M);
    void create_BB_to_MInumber_Key(Function &FI);    
    void create_MI_to_number_Key(Function &FI);
    void writeBBToMImap(Function &FI);
    void writeLLVMToMImap(Function &FI);
    void getMappingInfoForFunction::writePrologue(const char * area,    
						  const char *label,
						  unsigned FunctionNo);
    void getMappingInfoForFunction::writeEpilogue(const char *area, 
						  const char *label,
						  unsigned FunctionNo);
    unsigned writeNumber(unsigned X);
  };
}


//pass definition
Pass *MappingInfoForFunction(std::ostream &out){
  return (new getMappingInfoForFunction(out));
}

//function definitions :
//create and output maps to the .s file
bool getMappingInfoForFunction::runOnFunction(Function &FI) {
  
  
  //first create reference maps
  //createFunctionKey(M);
  create_BB_to_MInumber_Key(FI);
  create_MI_to_number_Key(FI);
  unsigned FunctionNo = Fkey[&(FI)];

  //now print out the maps
  writePrologue("BB TO MI MAP", "BBMIMap", FunctionNo);
  writeBBToMImap(FI);
  writeEpilogue("BB TO MI MAP", "BBMIMap", FunctionNo);  
  
  writePrologue("LLVM I TO MI MAP", "LMIMap", FunctionNo);
  writeLLVMToMImap(FI);
  writeEpilogue("LLVM I TO MI MAP", "LMIMap", FunctionNo); 
  return false; 
}  

void getMappingInfoForFunction::writePrologue(const char *area,
					      const char *label, 
					      unsigned FunctionNo){
  Out << "!" << area << "\n";   
  Out << "\t.section \".rodata\"\n\t.align 8\n";  
  Out << "\t.global " << label << FunctionNo << "\n";    
  Out << "\t.type " << label << FunctionNo << ",#object\n"; 
  Out << label << FunctionNo << ":\n"; 
  Out << "\t.word .end_" << label << FunctionNo << "-"
      << label << FunctionNo << "\n";
}

void getMappingInfoForFunction::writeEpilogue(const char *area,
					      const char *label,
					      unsigned FunctionNo){
  Out << ".end_" << label << FunctionNo << ":\n";    
  Out << "\t.size " << label << FunctionNo << ", .end_" 
      << label << FunctionNo << "-" << label 
      << FunctionNo << "\n\n\n\n";
}

//write out information as .byte directives
unsigned getMappingInfoForFunction::writeNumber(unsigned X) {
  unsigned i=0;
  do {
    unsigned tmp = X & 127;
    X >>= 7;
    if (X) tmp |= 128;
    Out << "\t.byte " << tmp << "\n";
    ++i;
  } while(X);
  return i;
}

//Assign a number to each Function 
bool getMappingInfoForFunction::doInitialization(Module &M) {
  unsigned i = 0;
  for (Module::iterator FI = M.begin(), FE = M.end();
       FI != FE; ++FI){
    //dont count F with 0 BBs
    if(FI->isExternal()) continue;
    Fkey[FI] = i;
    ++i;
  }
  return false;
}
     
//Assign a Number to each BB
void getMappingInfoForFunction::create_BB_to_MInumber_Key(Function &FI) {
  unsigned i = 0;
  MachineFunction &MF = MachineFunction::get(&FI);
  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
       BI != BE; ++BI) {
    MachineBasicBlock &miBB = *BI;
    BBkey[miBB[0]] = i;
    i = i+(miBB.size());
  }
}

//Assign a number to each MI wrt beginning of the BB
void getMappingInfoForFunction::create_MI_to_number_Key(Function &FI) {
  MachineFunction &MF = MachineFunction::get(&FI);
  for (MachineFunction::iterator BI=MF.begin(), BE=MF.end(); BI != BE; ++BI) {
    MachineBasicBlock &miBB = *BI;
    unsigned j = 0;
    for(MachineBasicBlock::iterator miI=miBB.begin(), miE=miBB.end();
	miI!=miE; ++miI, ++j) {
      MIkey[*miI]=j;
    }
  }
}

//BBtoMImap: contains F#, BB#, 
//              MI#[wrt beginning of F], #MI in BB
void getMappingInfoForFunction::writeBBToMImap(Function &FI){
  unsigned bb = 0;
  MachineFunction &MF = MachineFunction::get(&FI);  
  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
       BI != BE; ++BI, ++bb) {
    MachineBasicBlock &miBB = *BI;
    writeNumber(bb);
    //Out << " BB: "<<(void *)BI<<"\n";
    //for(int i=0; i<miBB.size(); ++i)
    //Out<<*miBB[i]<<"\n";
    writeNumber( BBkey[ miBB[0] ]);
    writeNumber(miBB.size());
  }
}

//LLVMtoMImap: contains F#, BB#, LLVM#, 
//                           MIs[wrt to beginning of BB] 
void getMappingInfoForFunction::writeLLVMToMImap(Function &FI) {

  unsigned bb =0;
  for (Function::iterator BI = FI.begin(),  BE = FI.end(); 
       BI != BE; ++BI, ++bb) {
    unsigned li = 0;
    writeNumber(bb);
    //std::cerr<<"BasicBlockNumber= "<<bb<<"\n";

    //Out << "BB: "<<(void *)BI<<"\n";
    writeNumber(BI->size());
    //std::cerr<<"BasicBlockSize  = "<<BI->size()<<"\n";

    for (BasicBlock::iterator II = BI->begin(), 
	   IE = BI->end(); II != IE; ++II, ++li) {
    //Out << "I: "<<*II<<"\n";
      MachineCodeForInstruction& miI = 
	MachineCodeForInstruction::get(II);
      
      //do for each corr. MI
      writeNumber(li);
      //std::cerr<<"InstructionNumber= "<<li<<"\n";

      writeNumber(miI.size());
      //std::cerr<<"InstructionSize  = "<<miI.size()<<"\n";
   
      for (MachineCodeForInstruction::iterator miII = miI.begin(), 
	     miIE = miI.end(); miII != miIE; ++miII){
	//Out << "MI: "<<**miII<<"\n";
	writeNumber(MIkey[*miII]);
        //std::cerr<<"MachineInstruction= "<<MIkey[*miII]<<"\n";
      }
    }
  } 
}
