mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 18:29:46 +00:00
1. LiveIntervals now implement a 4 slot per instruction model. Load, Use, Def and a Store slot. This is required in order to correctly represent caller saved register clobbering on function calls, register reuse in the same instruction (def resues last use) and also spill code added later by the allocator. The previous representation (2 slots per instruction) was insufficient and as a result was causing subtle bugs. 2. Fixes in spill code generation. This was the major cause of failures in the test suite. 3. Linear scan now has core support for folding memory operands. This is untested and not enabled (the live interval update function does not attempt to fold loads/stores in instructions). 4. Lots of improvements in the debugging output of both live intervals and linear scan. Give it a try... it is beautiful :-) In summary the above fixes all the issues with the recent reserved register elimination changes and get the allocator very close to the next big step: folding memory operands. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11654 91177308-0d34-0410-b5e6-96231b3b80d8
211 lines
6.9 KiB
C++
211 lines
6.9 KiB
C++
//===-- llvm/CodeGen/LiveInterval.h - Live Interval Analysis ----*- C++ -*-===//
|
|
//
|
|
// 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.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the LiveInterval analysis pass. Given some
|
|
// numbering of each the machine instructions (in this implemention
|
|
// depth-first order) an interval [i, j) is said to be a live interval
|
|
// for register v if there is no instruction with number j' > j such
|
|
// that v is live at j' abd there is no instruction with number i' < i
|
|
// such that v is live at i'. In this implementation intervals can
|
|
// have holes, i.e. an interval might look like [1,20), [50,65),
|
|
// [1000,1001)
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CODEGEN_LIVEINTERVALS_H
|
|
#define LLVM_CODEGEN_LIVEINTERVALS_H
|
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include <list>
|
|
|
|
namespace llvm {
|
|
|
|
class LiveVariables;
|
|
class MRegisterInfo;
|
|
|
|
class LiveIntervals : public MachineFunctionPass
|
|
{
|
|
public:
|
|
struct Interval {
|
|
typedef std::pair<unsigned, unsigned> Range;
|
|
typedef std::vector<Range> Ranges;
|
|
unsigned reg; // the register of this interval
|
|
float weight; // weight of this interval (number of uses
|
|
// * 10^loopDepth)
|
|
Ranges ranges; // the ranges in which this register is live
|
|
|
|
Interval(unsigned r);
|
|
|
|
bool empty() const { return ranges.empty(); }
|
|
|
|
bool spilled() const;
|
|
|
|
unsigned start() const {
|
|
assert(!empty() && "empty interval for register");
|
|
return ranges.front().first;
|
|
}
|
|
|
|
unsigned end() const {
|
|
assert(!empty() && "empty interval for register");
|
|
return ranges.back().second;
|
|
}
|
|
|
|
bool expiredAt(unsigned index) const {
|
|
return end() <= (index + 1);
|
|
}
|
|
|
|
bool liveAt(unsigned index) const;
|
|
|
|
bool overlaps(const Interval& other) const;
|
|
|
|
void addRange(unsigned start, unsigned end);
|
|
|
|
void join(const Interval& other);
|
|
|
|
private:
|
|
Ranges::iterator mergeRangesForward(Ranges::iterator it);
|
|
|
|
Ranges::iterator mergeRangesBackward(Ranges::iterator it);
|
|
};
|
|
|
|
struct StartPointComp {
|
|
bool operator()(const Interval& lhs, const Interval& rhs) {
|
|
return lhs.ranges.front().first < rhs.ranges.front().first;
|
|
}
|
|
};
|
|
|
|
struct EndPointComp {
|
|
bool operator()(const Interval& lhs, const Interval& rhs) {
|
|
return lhs.ranges.back().second < rhs.ranges.back().second;
|
|
}
|
|
};
|
|
|
|
typedef std::list<Interval> Intervals;
|
|
|
|
private:
|
|
MachineFunction* mf_;
|
|
const TargetMachine* tm_;
|
|
const MRegisterInfo* mri_;
|
|
MachineBasicBlock* currentMbb_;
|
|
MachineBasicBlock::iterator currentInstr_;
|
|
LiveVariables* lv_;
|
|
|
|
typedef std::map<unsigned, MachineBasicBlock*> MbbIndex2MbbMap;
|
|
MbbIndex2MbbMap mbbi2mbbMap_;
|
|
|
|
typedef std::map<MachineInstr*, unsigned> Mi2IndexMap;
|
|
Mi2IndexMap mi2iMap_;
|
|
|
|
typedef std::vector<MachineInstr*> Index2MiMap;
|
|
Index2MiMap i2miMap_;
|
|
|
|
typedef std::map<unsigned, Intervals::iterator> Reg2IntervalMap;
|
|
Reg2IntervalMap r2iMap_;
|
|
|
|
typedef std::map<unsigned, unsigned> Reg2RegMap;
|
|
Reg2RegMap r2rMap_;
|
|
|
|
Intervals intervals_;
|
|
|
|
public:
|
|
struct InstrSlots
|
|
{
|
|
enum {
|
|
LOAD = 0,
|
|
USE = 1,
|
|
DEF = 2,
|
|
STORE = 3,
|
|
NUM = 4,
|
|
};
|
|
};
|
|
|
|
static unsigned getBaseIndex(unsigned index) {
|
|
return index - (index % 4);
|
|
}
|
|
static unsigned getLoadIndex(unsigned index) {
|
|
return getBaseIndex(index) + InstrSlots::LOAD;
|
|
}
|
|
static unsigned getUseIndex(unsigned index) {
|
|
return getBaseIndex(index) + InstrSlots::USE;
|
|
}
|
|
static unsigned getDefIndex(unsigned index) {
|
|
return getBaseIndex(index) + InstrSlots::DEF;
|
|
}
|
|
static unsigned getStoreIndex(unsigned index) {
|
|
return getBaseIndex(index) + InstrSlots::STORE;
|
|
}
|
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
|
virtual void releaseMemory();
|
|
|
|
/// runOnMachineFunction - pass entry point
|
|
virtual bool runOnMachineFunction(MachineFunction&);
|
|
|
|
Interval& getInterval(unsigned reg) {
|
|
assert(r2iMap_.count(reg)&& "Interval does not exist for register");
|
|
return *r2iMap_.find(reg)->second;
|
|
}
|
|
|
|
/// getInstructionIndex - returns the base index of instr
|
|
unsigned getInstructionIndex(MachineInstr* instr) const;
|
|
|
|
/// getInstructionFromIndex - given an index in any slot of an
|
|
/// instruction return a pointer the instruction
|
|
MachineInstr* getInstructionFromIndex(unsigned index) const;
|
|
|
|
Intervals& getIntervals() { return intervals_; }
|
|
|
|
void updateSpilledInterval(Interval& i, int slot);
|
|
|
|
private:
|
|
/// computeIntervals - compute live intervals
|
|
void computeIntervals();
|
|
|
|
/// joinIntervals - join compatible live intervals
|
|
void joinIntervals();
|
|
|
|
/// handleRegisterDef - update intervals for a register def
|
|
/// (calls handlePhysicalRegisterDef and
|
|
/// handleVirtualRegisterDef)
|
|
void handleRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg);
|
|
|
|
/// handleVirtualRegisterDef - update intervals for a virtual
|
|
/// register def
|
|
void handleVirtualRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg);
|
|
|
|
/// handlePhysicalRegisterDef - update intervals for a
|
|
/// physical register def
|
|
void handlePhysicalRegisterDef(MachineBasicBlock* mbb,
|
|
MachineBasicBlock::iterator mi,
|
|
unsigned reg);
|
|
|
|
bool overlapsAliases(const Interval& lhs, const Interval& rhs) const;
|
|
|
|
/// rep - returns the representative of this register
|
|
unsigned rep(unsigned reg);
|
|
|
|
void printRegName(unsigned reg) const;
|
|
};
|
|
|
|
inline bool operator==(const LiveIntervals::Interval& lhs,
|
|
const LiveIntervals::Interval& rhs) {
|
|
return lhs.reg == rhs.reg;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os,
|
|
const LiveIntervals::Interval& li);
|
|
|
|
} // End llvm namespace
|
|
|
|
#endif
|