Esempio n. 1
0
bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) {
  DEBUG(dbgs() << "********** Stack Slot Coloring **********\n");

  MFI = MF.getFrameInfo();
  MRI = &MF.getRegInfo(); 
  TII = MF.getTarget().getInstrInfo();
  TRI = MF.getTarget().getRegisterInfo();
  LS = &getAnalysis<LiveStacks>();
  VRM = &getAnalysis<VirtRegMap>();
  loopInfo = &getAnalysis<MachineLoopInfo>();

  bool Changed = false;

  unsigned NumSlots = LS->getNumIntervals();
  if (NumSlots < 2) {
    if (NumSlots == 0 || !VRM->HasUnusedRegisters())
      // Nothing to do!
      return false;
  }

  // If there are calls to setjmp or sigsetjmp, don't perform stack slot
  // coloring. The stack could be modified before the longjmp is executed,
  // resulting in the wrong value being used afterwards. (See
  // <rdar://problem/8007500>.)
  if (MF.callsSetJmp())
    return false;

  // Gather spill slot references
  ScanForSpillSlotRefs(MF);
  InitializeSlots();
  Changed = ColorSlots(MF);

  NextColor = -1;
  SSIntervals.clear();
  for (unsigned i = 0, e = SSRefs.size(); i != e; ++i)
    SSRefs[i].clear();
  SSRefs.clear();
  OrigAlignments.clear();
  OrigSizes.clear();
  AllColors.clear();
  UsedColors.clear();
  for (unsigned i = 0, e = Assignments.size(); i != e; ++i)
    Assignments[i].clear();
  Assignments.clear();

  if (Changed) {
    for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
      Changed |= RemoveDeadStores(I);
  }

  return Changed;
}
Esempio n. 2
0
bool VirtRegReduction::runOnMachineFunction(MachineFunction &MF)
{
  bool Changed = false;

#if VRRPROF
  const Function *F = MF.getFunction();
  std::string FN = F->getName().str();
  llog("starting vrr... %s (%d)\n", FN.c_str(), (int)time(NULL));
  llog("starting immRegs finder... (%d)\n", (int)time(NULL));
#endif
  std::auto_ptr<std::unordered_set<unsigned> > immRegsHolder;
  std::unordered_set<unsigned> *immRegs = NULL;
  
  // single-def regs defined by a MoveImm shouldn't coalesce as we may be
  // able to fold them later
  {
    std::unordered_map<unsigned, const MachineInstr *> singleDef;

    MachineFunction::const_iterator I = MF.begin(), E = MF.end();

    // find all registers w/ a single def
    for(; I != E; I++)
    {
      MachineBasicBlock::const_iterator BI = I->begin(), BE = I->end();

     for(; BI != BE; BI++)
     {
       MachineInstr::const_mop_iterator II, IE;
       II = BI->operands_begin();
       IE = BI->operands_end();
       for(; II != IE; II++)
         if(II->isReg() && II->isDef())
         {
           unsigned R = II->getReg();
           std::unordered_map<unsigned, const MachineInstr *>::iterator SI = singleDef.find(R);

           if(SI == singleDef.end())
             singleDef[R] = BI; // first seen! insert
           else
             SI->second = NULL; // second seen -- replace w/ NULL
         }
      }
    }

    std::unordered_map<unsigned, const MachineInstr *>::const_iterator SI = singleDef.begin(), SE = singleDef.end();

    for(; SI != SE; SI++)
    {
      if(SI->second && SI->second->getDesc().isMoveImmediate()) // single def imm?
      {
        if(!immRegs)
          immRegsHolder.reset(immRegs = new std::unordered_set<unsigned>);
        immRegs->insert(SI->first); // don't coalesce
      }
    }
  }

#if VRRPROF
  llog("starting tdkRegs finder... (%d)\n", (int)time(NULL));
#endif

  std::auto_ptr<std::unordered_set<unsigned> > tdkRegsHolder;
  std::unordered_set<unsigned> *tdkRegs = NULL;
  
  bool setjmpSafe = !MF.callsSetJmp() && MF.getFunction()->doesNotThrow();

  {
    tdkRegsHolder.reset(tdkRegs = new std::unordered_set<unsigned>);

    std::unordered_map<unsigned, unsigned> trivialDefKills;

    MachineFunction::const_iterator I = MF.begin(), E = MF.end();

    // find all registers defed and killed in the same block w/ no intervening
    // unsafe (due to setjmp) calls + side-effecty operations
    for(; I != E; I++)
    {
      std::unordered_set<unsigned> defs;

      MachineBasicBlock::const_iterator BI = I->begin(), BE = I->end();

     for(; BI != BE; BI++)
     {
       // TODO need to add || BI->getDesc().isInlineAsm() here to help stackification?
       if((!setjmpSafe && BI->getDesc().isCall()) || BI->getDesc().hasUnmodeledSideEffects()) { 
         // invalidate on a call instruction if setjmp present, or instr with side effects regardless
         defs.clear();
       }

       MachineInstr::const_mop_iterator II, IE;
     
       // uses when we're not tracking a reg it make it unsafe
       II = BI->operands_begin();
       IE = BI->operands_end();
       for(; II != IE; II++)
         if(II->isReg() && II->isUse())
         {
           unsigned R = II->getReg();
           std::unordered_set<unsigned>::const_iterator DI = defs.find(R);

           if(DI == defs.end())
             trivialDefKills[R] = 100;
         }
       // kills of tracked defs are trivial def/kills
       II = BI->operands_begin();
       IE = BI->operands_end();
       for(; II != IE; II++)
         if(II->isReg() && II->isKill())
         {
           unsigned R = II->getReg();
           std::unordered_set<unsigned>::const_iterator DI = defs.find(R);

           if(DI != defs.end())
           {
             defs.erase(DI);
             trivialDefKills[R]++;
           }
           else
             trivialDefKills[R] = 100; // don't use
         }
       // record all defs in this instruction
       II = BI->operands_begin();
       IE = BI->operands_end();
       for(; II != IE; II++)
         if(II->isReg() && II->isDef())
           defs.insert(II->getReg());
      }
    }

    std::unordered_map<unsigned, unsigned>::const_iterator DKI = trivialDefKills.begin(),
        DKE = trivialDefKills.end();

    for(; DKI != DKE; DKI++)
      if(DKI->second == 1)
        tdkRegs->insert(DKI->first);
  }

#if VRRPROF
  llog("starting conflict graph construction... (%d)\n", (int)time(NULL));
#endif

  std::unordered_set<unsigned>::const_iterator tdkE = tdkRegs->end();

  std::unordered_set<unsigned> *okRegs = NULL;

  if(!setjmpSafe)
    okRegs = tdkRegs;

  MachineRegisterInfo *RI = &(MF.getRegInfo());
  // will eventually hold a virt register coloring for this function
  ConflictGraph::Coloring coloring;

  {
    ConflictGraph cg;
    LiveIntervals &LIS = getAnalysis<LiveIntervals>();
    LiveIntervals::const_iterator I = LIS.begin(), E = LIS.end();

    // check every possible LiveInterval, LiveInterval pair of the same
    // register class for overlap and add overlaps to the conflict graph
    // also, treat trivially def-kill-ed regs and not trivially def-kill-ed
    // regs as conflicting so they end up using different VRs -- this makes
    // stackification easier later in the toolchain
    for(; I != E; I++)
    {
      unsigned R = I->first;

      if(TargetRegisterInfo::isPhysicalRegister(R))
        continue;
      if(okRegs && okRegs->find(R) == okRegs->end())
        continue;
      // leave singly-defined MoveImm regs for later coalescing
      if(immRegs && immRegs->find(R) != immRegs->end())
        continue;

//      const TargetRegisterClass *RC = RI->getRegClass(R);
      const LiveInterval *LI = I->second;

      if(LI->empty())
        continue;

      cg.addVertex(R);

      bool notTDK = tdkRegs->find(R) == tdkE;
      LiveIntervals::const_iterator I1 = I;

      I1++;
					
      for(; I1 != E; I1++)
      {
        unsigned R1 = I1->first;

        if(TargetRegisterInfo::isPhysicalRegister(R1))
          continue;
        if(okRegs && okRegs->find(R1) == okRegs->end())
          continue;
        // leave singly-defined MoveImm regs for later coalescing
        if(immRegs && immRegs->find(R1) != immRegs->end())
          continue;

/* Don't bother checked RC -- even though it sounds like an opt, it doesn't speed us up in practice
        const TargetRegisterClass *RC1 = RI->getRegClass(R1);

        if(RC != RC1)
          continue; // different reg class... won't conflict
*/

	const LiveInterval *LI1 = I1->second;

        // conflict if intervals overlap OR they're not both TDK or both NOT TDK
        if(LI->overlaps(*LI1) || notTDK != (tdkRegs->find(R1) == tdkE))
          cg.addEdge(R, R1);
      }
    }

#if VRRPROF
  llog("starting coloring... (%d)\n", (int)time(NULL));
#endif

    cg.color(&coloring);

#if VRRPROF
  llog("starting vreg=>vreg construction... (%d)\n", (int)time(NULL));
#endif

	typedef std::unordered_map<unsigned, unsigned> VRegMap;
	VRegMap Regs;

	// build up map of vreg=>vreg
	{
		std::unordered_map<const TargetRegisterClass *, std::unordered_map<unsigned, unsigned> > RCColor2VReg;

		ConflictGraph::Coloring::const_iterator I = coloring.begin(), E = coloring.end();

		for(; I != E; I++)
		{
			unsigned R = I->first;
			unsigned Color = I->second;
			const TargetRegisterClass *RC = RI->getRegClass(R);
			std::unordered_map<unsigned, unsigned> &Color2VReg = RCColor2VReg[RC];

			VRegMap::const_iterator CI = Color2VReg.find(Color);

			if(CI != Color2VReg.end())
				Regs[R] = CI->second; // seen this color; map it
			else
				Regs[R] = Color2VReg[Color] = R; // first sighting of color; bind to this reg
		}
	}

#if VRRPROF
  llog("starting remap... (%d)\n", (int)time(NULL));
#endif


	// remap regs
	{
		VRegMap::const_iterator I = Regs.begin(), E = Regs.end();

		for(; I != E; I++)
			if(I->first != I->second)
			{
				RI->replaceRegWith(I->first, I->second);
				Changed = true;
			}
	}
  }

#if VRRPROF
  llog("done... (%d)\n", (int)time(NULL));
#endif

  return Changed;
}