[llvm-commits] [regalloc_linearscan] CVS: llvm/lib/CodeGen/RegAllocLinearScan.cpp LiveIntervals.cpp

Alkis Evlogimenos alkis at cs.uiuc.edu
Tue Nov 18 03:45:04 PST 2003


Changes in directory llvm/lib/CodeGen:

RegAllocLinearScan.cpp updated: 1.1.2.13 -> 1.1.2.14
LiveIntervals.cpp updated: 1.1.2.10 -> 1.1.2.11

---
Log message:

LiveIntervals:
  - delete unneeded member functions
  - computer intervals for all registers (physical and virtual)

RegAllocLinearScan (major rewrite):
  - two registers from each register class are reserved for loading
    virtual registers from the stack.
  - register allocation happens in two passes: in the first pass
    registers are allocated for each virtual register interval and in
    the second the machine code is rewritten using the generated
    mapping.
  - live interval holes are still not used for better register
    allocation.
  - allocator was tested on
    test/Programs/SingleSource/Benchmarks/Shootout and it works with
    all but the heapsort benchmark.


---
Diffs of the changes:  (+378 -269)

Index: llvm/lib/CodeGen/RegAllocLinearScan.cpp
diff -u llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.13 llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.14
--- llvm/lib/CodeGen/RegAllocLinearScan.cpp:1.1.2.13	Sat Nov 15 12:33:33 2003
+++ llvm/lib/CodeGen/RegAllocLinearScan.cpp	Tue Nov 18 03:44:28 2003
@@ -46,28 +46,19 @@
         const MRegisterInfo* mri_;
         MachineBasicBlock* currentMbb_;
         MachineBasicBlock::iterator currentInstr_;
-        LiveVariables* lv_;
         typedef LiveIntervals::Intervals Intervals;
         const Intervals* li_;
-        Intervals::const_iterator currentInterval_;
         IntervalPtrs active_, inactive_;
 
         typedef std::vector<unsigned> Regs;
         Regs tempUseOperands_;
         Regs tempDefOperands_;
 
-        typedef LiveIntervals::MiIndex2MbbMap MiIndex2MbbMap;
-        MiIndex2MbbMap* mii2mbbMap_;
-
-        typedef LiveIntervals::Mbb2MiIndexMap Mbb2MiIndexMap;
-        Mbb2MiIndexMap* mbb2miiMap_;
+        Regs reserved_;
 
         typedef LiveIntervals::MachineBasicBlockPtrs MachineBasicBlockPtrs;
         MachineBasicBlockPtrs mbbs_;
 
-        typedef std::map<MachineInstr*, unsigned> Instr2IndexMap;
-        Instr2IndexMap i2iMap_;
-
         typedef std::vector<unsigned> Phys2VirtMap;
         Phys2VirtMap p2vMap_;
 
@@ -94,22 +85,19 @@
         /// runOnMachineFunction - register allocate the whole function
         bool runOnMachineFunction(MachineFunction&);
 
-        /// processInterval - inspect current interval and add it to
-        /// the active list if required
-        void processInterval(unsigned curIndex);
-
         /// processActiveIntervals - expire old intervals and move
         /// non-overlapping ones to the incative list
-        void processActiveIntervals(unsigned curIndex);
+        void processActiveIntervals(Intervals::const_iterator cur);
 
         /// processInactiveIntervals - expire old intervals and move
         /// overlapping ones to the active list
-        void processInactiveIntervals(unsigned curIndex);
+        void processInactiveIntervals(Intervals::const_iterator cur);
 
-        /// spillInterval - choose and spill interval. Currently we
-        /// spill the interval with the last end point in the active
-        /// and inactive lists
-        void spillInterval();
+        /// assignStackSlotAtInterval - choose and spill
+        /// interval. Currently we spill the interval with the last
+        /// end point in the active and inactive lists and the current
+        /// interval
+        void assignStackSlotAtInterval(Intervals::const_iterator cur);
 
         ///
         /// register handling helpers
@@ -131,15 +119,38 @@
         /// virtual register if we have one, otherwise return 0
         unsigned getFreePhysReg(unsigned virtReg);
 
-        /// allocateVirt2PhysReg - allocates the free physical
-        /// register to the virtual register passed as arguments
-        void allocateVirt2PhysReg(unsigned virtReg, unsigned physReg);
+
+        /// tempPhysRegAvailable - returns true if the specifed
+        /// temporary physical register is available
+        bool tempPhysRegAvailable(unsigned physReg);
+
+        /// getFreeTempPhysReg - return a free temprorary physical
+        /// register for this register class if we have one (should
+        /// never return 0)
+        unsigned getFreeTempPhysReg(const TargetRegisterClass* rc);
+
+        /// getFreeTempPhysReg - return a free temprorary physical
+        /// register for this virtual register if we have one (should
+        /// never return 0)
+        unsigned getFreeTempPhysReg(unsigned virtReg) {
+            const TargetRegisterClass* rc =
+                mf_->getSSARegMap()->getRegClass(virtReg);
+            return getFreeTempPhysReg(rc);
+        }
+
+        /// assignVirt2PhysReg - assigns the free physical register to
+        /// the virtual register passed as arguments
+        void assignVirt2PhysReg(unsigned virtReg, unsigned physReg);
 
         /// clearVirtReg - free the physical register associated with this
         /// virtual register and disassociate virtual->physical and
         /// physical->virtual mappings
         void clearVirtReg(unsigned virtReg);
 
+        /// assignVirt2StackSlot - assigns this virtual register to a
+        /// stack slot
+        void assignVirt2StackSlot(unsigned virtReg);
+
         /// findOrCreateStackSlot - returns the offset of the
         /// specified register on the stack allocating space if
         /// necessary
@@ -153,17 +164,12 @@
         /// an assigned stack slot
         void loadVirt2PhysReg(unsigned virtReg, unsigned physReg);
 
-        /// getInstructionIndex() - returns the instruction index as
-        /// it was computed by the live interval analysis (adjusts for
-        /// inserted instructions.
-        unsigned getInstructionIndex() const;
-
         void printVirt2PhysMap() const {
-            std::cerr << "\tallocated registers: ";
+            std::cerr << "allocated registers:\n";
             for (Virt2PhysMap::const_iterator
                      i = v2pMap_.begin(), e = v2pMap_.end(); i != e; ++i) {
                 std::cerr << '[' << i->first << ','
-                          << mri_->getName(i->second) << "] ";
+                          << mri_->getName(i->second) << "]\n";
             }
             std::cerr << '\n';
         }
@@ -172,7 +178,14 @@
                             RA::IntervalPtrs::const_iterator e) const {
             if (str) std::cerr << str << " intervals:\n";
             for (; i != e; ++i) {
-                std::cerr << "\t\t" << **i << '\n';
+                std::cerr << "\t\t" << **i << " -> ";
+                if ((*i)->reg < MRegisterInfo::FirstVirtualRegister) {
+                    std::cerr << mri_->getName((*i)->reg);
+                }
+                else {
+                    std::cerr << mri_->getName(v2pMap_.find((*i)->reg)->second);
+                }
+                std::cerr << '\n';
             }
         }
     };
@@ -182,190 +195,169 @@
     mf_ = &fn;
     tm_ = &fn.getTarget();
     mri_ = tm_->getRegisterInfo();
-    lv_ = &getAnalysis<LiveVariables>();
     li_ = &getAnalysis<LiveIntervals>().getIntervals();
-    currentInterval_ = li_->begin();
     active_.clear();
     inactive_.clear();
-    mii2mbbMap_ = &getAnalysis<LiveIntervals>().getMiIndex2MbbMap();
-    mbb2miiMap_ = &getAnalysis<LiveIntervals>().getMbb2MiIndexMap();
     mbbs_ = getAnalysis<LiveIntervals>().getOrderedMachineBasicBlockPtrs();
     p2vMap_.resize(MRegisterInfo::FirstVirtualRegister-1);
     p2vMap_.clear();
     v2pMap_.clear();
     v2ssMap_.clear();
 
+    // FIXME: this will work only for the X86 backend. I need to
+    // device an algorthm to select the minimal (considering register
+    // aliasing) number of temp registers to reserve so that we have 2
+    // registers for each register class available.
+
+    // reserve R32: EDI, EBX,
+    //         R16:  DI,  BX,
+    //         R8:   DH,  BH,
+    //         RFP: FP5, FP6
+    reserved_.push_back(19); /* EDI */
+    reserved_.push_back(17); /* EBX */
+    reserved_.push_back(12); /*  DI */
+    reserved_.push_back( 7); /*  BX */
+    reserved_.push_back(11); /*  DH */
+    reserved_.push_back( 4); /*  BH */
+    reserved_.push_back(28); /* FP5 */
+    reserved_.push_back(29); /* FP6 */
+
+    // liner scan algorithm
+    for (Intervals::const_iterator
+             i = li_->begin(), e = li_->end(); i != e; ++i) {
+        DEBUG(std::cerr << "processing current interval: " << *i << '\n');
+
+        DEBUG(printIntervals("\tactive", active_.begin(), active_.end()));
+        DEBUG(printIntervals("\tinactive", inactive_.begin(), inactive_.end()));
+
+        processActiveIntervals(i);
+        // processInactiveIntervals(i);
+
+        // if this register is preallocated, look for an interval that
+        // overlaps with it and assign it to a memory location
+        if (i->reg < MRegisterInfo::FirstVirtualRegister) {
+            for (IntervalPtrs::iterator
+                     ai = active_.begin(), ae = active_.end(); ai != ae; ++ai) {
+                unsigned virtReg = (*ai)->reg;
+                Virt2PhysMap::const_iterator it = v2pMap_.find(virtReg);
+                if (it != v2pMap_.end() && it->second == i->reg) {
+                    active_.erase(ai);
+                    clearVirtReg(virtReg);
+                    break;
+                }
+            }
+            reservePhysReg(i->reg);
+            active_.push_back(&*i);
+        }
+        // otherwise we are allocating a virtual register. try to find
+        // a free physical register or spill an interval in order to
+        // assign it one (we could spill the current though).
+        else {
+            unsigned physReg = getFreePhysReg(i->reg);
+            if (!physReg) {
+                assignStackSlotAtInterval(i);
+            }
+            else {
+                assignVirt2PhysReg(i->reg, physReg);
+                active_.push_back(&*i);
+            }
+        }
+    }
+    DEBUG(std::cerr << "finished register allocation\n");
+    DEBUG(printVirt2PhysMap());
+
+    DEBUG(std::cerr << "Rewrite machine code:\n");
     for (MachineBasicBlockPtrs::iterator
              mbbi = mbbs_.begin(), mbbe = mbbs_.end(); mbbi != mbbe; ++mbbi) {
         instrAdded_ = 0;
         currentMbb_ = *mbbi;
+
         for (currentInstr_ = currentMbb_->begin();
              currentInstr_ != currentMbb_->end(); ++currentInstr_) {
-            // virtual registers that were brought in just for the
-            // computation of the value generated by this
-            // instruction. they will need to be cleared at the end
-            tempUseOperands_.clear();
-            tempDefOperands_.clear();
 
-            assert(currentInstr_ >= currentMbb_->begin() &&
-                   currentInstr_ < currentMbb_->end() &&
-                   "current instruction/machine basic block mismatch");
-            unsigned curIndex = getInstructionIndex();
-            DEBUG(std::cerr << "instruction[" << curIndex << "]: ";
-                  (*currentInstr_)->print(std::cerr, *tm_));
-            DEBUG(std::cerr << "\tcurrent interval: ";
-                  if (currentInterval_ == li_->end()) std::cerr << "NONE\n";
-                  else std::cerr << *currentInterval_ << '\n');
-            DEBUG(printIntervals("\tactive", active_.begin(), active_.end()));
-            DEBUG(printIntervals("\tinactive",
-                                 inactive_.begin(),
-                                 inactive_.end()));
-            DEBUG(printVirt2PhysMap());
-
-            // FIXME: holes are completely ignored for now
-            // processInactiveIntervals(curIndex);
-
-            // loop over implicit defs spilling them
-            DEBUG(std::cerr << "\t\tprocessing implicit defs:\n");
-            const TargetInstrDescriptor& tid =
-                tm_->getInstrInfo().get((*currentInstr_)->getOpcode());
-            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
-                unsigned physReg = *id;
-                reservePhysReg(physReg);
+            DEBUG(std::cerr << "\tinstruction: ";
+                  (*currentInstr_)->print(std::cerr, *tm_););
+            DEBUG(std::cerr << "\t\tspilling temporarily defined operands "
+                  "of previous instruction:\n");
+            for (unsigned i = 0, e = tempDefOperands_.size(); i != e; ++i) {
+                spillVirtReg(tempDefOperands_[i]);
             }
+            tempDefOperands_.clear();
 
-            // assign physical registers to used operands
-            DEBUG(std::cerr << "\t\tprocessing used operands:\n");
+            // use our current mapping and actually replace and
+            // virtual register with its allocated physical registers
+            DEBUG(std::cerr << "\t\treplacing virtual registers with mapped "
+                  "physical registers:\n");
             for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
                  i != e; ++i) {
                 MachineOperand& op = (*currentInstr_)->getOperand(i);
-                if (op.opIsUse() && op.isVirtualRegister()) {
+                if (op.isVirtualRegister()) {
                     unsigned virtReg = op.getAllocatedRegNum();
-                    Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
-                    // virtual register is used but it is not
-                    // allocated.  it must be in a stack slot
-                    if (it == v2pMap_.end()) {
-                        unsigned physReg = getFreePhysReg(virtReg);
-                        if (!physReg) {
-                            spillInterval();
-                            physReg = getFreePhysReg(virtReg);
-                        }
-                        assert(physReg && "no available physical register?!");
-                        loadVirt2PhysReg(virtReg, physReg);
-                        tempUseOperands_.push_back(virtReg);
+                    unsigned physReg = v2pMap_[virtReg];
+                    // if this virtual registers lives on the stack,
+                    // load it to a temporary physical register
+                    if (physReg) {
+                        DEBUG(std::cerr << "\t\t\t%reg" << virtReg
+                              << " -> " << mri_->getName(physReg) << '\n');
+                        (*currentInstr_)->SetMachineOperandReg(i, physReg);
                     }
-                    (*currentInstr_)->SetMachineOperandReg(i, v2pMap_[virtReg]);
-                }
-            }
-
-            // loop over killed physical registers and clear them
-            DEBUG(std::cerr << "\t\tprocessing killed physical registers:\n");
-            for (LiveVariables::killed_iterator
-                     ki = lv_->killed_begin(*currentInstr_),
-                     ke = lv_->killed_end(*currentInstr_);
-                 ki != ke; ++ki) {
-                unsigned reg = ki->second;
-                if (reg < MRegisterInfo::FirstVirtualRegister) {
-                    clearReservedPhysReg(reg);
-                }
-            }
-
-            // loop over dead physical registers and clear them
-            DEBUG(std::cerr << "\t\tprocessing dead physical registers:\n");
-            for (LiveVariables::killed_iterator
-                     ki = lv_->dead_begin(*currentInstr_),
-                     ke = lv_->dead_end(*currentInstr_);
-                 ki != ke; ++ki) {
-                unsigned reg = ki->second;
-                if (reg < MRegisterInfo::FirstVirtualRegister) {
-                    clearReservedPhysReg(reg);
                 }
             }
 
-
-            DEBUG(std::cerr << "\t\tclearing temporarily used operands:\n");
-            for (unsigned i = 0, e = tempUseOperands_.size(); i != e; ++i) {
-                clearVirtReg(tempUseOperands_[i]);
-            }
-
-            // this will expire intervals that are dead right after
-            // the execution of this instruction
-            processActiveIntervals(curIndex + 1);
-
-            processInterval(curIndex);
-
-            // loop over operands and spill all already defined
-            // physical registers
-            DEBUG(std::cerr << "\t\tprocessing already allocated physical "
+            DEBUG(std::cerr << "\t\tloading temporarily used operands to "
                   "registers:\n");
             for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
                  i != e; ++i) {
                 MachineOperand& op = (*currentInstr_)->getOperand(i);
-                if (op.isPhysicalRegister() &&
-                    (op.opIsDefOnly() || op.opIsDefAndUse())) {
-                    unsigned physReg = op.getAllocatedRegNum();
-                    reservePhysReg(physReg);
-                }
-            }
-
-            // assign physical registers to not allocated defined operands
-            DEBUG(std::cerr << "\t\tprocessing not allocated defined "
-                  "operands:\n");
-            for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
-                 i != e; ++i) {
-                MachineOperand& op = (*currentInstr_)->getOperand(i);
-                if ((op.opIsDefOnly() || op.opIsDefAndUse()) &&
-                    op.isVirtualRegister()) {
+                if (op.isVirtualRegister() && op.opIsUse()) {
                     unsigned virtReg = op.getAllocatedRegNum();
-                    Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
-                    // virtual register is defined but it is not
-                    // allocated.  it must be in a stack slot
-                    if (it == v2pMap_.end()) {
-                        unsigned physReg = getFreePhysReg(virtReg);
-                        if (!physReg) {
-                            spillInterval();
-                            physReg = getFreePhysReg(virtReg);
-                        }
-                        assert(physReg && "no available physical register?!");
-                        // load from stack only if we are going to use the value
-                        if (op.opIsDefAndUse()) {
-                            loadVirt2PhysReg(virtReg, physReg);
-                        }
-                        // otherwise just assign the mapping
-                        else {
-                            allocateVirt2PhysReg(virtReg, physReg);
-                        }
-                        tempDefOperands_.push_back(virtReg);
+                    unsigned physReg = v2pMap_[virtReg];
+                    if (!physReg) {
+                        physReg = getFreeTempPhysReg(virtReg);
                     }
-                    (*currentInstr_)->SetMachineOperandReg(i, v2pMap_[virtReg]);
+                    loadVirt2PhysReg(virtReg, physReg);
+                    tempUseOperands_.push_back(virtReg);
+                    (*currentInstr_)->SetMachineOperandReg(i, physReg);
                 }
             }
 
-            // interval maybe spilled so we need to pull in any defs
-            // temporarily and spill them after the instruction is
-            // done
+            DEBUG(std::cerr << "\t\tclearing temporarily used operands:\n");
+            for (unsigned i = 0, e = tempUseOperands_.size(); i != e; ++i) {
+                clearVirtReg(tempUseOperands_[i]);
+            }
+            tempUseOperands_.clear();
 
-            // use our current mapping and actually replace and
-            // virtual register with its allocated physical registers
+            DEBUG(std::cerr << "\t\tassigning temporarily defined operands to "
+                  "registers:\n");
             for (unsigned i = 0, e = (*currentInstr_)->getNumOperands();
                  i != e; ++i) {
                 MachineOperand& op = (*currentInstr_)->getOperand(i);
-                if (op.isVirtualRegister()) {
+                if (op.isVirtualRegister() && !op.opIsUse()) {
                     unsigned virtReg = op.getAllocatedRegNum();
                     unsigned physReg = v2pMap_[virtReg];
-                    assert(physReg && "should not have virtual registers here");
+                    if (!physReg) {
+                        physReg = getFreeTempPhysReg(virtReg);
+                    }
+                    if (op.opIsDefAndUse()) {
+                        loadVirt2PhysReg(virtReg, physReg);
+                    }
+                    else {
+                        assignVirt2PhysReg(virtReg, physReg);
+                    }
+                    tempDefOperands_.push_back(virtReg);
                     (*currentInstr_)->SetMachineOperandReg(i, physReg);
                 }
             }
 
-            // if the instructions is a two address instruction:
-            //
-            //"a = b + c" but a and b must be the same register,
-            //insert "a = b" before it and make the original
-            //instruction "a = a + c")
 
-            if (tm_->getInstrInfo().isTwoAddrInstr(
-                    (*currentInstr_)->getOpcode())) {
+            // if the instruction is a two address instruction and the
+            // source operands are not identical we need to insert
+            // extra instructions.
+
+            unsigned opcode = (*currentInstr_)->getOpcode();
+            if (tm_->getInstrInfo().isTwoAddrInstr(opcode) &&
+                (*currentInstr_)->getOperand(0).getAllocatedRegNum() !=
+                (*currentInstr_)->getOperand(1).getAllocatedRegNum()) {
                 assert((*currentInstr_)->getOperand(1).isRegister() &&
                        (*currentInstr_)->getOperand(1).getAllocatedRegNum() &&
                        (*currentInstr_)->getOperand(1).opIsUse() &&
@@ -375,26 +367,62 @@
                     (*currentInstr_)->getOperand(0).getAllocatedRegNum();
                 unsigned regB =
                     (*currentInstr_)->getOperand(1).getAllocatedRegNum();
+                unsigned regC =
+                    ((*currentInstr_)->getNumOperands() > 2 &&
+                     (*currentInstr_)->getOperand(2).isRegister()) ?
+                    (*currentInstr_)->getOperand(2).getAllocatedRegNum() :
+                    0;
+
                 const TargetRegisterClass* rc = mri_->getRegClass(regA);
 
-                instrAdded_ += mri_->copyRegToReg(*currentMbb_,
-                                                  currentInstr_,
-                                                  regA,
-                                                  regB,
-                                                  rc);
-                tempUseOperands_.erase(remove(tempUseOperands_.begin(),
-                                              tempUseOperands_.end(),
-                                              regB),
-                                       tempUseOperands_.end());
-                (*currentInstr_)->SetMachineOperandReg(1, regA);
-            }
-            DEBUG(std::cerr << "\t\tspilling temporarily defined operands:\n");
-            for (unsigned i = 0, e = tempDefOperands_.size(); i != e; ++i) {
-                spillVirtReg(tempDefOperands_[i]);
+                // special case: "a = b op a". If b is a temporary
+                // reserved register rewrite as: "b = b op a; a = b"
+                // otherwise use a temporary reserved register t and
+                // rewrite as: "t = b; t = t op a; a = t"
+                if (regC && regA == regC) {
+                    // b is a temp reserved register
+                    if (find(reserved_.begin(), reserved_.end(),
+                             regB) != reserved_.end()) {
+                        (*currentInstr_)->SetMachineOperandReg(0, regB);
+                        ++currentInstr_;
+                        instrAdded_ += mri_->copyRegToReg(*currentMbb_,
+                                                          currentInstr_,
+                                                          regA,
+                                                          regB,
+                                                          rc);
+                        --currentInstr_;
+                    }
+                    // b is just a normal register
+                    else {
+                        unsigned tempReg = getFreeTempPhysReg(rc);
+                        assert (tempReg &&
+                                "no free temp reserved physical register?");
+                        instrAdded_ += mri_->copyRegToReg(*currentMbb_,
+                                                          currentInstr_,
+                                                          tempReg,
+                                                          regB,
+                                                          rc);
+                        (*currentInstr_)->SetMachineOperandReg(0, tempReg);
+                        (*currentInstr_)->SetMachineOperandReg(1, tempReg);
+                        ++currentInstr_;
+                        instrAdded_ += mri_->copyRegToReg(*currentMbb_,
+                                                          currentInstr_,
+                                                          regA,
+                                                          tempReg,
+                                                          rc);
+                        --currentInstr_;
+                    }
+                }
+                // "a = b op c" gets rewritten to "a = b; a = a op c"
+                else {
+                    instrAdded_ += mri_->copyRegToReg(*currentMbb_,
+                                                      currentInstr_,
+                                                      regA,
+                                                      regB,
+                                                      rc);
+                    (*currentInstr_)->SetMachineOperandReg(1, regA);
+                }
             }
-
-            DEBUG(std::cerr << "instruction[" << curIndex << "]: ";
-                  (*currentInstr_)->print(std::cerr, *tm_));
         }
 
         for (unsigned i = 0, e = p2vMap_.size(); i != e; ++i) {
@@ -406,38 +434,23 @@
     return true;
 }
 
-void RA::processInterval(unsigned curIndex)
+void RA::processActiveIntervals(Intervals::const_iterator cur)
 {
-    // liner scan algorithm
-    assert((currentInterval_ == li_->end() ||
-            currentInterval_->start() >= curIndex)
-           && "skipping intervals?");
-
-    if (currentInterval_ != li_->end() &&
-        currentInterval_->start() == curIndex) {
-        DEBUG(std::cerr << "\t\tprocessing current interval:\n");
-        unsigned virtReg = currentInterval_->reg;
-        unsigned physReg = getFreePhysReg(virtReg);
-
-        if (!physReg) {
-            spillInterval();
-            physReg = getFreePhysReg(virtReg);
-        }
-        allocateVirt2PhysReg(virtReg, physReg);
-        active_.push_back(&*currentInterval_);
-        ++currentInterval_;
-    }
-}
-
-void RA::processActiveIntervals(unsigned curIndex)
-{
-    DEBUG(std::cerr << "\t\tprocessing active intervals:\n");
+    DEBUG(std::cerr << "\tprocessing active intervals:\n");
     for (IntervalPtrs::iterator i = active_.begin(); i != active_.end();) {
-        unsigned virtReg = (*i)->reg;
-        // remove expired intervals
-        if ((*i)->expired(curIndex)) {
-            DEBUG(std::cerr << "\t\t\tinterval " << **i << " expired\n");
-            clearVirtReg(virtReg);
+        unsigned reg = (*i)->reg;
+        // remove expired intervals. we expire earlier because this if
+        // an interval expires this is going to be the last use. in
+        // this case we can reuse the register for a def in the same
+        // instruction
+        if ((*i)->expired(cur->start() + 1)) {
+            DEBUG(std::cerr << "\t\tinterval " << **i << " expired\n");
+            if (reg < MRegisterInfo::FirstVirtualRegister) {
+                clearReservedPhysReg(reg);
+            }
+            else {
+                p2vMap_[v2pMap_[reg]] = 0;
+            }
             // remove interval from active
             i = active_.erase(i);
         }
@@ -456,9 +469,9 @@
     }
 }
 
-void RA::processInactiveIntervals(unsigned curIndex)
+void RA::processInactiveIntervals(Intervals::const_iterator cur)
 {
-//     DEBUG(std::cerr << "\t\tprocessing inactive intervals:\n");
+//     DEBUG(std::cerr << "\tprocessing inactive intervals:\n");
 //     for (IntervalPtrs::iterator i = inactive_.begin(); i != inactive_.end();) {
 //         unsigned virtReg = (*i)->reg;
 //         // remove expired intervals
@@ -483,36 +496,94 @@
 //     }
 }
 
-void RA::spillInterval()
+void RA::assignStackSlotAtInterval(Intervals::const_iterator cur)
 {
-    DEBUG(std::cerr << "\t\tspilling at interval "<< *currentInterval_<< ":\n");
+    DEBUG(std::cerr << "\t\tassigning stack slot at interval "
+          << *cur << ":\n");
     assert(!active_.empty() &&
            "active set cannot be empty when choosing a register to spill");
-    IntervalPtrs::iterator lastEnd = active_.begin();
-    for (IntervalPtrs::iterator i = lastEnd + 1, e = active_.end();
+    const TargetRegisterClass* rcCur =
+        mf_->getSSARegMap()->getRegClass(cur->reg);
+
+    // find the interval for a virtual register that ends last in
+    // active and belongs to the same register class as the current
+    // interval
+    IntervalPtrs::iterator lastEndActive = active_.begin();
+    for (IntervalPtrs::iterator e = active_.end();
+         lastEndActive != e; ++lastEndActive) {
+        if ((*lastEndActive)->reg >= MRegisterInfo::FirstVirtualRegister) {
+            const TargetRegisterClass* rc =
+                mri_->getRegClass(v2pMap_[(*lastEndActive)->reg]);
+            if (rcCur == rc) {
+                break;
+            }
+        }
+    }
+    for (IntervalPtrs::iterator i = lastEndActive, e = active_.end();
          i != e; ++i) {
-        if ((*lastEnd)->end() < (*i)->end()) {
-            lastEnd = i;
+        if ((*i)->reg >= MRegisterInfo::FirstVirtualRegister) {
+            const TargetRegisterClass* rc =
+                mri_->getRegClass(v2pMap_[(*i)->reg]);
+            if (rcCur == rc &&
+                (*lastEndActive)->end() < (*i)->end()) {
+                lastEndActive = i;
+            }
+        }
+    }
+
+    // find the interval for a virtual register that ends last in
+    // inactive and belongs to the same register class as the current
+    // interval
+    IntervalPtrs::iterator lastEndInactive = inactive_.begin();
+    for (IntervalPtrs::iterator e = inactive_.end();
+         lastEndInactive != e; ++lastEndInactive) {
+        if ((*lastEndInactive)->reg >= MRegisterInfo::FirstVirtualRegister) {
+            const TargetRegisterClass* rc =
+                mri_->getRegClass(v2pMap_[(*lastEndInactive)->reg]);
+            if (rcCur == rc) {
+                break;
+            }
         }
     }
-    bool inInactive = false;
-    for (IntervalPtrs::iterator i = inactive_.begin(), e = inactive_.end();
+    for (IntervalPtrs::iterator i = lastEndInactive, e = inactive_.end();
          i != e; ++i) {
-        if ((*lastEnd)->end() < (*i)->end()) {
-            lastEnd = i;
-            inInactive = true;
+        if ((*i)->reg >= MRegisterInfo::FirstVirtualRegister) {
+            const TargetRegisterClass* rc =
+                mri_->getRegClass(v2pMap_[(*i)->reg]);
+            if (rcCur == rc &&
+                (*lastEndInactive)->end() < (*i)->end()) {
+                lastEndInactive = i;
+            }
         }
     }
 
-    DEBUG(std::cerr << "\t\t\tspilling interval " << **lastEnd << "\n");
-    // spill last in active and inactive
-    unsigned virtReg = (*lastEnd)->reg;
-    spillVirtReg(virtReg);
-    if (inInactive) {
-        inactive_.erase(lastEnd);
+    unsigned lastEndActiveInactive = 0;
+    if (lastEndActive != active_.end() &&
+        lastEndActiveInactive < (*lastEndActive)->end()) {
+        lastEndActiveInactive = (*lastEndActive)->end();
+    }
+    if (lastEndInactive != inactive_.end() &&
+        lastEndActiveInactive < (*lastEndInactive)->end()) {
+        lastEndActiveInactive = (*lastEndInactive)->end();
+    }
+
+    if (lastEndActiveInactive > cur->end()) {
+        if (lastEndInactive == inactive_.end() ||
+            (*lastEndActive)->end() > (*lastEndInactive)->end()) {
+            assignVirt2StackSlot((*lastEndActive)->reg);
+            active_.erase(lastEndActive);
+        }
+        else {
+            assignVirt2StackSlot((*lastEndInactive)->reg);
+            inactive_.erase(lastEndInactive);
+        }
+        unsigned physReg = getFreePhysReg(cur->reg);
+        assert(physReg && "no free physical register after spill?");
+        assignVirt2PhysReg(cur->reg, physReg);
+        active_.push_back(&*cur);
     }
     else {
-        active_.erase(lastEnd);
+        assignVirt2StackSlot(cur->reg);
     }
 }
 
@@ -559,12 +630,17 @@
         }
     }
 
+    // if it is one of the reserved registers it is still not free
+    if (find(reserved_.begin(), reserved_.end(), physReg) != reserved_.end()) {
+        return false;
+    }
+
     return true;
 }
 
 unsigned RA::getFreePhysReg(unsigned virtReg)
 {
-    DEBUG(std::cerr << "\t\t\tgetting free physical register: ");
+    DEBUG(std::cerr << "\t\tgetting free physical register: ");
     const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
     TargetRegisterClass::iterator reg = rc->allocation_order_begin(*mf_);
     TargetRegisterClass::iterator regEnd = rc->allocation_order_end(*mf_);
@@ -581,17 +657,51 @@
     return 0;
 }
 
-void RA::allocateVirt2PhysReg(unsigned virtReg, unsigned physReg)
+bool RA::tempPhysRegAvailable(unsigned physReg)
 {
-    assert(physRegAvailable(physReg) &&
+    assert(find(reserved_.begin(), reserved_.end(), physReg) != reserved_.end()
+           && "cannot call this method with a non reserved temp register");
+
+    if (p2vMap_[physReg]) {
+        return false;
+    }
+
+    // if it aliases other registers it is still not free
+    for (const unsigned* as = mri_->getAliasSet(physReg); *as; ++as) {
+        if (p2vMap_[*as]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+unsigned RA::getFreeTempPhysReg(const TargetRegisterClass* rc)
+{
+    DEBUG(std::cerr << "\t\tgetting free temporary physical register: ");
+
+    for (Regs::const_iterator
+             reg = reserved_.begin(), regEnd = reserved_.end();
+         reg != regEnd; ++reg) {
+        if (rc == mri_->getRegClass(*reg) && tempPhysRegAvailable(*reg)) {
+            assert(*reg != 0 && "Cannot use register!");
+            DEBUG(std::cerr << mri_->getName(*reg) << '\n');
+            return *reg; // Found an unused register!
+        }
+    }
+    assert(0 && "no free temporary physical register?");
+    return 0;
+}
+
+void RA::assignVirt2PhysReg(unsigned virtReg, unsigned physReg)
+{
+    assert((physRegAvailable(physReg) ||
+            find(reserved_.begin(),
+                 reserved_.end(),
+                 physReg) != reserved_.end()) &&
            "attempt to allocate to a not available physical register");
-    Virt2PhysMap::iterator it = v2pMap_.find(virtReg);
-    bool inserted = v2pMap_.insert(std::make_pair(virtReg, physReg)).second;
-    assert(inserted &&
-           "attempt to allocate an already allocated virtual register");
+    v2pMap_[virtReg] = physReg;
     p2vMap_[physReg] = virtReg;
-    DEBUG(std::cerr << "\t\t\t\tallocated register " << virtReg << " to "
-          << mri_->getName(physReg) << '\n');
 }
 
 void RA::clearVirtReg(unsigned virtReg)
@@ -600,14 +710,28 @@
     assert(it != v2pMap_.end() &&
            "attempting to clear a not allocated virtual register");
     unsigned physReg = it->second;
-    assert(p2vMap_[physReg] == virtReg &&
-           "virt2physMap and phys2virtMap mismatch");
     p2vMap_[physReg] = 0;
-    v2pMap_.erase(it);
-    DEBUG(std::cerr << "\t\t\t\tcleared register " << mri_->getName(physReg)
+    v2pMap_[virtReg] = 0; // this marks that this virtual register
+                          // lives on the stack
+    DEBUG(std::cerr << "\t\t\tcleared register " << mri_->getName(physReg)
           << "\n");
 }
 
+void RA::assignVirt2StackSlot(unsigned virtReg)
+{
+    const TargetRegisterClass* rc = mf_->getSSARegMap()->getRegClass(virtReg);
+    int frameIndex = mf_->getFrameInfo()->CreateStackObject(rc);
+
+    bool inserted = v2ssMap_.insert(std::make_pair(virtReg, frameIndex)).second;
+    assert(inserted &&
+           "attempt to assign stack slot to already assigned register?");
+    // if the virtual register was previously assigned clear the mapping
+    // and free the virtual register
+    if (v2pMap_.find(virtReg) != v2pMap_.end()) {
+        clearVirtReg(virtReg);
+    }
+}
+
 int RA::findOrCreateStackSlot(unsigned virtReg)
 {
     // use lower_bound so that we can do a possibly O(1) insert later
@@ -645,15 +769,7 @@
     ++numReloaded;
     instrAdded_ += mri_->loadRegFromStackSlot(*currentMbb_, currentInstr_,
                                               physReg, frameIndex, rc);
-    allocateVirt2PhysReg(virtReg, physReg);
-}
-
-unsigned RA::getInstructionIndex() const
-{
-    Mbb2MiIndexMap::const_iterator it = mbb2miiMap_->find(currentMbb_);
-    assert(it != mbb2miiMap_->end() &&
-           "no MachineInstruction index for basic block?");
-    return it->second + (currentInstr_ - currentMbb_->begin()) - instrAdded_;
+    assignVirt2PhysReg(virtReg, physReg);
 }
 
 FunctionPass* llvm::createLinearScanRegisterAllocator() {


Index: llvm/lib/CodeGen/LiveIntervals.cpp
diff -u llvm/lib/CodeGen/LiveIntervals.cpp:1.1.2.10 llvm/lib/CodeGen/LiveIntervals.cpp:1.1.2.11
--- llvm/lib/CodeGen/LiveIntervals.cpp:1.1.2.10	Thu Nov 13 03:48:51 2003
+++ llvm/lib/CodeGen/LiveIntervals.cpp	Tue Nov 18 03:44:30 2003
@@ -65,8 +65,6 @@
     r2iMap_.clear();
     r2iMap_.clear();
     intervals_.clear();
-    mii2mbbMap_.clear();
-    mbb2miiMap_.clear();
 
     // mark allocatable registers
     allocatableRegisters_.resize(MRegisterInfo::FirstVirtualRegister);
@@ -91,16 +89,11 @@
         bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
                                                            entry.first)).second;
         assert(inserted && "multiple index -> MachineBasicBlock");
-        inserted = mbb2miiMap_.insert(std::make_pair(&*mbb, miIndex)).second;
-        assert(inserted && "multiple MachineBasicBlock -> index mappings");
 
         for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
              mi != miEnd; ++mi) {
             inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second;
             assert(inserted && "multiple MachineInstr -> index mappings");
-            inserted =
-                mii2mbbMap_.insert(std::make_pair(miIndex, &*mbb)).second;
-            assert(inserted && "multiple index -> MachineBasicBlock mappings");
             ++miIndex;
         }
     }
@@ -284,10 +277,10 @@
                   instr->print(std::cerr, *tm_););
 
             // handle implicit defs
-//             for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
-//                 unsigned physReg = *id;
-//                 handlePhysicalRegisterDef(mbb, mi, physReg);
-//             }
+            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
+                unsigned physReg = *id;
+                handlePhysicalRegisterDef(mbb, mi, physReg);
+            }
 
             // handle explicit defs
             for (int i = instr->getNumOperands() - 1; i >= 0; --i) {





More information about the llvm-commits mailing list