//
//===----------------------------------------------------------------------===//
+#include "AllocInfo.h"
+#include "IGNode.h"
#include "PhyRegAlloc.h"
#include "RegAllocCommon.h"
#include "RegClass.h"
-#include "IGNode.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/iOther.h"
+#include "llvm/Module.h"
+#include "llvm/Type.h"
+#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/FunctionLiveVarInfo.h"
#include "llvm/CodeGen/InstrSelection.h"
+#include "llvm/CodeGen/MachineCodeForInstruction.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineInstrAnnot.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineFunctionInfo.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Type.h"
-#include "llvm/iOther.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Constants.h"
-#include "llvm/Module.h"
#include "llvm/Support/InstIterator.h"
-#include "Support/STLExtras.h"
-#include "Support/SetOperations.h"
+#include "llvm/Target/TargetInstrInfo.h"
#include "Support/CommandLine.h"
+#include "Support/SetOperations.h"
+#include "Support/STLExtras.h"
#include <cmath>
RegAllocDebugLevel_t DEBUG_RA;
+/// The reoptimizer wants to be able to grovel through the register
+/// allocator's state after it has done its job. This is a hack.
+///
+PhyRegAlloc::SavedStateMapTy ExportedFnAllocState;
+const bool SaveStateToModule = true;
+
static cl::opt<RegAllocDebugLevel_t, true>
DRA_opt("dregalloc", cl::Hidden, cl::location(DEBUG_RA),
cl::desc("enable register allocation debugging information"),
}
-namespace {
- /// AllocInfo - Structure representing one instruction's
- /// operand's-worth of register allocation state. We create tables
- /// made out of these data structures to generate mapping information
- /// for this register allocator. (FIXME: This might move to a header
- /// file at some point.)
- ///
- struct AllocInfo {
- unsigned Instruction;
- unsigned Operand;
- unsigned AllocState;
- int Placement;
- AllocInfo (unsigned Instruction_, unsigned Operand_,
- unsigned AllocState_, int Placement_) :
- Instruction (Instruction_), Operand (Operand_),
- AllocState (AllocState_), Placement (Placement_) { }
- /// getConstantType - Return a StructType representing an AllocInfo
- /// object.
- ///
- static StructType *getConstantType () {
- std::vector<const Type *> TV;
- TV.push_back (Type::UIntTy);
- TV.push_back (Type::UIntTy);
- TV.push_back (Type::UIntTy);
- TV.push_back (Type::IntTy);
- return StructType::get (TV);
- }
- /// toConstant - Convert this AllocInfo into an LLVM Constant of type
- /// getConstantType(), and return the Constant.
- ///
- Constant *toConstant () const {
- StructType *ST = getConstantType ();
- std::vector<Constant *> CV;
- CV.push_back (ConstantUInt::get (Type::UIntTy, Instruction));
- CV.push_back (ConstantUInt::get (Type::UIntTy, Operand));
- CV.push_back (ConstantUInt::get (Type::UIntTy, AllocState));
- CV.push_back (ConstantSInt::get (Type::IntTy, Placement));
- return ConstantStruct::get (ST, CV);
- }
- };
+void PhyRegAlloc::saveStateForValue (std::vector<AllocInfo> &state,
+ const Value *V, unsigned Insn, int Opnd) {
+ LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap ()->find (V);
+ LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap ()->end ();
+ AllocInfo::AllocStateTy AllocState = AllocInfo::NotAllocated;
+ int Placement = -1;
+ if ((HMI != HMIEnd) && HMI->second) {
+ LiveRange *L = HMI->second;
+ assert ((L->hasColor () || L->isMarkedForSpill ())
+ && "Live range exists but not colored or spilled");
+ if (L->hasColor ()) {
+ AllocState = AllocInfo::Allocated;
+ Placement = MRI.getUnifiedRegNum (L->getRegClassID (),
+ L->getColor ());
+ } else if (L->isMarkedForSpill ()) {
+ AllocState = AllocInfo::Spilled;
+ assert (L->hasSpillOffset ()
+ && "Live range marked for spill but has no spill offset");
+ Placement = L->getSpillOffFromFP ();
+ }
+ }
+ state.push_back (AllocInfo (Insn, Opnd, AllocState, Placement));
}
+
/// Save the global register allocation decisions made by the register
/// allocator so that they can be accessed later (sort of like "poor man's
/// debug info").
///
void PhyRegAlloc::saveState () {
- std::vector<Constant *> &state = FnAllocState[Fn];
+ std::vector<AllocInfo> &state = FnAllocState[Fn];
unsigned Insn = 0;
- LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap ()->end ();
- for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II != IE; ++II)
+ for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II!=IE; ++II){
+ saveStateForValue (state, (*II), Insn, -1);
for (unsigned i = 0; i < (*II)->getNumOperands (); ++i) {
const Value *V = (*II)->getOperand (i);
- // Don't worry about it unless it's something whose reg. we'll need.
- if (!isa<Argument> (V) && !isa<Instruction> (V))
- continue;
- LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap ()->find (V);
- static const unsigned NotAllocated = 0, Allocated = 1, Spilled = 2;
- unsigned AllocState = NotAllocated;
- int Placement = -1;
- if ((HMI != HMIEnd) && HMI->second) {
- LiveRange *L = HMI->second;
- assert ((L->hasColor () || L->isMarkedForSpill ())
- && "Live range exists but not colored or spilled");
- if (L->hasColor()) {
- AllocState = Allocated;
- Placement = MRI.getUnifiedRegNum (L->getRegClassID (),
- L->getColor ());
- } else if (L->isMarkedForSpill ()) {
- AllocState = Spilled;
- assert (L->hasSpillOffset ()
- && "Live range marked for spill but has no spill offset");
- Placement = L->getSpillOffFromFP ();
- }
- }
- state.push_back (AllocInfo (Insn, i, AllocState,
- Placement).toConstant ());
+ // Don't worry about it unless it's something whose reg. we'll need.
+ if (!isa<Argument> (V) && !isa<Instruction> (V))
+ continue;
+ saveStateForValue (state, V, Insn, i);
}
+ ++Insn;
+ }
}
+
/// Check the saved state filled in by saveState(), and abort if it looks
-/// wrong. Only used when debugging.
+/// wrong. Only used when debugging. FIXME: Currently it just prints out
+/// the state, which isn't quite as useful.
///
void PhyRegAlloc::verifySavedState () {
- /// not yet implemented
+ std::vector<AllocInfo> &state = FnAllocState[Fn];
+ unsigned Insn = 0;
+ for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II!=IE; ++II) {
+ const Instruction *I = *II;
+ MachineCodeForInstruction &Instrs = MachineCodeForInstruction::get (I);
+ std::cerr << "Instruction:\n" << " " << *I << "\n"
+ << "MachineCodeForInstruction:\n";
+ for (unsigned i = 0, n = Instrs.size (); i != n; ++i)
+ std::cerr << " " << *Instrs[i] << "\n";
+ std::cerr << "FnAllocState:\n";
+ for (unsigned i = 0; i < state.size (); ++i) {
+ AllocInfo &S = state[i];
+ if (Insn == S.Instruction) {
+ std::cerr << " (Instruction " << S.Instruction
+ << ", Operand " << S.Operand
+ << ", AllocState " << S.allocStateToString ()
+ << ", Placement " << S.Placement << ")\n";
+ }
+ }
+ std::cerr << "----------\n";
+ ++Insn;
+ }
}
+
+/// Finish the job of saveState(), by collapsing FnAllocState into an LLVM
+/// Constant and stuffing it inside the Module. (NOTE: Soon, there will be
+/// other, better ways of storing the saved state; this one is cumbersome and
+/// does not work well with the JIT.)
+///
bool PhyRegAlloc::doFinalization (Module &M) {
if (!SaveRegAllocState)
return false; // Nothing to do here, unless we're saving state.
+ // If saving state into the module, just copy new elements to the
+ // correct global.
+ if (!SaveStateToModule) {
+ ExportedFnAllocState = FnAllocState;
+ // FIXME: should ONLY copy new elements in FnAllocState
+ return false;
+ }
+
// Convert FnAllocState to a single Constant array and add it
// to the Module.
ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), 0);
std::vector<Constant *> allstate;
for (Module::iterator I = M.begin (), E = M.end (); I != E; ++I) {
Function *F = I;
+ if (F->isExternal ()) continue;
if (FnAllocState.find (F) == FnAllocState.end ()) {
allstate.push_back (ConstantPointerNull::get (PT));
} else {
- std::vector<Constant *> &state = FnAllocState[F];
+ std::vector<AllocInfo> &state = FnAllocState[F];
// Convert state into an LLVM ConstantArray, and put it in a
// ConstantStruct (named S) along with its size.
- unsigned Size = state.size ();
+ std::vector<Constant *> stateConstants;
+ for (unsigned i = 0, s = state.size (); i != s; ++i)
+ stateConstants.push_back (state[i].toConstant ());
+ unsigned Size = stateConstants.size ();
ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), Size);
std::vector<const Type *> TV;
TV.push_back (Type::UIntTy);
StructType *ST = StructType::get (TV);
std::vector<Constant *> CV;
CV.push_back (ConstantUInt::get (Type::UIntTy, Size));
- CV.push_back (ConstantArray::get (AT, state));
+ CV.push_back (ConstantArray::get (AT, stateConstants));
Constant *S = ConstantStruct::get (ST, CV);
GlobalVariable *GV =
GlobalValue::InternalLinkage, S,
F->getName () + ".regAllocState", &M);
- // Have: { uint, [Size x { uint, uint, uint, int }] } *
- // Cast it to: { uint, [0 x { uint, uint, uint, int }] } *
+ // Have: { uint, [Size x { uint, int, uint, int }] } *
+ // Cast it to: { uint, [0 x { uint, int, uint, int }] } *
Constant *CE = ConstantExpr::getCast (ConstantPointerRef::get (GV), PT);
allstate.push_back (CE);
}
unsigned Size = allstate.size ();
// Final structure type is:
- // { uint, [Size x { uint, [0 x { uint, uint, uint, int }] } *] }
+ // { uint, [Size x { uint, [0 x { uint, int, uint, int }] } *] }
std::vector<const Type *> TV2;
TV2.push_back (Type::UIntTy);
ArrayType *AT2 = ArrayType::get (PT, Size);
std::vector<Constant *> CV2;
CV2.push_back (ConstantUInt::get (Type::UIntTy, Size));
CV2.push_back (ConstantArray::get (AT2, allstate));
- new GlobalVariable (ST2, true, GlobalValue::InternalLinkage,
+ new GlobalVariable (ST2, true, GlobalValue::ExternalLinkage,
ConstantStruct::get (ST2, CV2), "_llvm_regAllocState",
&M);
return false; // No error.