X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FMachineFunction.cpp;h=02646de18fd1610babe3205cfe12f3b1359e116a;hb=e165a78551a91d8420cd8f074d97701e8788f8b5;hp=8e1a80b37ecf032532ade5cdb71f15bdb398b58c;hpb=89e2da034a02cd33b306b59dbbf607650cca1c4c;p=oota-llvm.git diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 8e1a80b37ec..02646de18fd 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -1,315 +1,420 @@ -//===-- MachineCodeForMethod.cpp --------------------------------------------=// -// -// Purpose: -// Collect native machine code information for a method. -// This allows target-specific information about the generated code -// to be stored with each method. +//===-- MachineFunction.cpp -----------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// +// +// Collect native machine code information for a function. This allows +// target-specific information about the generated code to be stored with each +// function. +// //===----------------------------------------------------------------------===// -#include "llvm/CodeGen/MachineCodeForMethod.h" -#include "llvm/CodeGen/MachineInstr.h" // For debug output +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/SSARegMap.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/MachineFrameInfo.h" -#include "llvm/Target/MachineCacheInfo.h" -#include "llvm/Method.h" -#include "llvm/BasicBlock.h" -#include "llvm/iOther.h" -#include +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Function.h" +#include "llvm/Instructions.h" +#include "llvm/Support/LeakDetector.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Config/config.h" +#include #include +#include -const int INVALID_FRAME_OFFSET = INT_MAX; // std::numeric_limits::max(); +using namespace llvm; -static AnnotationID MCFM_AID( - AnnotationManager::getID("CodeGen::MachineCodeForMethod")); +static AnnotationID MF_AID( + AnnotationManager::getID("CodeGen::MachineCodeForFunction")); -// The next two methods are used to construct and to retrieve -// the MachineCodeForMethod object for the given method. -// construct() -- Allocates and initializes for a given method and target -// get() -- Returns a handle to the object. -// This should not be called before "construct()" -// for a given Method. -// -MachineCodeForMethod& -MachineCodeForMethod::construct(const Method *M, const TargetMachine &Tar) -{ - assert(M->getAnnotation(MCFM_AID) == 0 && - "Object already exists for this method!"); - MachineCodeForMethod* mcInfo = new MachineCodeForMethod(M, Tar); - M->addAnnotation(mcInfo); - return *mcInfo; -} -void -MachineCodeForMethod::destruct(const Method *M) -{ - bool Deleted = M->deleteAnnotation(MCFM_AID); - assert(Deleted && "Machine code did not exist for method!"); +namespace { + struct Printer : public MachineFunctionPass { + std::ostream *OS; + const std::string Banner; + + Printer (std::ostream *_OS, const std::string &_Banner) : + OS (_OS), Banner (_Banner) { } + + const char *getPassName() const { return "MachineFunction Printer"; } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + bool runOnMachineFunction(MachineFunction &MF) { + (*OS) << Banner; + MF.print (*OS); + return false; + } + }; } -MachineCodeForMethod& -MachineCodeForMethod::get(const Method* method) -{ - MachineCodeForMethod* mc = (MachineCodeForMethod*) - method->getAnnotation(MCFM_AID); - assert(mc && "Call construct() method first to allocate the object"); - return *mc; +/// Returns a newly-created MachineFunction Printer pass. The default output +/// stream is std::cerr; the default banner is empty. +/// +FunctionPass *llvm::createMachineFunctionPrinterPass(std::ostream *OS, + const std::string &Banner){ + return new Printer(OS, Banner); } -static unsigned -ComputeMaxOptionalArgsSize(const TargetMachine& target, const Method* method) -{ - const MachineFrameInfo& frameInfo = target.getFrameInfo(); - - unsigned int maxSize = 0; - - for (Method::const_iterator MI=method->begin(), ME=method->end(); - MI != ME; ++MI) - { - const BasicBlock *BB = *MI; - for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) - if (CallInst *callInst = dyn_cast(*I)) - { - unsigned int numOperands = callInst->getNumOperands() - 1; - int numExtra = (int) numOperands - frameInfo.getNumFixedOutgoingArgs(); - if (numExtra <= 0) - continue; - - unsigned int sizeForThisCall; - if (frameInfo.argsOnStackHaveFixedSize()) - { - int argSize = frameInfo.getSizeOfEachArgOnStack(); - sizeForThisCall = numExtra * (unsigned) argSize; - } - else - { - assert(0 && "UNTESTED CODE: Size per stack argument is not fixed on this architecture: use actual arg sizes to compute MaxOptionalArgsSize"); - sizeForThisCall = 0; - for (unsigned i=0; i < numOperands; ++i) - sizeForThisCall += target.findOptimalStorageSize(callInst-> - getOperand(i)->getType()); - } - - if (maxSize < sizeForThisCall) - maxSize = sizeForThisCall; - } +namespace { + struct Deleter : public MachineFunctionPass { + const char *getPassName() const { return "Machine Code Deleter"; } + + bool runOnMachineFunction(MachineFunction &MF) { + // Delete the annotation from the function now. + MachineFunction::destruct(MF.getFunction()); + return true; } - - return maxSize; + }; } -// Align data larger than one L1 cache line on L1 cache line boundaries. -// Align all smaller data on the next higher 2^x boundary (4, 8, ...). -// -// THIS FUNCTION HAS BEEN COPIED FROM EMITASSEMBLY.CPP AND -// SHOULD BE USED DIRECTLY THERE -// -inline unsigned int -SizeToAlignment(unsigned int size, const TargetMachine& target) -{ - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); - if (size > (unsigned) cacheLineSize / 2) - return cacheLineSize; - else - for (unsigned sz=1; /*no condition*/; sz *= 2) - if (sz >= size) - return sz; +/// MachineCodeDeletion Pass - This pass deletes all of the machine code for +/// the current function, which should happen after the function has been +/// emitted to a .s file or to memory. +FunctionPass *llvm::createMachineCodeDeleter() { + return new Deleter(); } -/*ctor*/ -MachineCodeForMethod::MachineCodeForMethod(const Method* _M, - const TargetMachine& target) - : Annotation(MCFM_AID), - method(_M), compiledAsLeaf(false), staticStackSize(0), - automaticVarsSize(0), regSpillsSize(0), - currentOptionalArgsSize(0), maxOptionalArgsSize(0), - currentTmpValuesSize(0) -{ - maxOptionalArgsSize = ComputeMaxOptionalArgsSize(target, method); - staticStackSize = maxOptionalArgsSize - + target.getFrameInfo().getMinStackFrameSize(); +//===---------------------------------------------------------------------===// +// MachineFunction implementation +//===---------------------------------------------------------------------===// + +MachineBasicBlock* ilist_traits::createSentinel() { + MachineBasicBlock* dummy = new MachineBasicBlock(); + LeakDetector::removeGarbageObject(dummy); + return dummy; } -int -MachineCodeForMethod::computeOffsetforLocalVar(const TargetMachine& target, - const Value* val, - unsigned int size) -{ - bool growUp; - int firstOffset =target.getFrameInfo().getFirstAutomaticVarOffset(*this, - growUp); - unsigned char align; - if (size == 0) - { - size = target.findOptimalStorageSize(val->getType()); - // align = target.DataLayout.getTypeAlignment(val->getType()); - } - - align = SizeToAlignment(size, target); - - int offset = getAutomaticVarsSize(); - if (! growUp) - offset += size; - - if (unsigned int mod = offset % align) - { - offset += align - mod; - size += align - mod; - } - - offset = growUp? firstOffset + offset - : firstOffset - offset; - - return offset; +void ilist_traits::transferNodesFromList( + iplist >& toList, + ilist_iterator first, + ilist_iterator last) { + if (Parent != toList.Parent) + for (; first != last; ++first) + first->Parent = toList.Parent; } -int -MachineCodeForMethod::allocateLocalVar(const TargetMachine& target, - const Value* val, - unsigned int size) -{ - // Check if we've allocated a stack slot for this value already - // - int offset = getOffset(val); - if (offset == INVALID_FRAME_OFFSET) - { - offset = this->computeOffsetforLocalVar(target, val, size); - offsets[val] = offset; - incrementAutomaticVarsSize(size); - } - return offset; +MachineFunction::MachineFunction(const Function *F, + const TargetMachine &TM) + : Annotation(MF_AID), Fn(F), Target(TM), UsedPhysRegs(0) { + SSARegMapping = new SSARegMap(); + MFInfo = 0; + FrameInfo = new MachineFrameInfo(); + ConstantPool = new MachineConstantPool(TM.getTargetData()); + JumpTableInfo = new MachineJumpTableInfo(TM.getTargetData()); + BasicBlocks.Parent = this; } + +MachineFunction::~MachineFunction() { + BasicBlocks.clear(); + delete SSARegMapping; + delete MFInfo; + delete FrameInfo; + delete ConstantPool; + delete JumpTableInfo; + delete[] UsedPhysRegs; +} + +void MachineFunction::dump() const { print(std::cerr); } + +void MachineFunction::print(std::ostream &OS) const { + OS << "# Machine code for " << Fn->getName () << "():\n"; + + // Print Frame Information + getFrameInfo()->print(*this, OS); -int -MachineCodeForMethod::allocateSpilledValue(const TargetMachine& target, - const Type* type) -{ - unsigned int size = target.findOptimalStorageSize(type); - unsigned char align = target.DataLayout.getTypeAlignment(type); - - bool growUp; - int firstOffset = target.getFrameInfo().getRegSpillAreaOffset(*this, growUp); + // Print JumpTable Information + getJumpTableInfo()->print(OS); + + // Print Constant Pool + getConstantPool()->print(OS); - int offset = getRegSpillsSize(); - if (! growUp) - offset += size; + const MRegisterInfo *MRI = getTarget().getRegisterInfo(); - if (unsigned int mod = offset % align) - { - offset += align - mod; - size += align - mod; + if (livein_begin() != livein_end()) { + OS << "Live Ins:"; + for (livein_iterator I = livein_begin(), E = livein_end(); I != E; ++I) { + if (MRI) + OS << " " << MRI->getName(I->first); + else + OS << " Reg #" << I->first; } + OS << "\n"; + } + if (liveout_begin() != liveout_end()) { + OS << "Live Outs:"; + for (liveout_iterator I = liveout_begin(), E = liveout_end(); I != E; ++I) + if (MRI) + OS << " " << MRI->getName(*I); + else + OS << " Reg #" << *I; + OS << "\n"; + } - offset = growUp? firstOffset + offset - : firstOffset - offset; - - incrementRegSpillsSize(size); - - return offset; + for (const_iterator BB = begin(); BB != end(); ++BB) + BB->print(OS); + + OS << "\n# End machine code for " << Fn->getName () << "().\n\n"; } -int -MachineCodeForMethod::allocateOptionalArg(const TargetMachine& target, - const Type* type) -{ - const MachineFrameInfo& frameInfo = target.getFrameInfo(); - - int size = INT_MAX; - if (frameInfo.argsOnStackHaveFixedSize()) - size = frameInfo.getSizeOfEachArgOnStack(); - else - { - size = target.findOptimalStorageSize(type); - assert(0 && "UNTESTED CODE: Size per stack argument is not fixed on this architecture: use actual argument sizes for computing optional arg offsets"); +/// CFGOnly flag - This is used to control whether or not the CFG graph printer +/// prints out the contents of basic blocks or not. This is acceptable because +/// this code is only really used for debugging purposes. +/// +static bool CFGOnly = false; + +namespace llvm { + template<> + struct DOTGraphTraits : public DefaultDOTGraphTraits { + static std::string getGraphName(const MachineFunction *F) { + return "CFG for '" + F->getFunction()->getName() + "' function"; } - unsigned char align = target.DataLayout.getTypeAlignment(type); - - bool growUp; - int firstOffset = frameInfo.getFirstOptionalOutgoingArgOffset(*this, growUp); - - int offset = getCurrentOptionalArgsSize(); - if (! growUp) - offset += size; - - if (unsigned int mod = offset % align) - { - offset += align - mod; - size += align - mod; + + static std::string getNodeLabel(const MachineBasicBlock *Node, + const MachineFunction *Graph) { + if (CFGOnly && Node->getBasicBlock() && + !Node->getBasicBlock()->getName().empty()) + return Node->getBasicBlock()->getName() + ":"; + + std::ostringstream Out; + if (CFGOnly) { + Out << Node->getNumber() << ':'; + return Out.str(); + } + + Node->print(Out); + + std::string OutStr = Out.str(); + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + return OutStr; } - - offset = growUp? firstOffset + offset - : firstOffset - offset; - - incrementCurrentOptionalArgsSize(size); - - return offset; + }; } -void -MachineCodeForMethod::resetOptionalArgs(const TargetMachine& target) +void MachineFunction::viewCFG() const { - currentOptionalArgsSize = 0; +#ifndef NDEBUG + std::string Filename = "/tmp/cfg." + getFunction()->getName() + ".dot"; + std::cerr << "Writing '" << Filename << "'... "; + std::ofstream F(Filename.c_str()); + + if (!F) { + std::cerr << " error opening file for writing!\n"; + return; + } + + WriteGraph(F, this); + F.close(); + std::cerr << "\n"; + +#ifdef HAVE_GRAPHVIZ + std::cerr << "Running 'Graphviz' program... " << std::flush; + if (system((LLVM_PATH_GRAPHVIZ " " + Filename).c_str())) { + std::cerr << "Error viewing graph: 'Graphviz' not in path?\n"; + } else { + system(("rm " + Filename).c_str()); + return; + } +#endif // HAVE_GRAPHVIZ + +#ifdef HAVE_GV + std::cerr << "Running 'dot' program... " << std::flush; + if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename + + " > /tmp/cfg.tempgraph.ps").c_str())) { + std::cerr << "Error running dot: 'dot' not in path?\n"; + } else { + std::cerr << "\n"; + system("gv /tmp/cfg.tempgraph.ps"); + } + system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str()); + return; +#endif // HAVE_GV +#endif // NDEBUG + std::cerr << "MachineFunction::viewCFG is only available in debug builds on " + << "systems with Graphviz or gv!\n"; + +#ifndef NDEBUG + system(("rm " + Filename).c_str()); +#endif } -int -MachineCodeForMethod::pushTempValue(const TargetMachine& target, - unsigned int size) +void MachineFunction::viewCFGOnly() const { - // Compute a power-of-2 alignment according to the possible sizes, - // but not greater than the alignment of the largest type we support - // (currently a double word -- see class TargetData). - unsigned char align = 1; - for (; align < size && align < target.DataLayout.getDoubleAlignment(); - align = 2*align) - ; - - bool growUp; - int firstTmpOffset = target.getFrameInfo().getTmpAreaOffset(*this, growUp); - - int offset = currentTmpValuesSize; - if (! growUp) - offset += size; - - if (unsigned int mod = offset % align) - { - offset += align - mod; - size += align - mod; - } - - offset = growUp ? firstTmpOffset + offset : firstTmpOffset - offset; - - currentTmpValuesSize += size; - return offset; + CFGOnly = true; + viewCFG(); + CFGOnly = false; } -void -MachineCodeForMethod::popAllTempValues(const TargetMachine& target) +// The next two methods are used to construct and to retrieve +// the MachineCodeForFunction object for the given function. +// construct() -- Allocates and initializes for a given function and target +// get() -- Returns a handle to the object. +// This should not be called before "construct()" +// for a given Function. +// +MachineFunction& +MachineFunction::construct(const Function *Fn, const TargetMachine &Tar) { - currentTmpValuesSize = 0; + assert(Fn->getAnnotation(MF_AID) == 0 && + "Object already exists for this function!"); + MachineFunction* mcInfo = new MachineFunction(Fn, Tar); + Fn->addAnnotation(mcInfo); + return *mcInfo; } -int -MachineCodeForMethod::getOffset(const Value* val) const -{ - std::hash_map::const_iterator pair = offsets.find(val); - return (pair == offsets.end())? INVALID_FRAME_OFFSET : pair->second; +void MachineFunction::destruct(const Function *Fn) { + bool Deleted = Fn->deleteAnnotation(MF_AID); + assert(Deleted && "Machine code did not exist for function!"); } -void -MachineCodeForMethod::dump() const +MachineFunction& MachineFunction::get(const Function *F) { - std::cerr << "\n" << method->getReturnType() - << " \"" << method->getName() << "\"\n"; + MachineFunction *mc = (MachineFunction*)F->getAnnotation(MF_AID); + assert(mc && "Call construct() method first to allocate the object"); + return *mc; +} + +void MachineFunction::clearSSARegMap() { + delete SSARegMapping; + SSARegMapping = 0; +} + +//===----------------------------------------------------------------------===// +// MachineFrameInfo implementation +//===----------------------------------------------------------------------===// + +void MachineFrameInfo::print(const MachineFunction &MF, std::ostream &OS) const{ + int ValOffset = MF.getTarget().getFrameInfo()->getOffsetOfLocalArea(); + + for (unsigned i = 0, e = Objects.size(); i != e; ++i) { + const StackObject &SO = Objects[i]; + OS << " : "; + if (SO.Size == 0) + OS << "variable sized"; + else + OS << "size is " << SO.Size << " byte" << (SO.Size != 1 ? "s," : ","); + OS << " alignment is " << SO.Alignment << " byte" + << (SO.Alignment != 1 ? "s," : ","); + + if (i < NumFixedObjects) + OS << " fixed"; + if (i < NumFixedObjects || SO.SPOffset != -1) { + int Off = SO.SPOffset - ValOffset; + OS << " at location [SP"; + if (Off > 0) + OS << "+" << Off; + else if (Off < 0) + OS << Off; + OS << "]"; + } + OS << "\n"; + } + + if (HasVarSizedObjects) + OS << " Stack frame contains variable sized objects\n"; +} + +void MachineFrameInfo::dump(const MachineFunction &MF) const { + print(MF, std::cerr); +} + + +//===----------------------------------------------------------------------===// +// MachineJumpTableInfo implementation +//===----------------------------------------------------------------------===// + +/// getJumpTableIndex - Create a new jump table entry in the jump table info +/// or return an existing one. +/// +unsigned MachineJumpTableInfo::getJumpTableIndex( + std::vector &DestBBs) { + for (unsigned i = 0, e = JumpTables.size(); i != e; ++i) + if (JumpTables[i].MBBs == DestBBs) + return i; + + JumpTables.push_back(MachineJumpTableEntry(DestBBs)); + return JumpTables.size()-1; +} + + +void MachineJumpTableInfo::print(std::ostream &OS) const { + // FIXME: this is lame, maybe we could print out the MBB numbers or something + // like {1, 2, 4, 5, 3, 0} + for (unsigned i = 0, e = JumpTables.size(); i != e; ++i) { + OS << " has " << JumpTables[i].MBBs.size() + << " entries\n"; + } +} + +unsigned MachineJumpTableInfo::getEntrySize() const { + return TD->getPointerSize(); +} + +unsigned MachineJumpTableInfo::getAlignment() const { + return TD->getPointerAlignment(); +} + +void MachineJumpTableInfo::dump() const { print(std::cerr); } + + +//===----------------------------------------------------------------------===// +// MachineConstantPool implementation +//===----------------------------------------------------------------------===// + +/// getConstantPoolIndex - Create a new entry in the constant pool or return +/// an existing one. User must specify an alignment in bytes for the object. +/// +unsigned MachineConstantPool::getConstantPoolIndex(Constant *C, + unsigned Alignment) { + assert(Alignment && "Alignment must be specified!"); + if (Alignment > PoolAlignment) PoolAlignment = Alignment; + + // Check to see if we already have this constant. + // + // FIXME, this could be made much more efficient for large constant pools. + unsigned AlignMask = (1 << Alignment)-1; + for (unsigned i = 0, e = Constants.size(); i != e; ++i) + if (Constants[i].Val == C && (Constants[i].Offset & AlignMask) == 0) + return i; - for (Method::const_iterator BI = method->begin(); BI != method->end(); ++BI) - { - BasicBlock* bb = *BI; - std::cerr << "\n" << bb->getName() << " (" << bb << ")" << ":\n"; - - MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec(); - for (unsigned i=0; i < mvec.size(); i++) - std::cerr << "\t" << *mvec[i]; - } - std::cerr << "\nEnd method \"" << method->getName() << "\"\n\n"; + unsigned Offset = 0; + if (!Constants.empty()) { + Offset = Constants.back().Offset; + Offset += TD->getTypeSize(Constants.back().Val->getType()); + Offset = (Offset+AlignMask)&~AlignMask; + } + + Constants.push_back(MachineConstantPoolEntry(C, Offset)); + return Constants.size()-1; } + + +void MachineConstantPool::print(std::ostream &OS) const { + for (unsigned i = 0, e = Constants.size(); i != e; ++i) { + OS << " is" << *(Value*)Constants[i].Val; + OS << " , offset=" << Constants[i].Offset; + OS << "\n"; + } +} + +void MachineConstantPool::dump() const { print(std::cerr); }