diff --git a/include/llvm/CodeGen/MachineCodeEmitter.h b/include/llvm/CodeGen/MachineCodeEmitter.h index 47ccef5317a..72002ef8977 100644 --- a/include/llvm/CodeGen/MachineCodeEmitter.h +++ b/include/llvm/CodeGen/MachineCodeEmitter.h @@ -31,19 +31,50 @@ class Value; class GlobalValue; class Function; +/// MachineCodeEmitter - This class defines two sorts of methods: those for +/// emitting the actual bytes of machine code, and those for emitting auxillary +/// structures, such as jump tables, relocations, etc. +/// +/// Emission of machine code is complicated by the fact that we don't (in +/// general) know the size of the machine code that we're about to emit before +/// we emit it. As such, we preallocate a certain amount of memory, and set the +/// BufferBegin/BufferEnd pointers to the start and end of the buffer. As we +/// emit machine instructions, we advance the CurBufferPtr to indicate the +/// location of the next byte to emit. In the case of a buffer overflow (we +/// need to emit more machine code than we have allocated space for), the +/// CurBufferPtr will saturate to BufferEnd and ignore stores. Once the entire +/// function has been emitted, the overflow condition is checked, and if it has +/// occurred, more memory is allocated, and we reemit the code into it. +/// class MachineCodeEmitter { +protected: + /// BufferBegin/BufferEnd - Pointers to the start and end of the memory + /// allocated for this code buffer. + unsigned char *BufferBegin, *BufferEnd; + + /// CurBufferPtr - Pointer to the next byte of memory to fill when emitting + /// code. This is guranteed to be in the range [BufferBegin,BufferEnd]. If + /// this pointer is at BufferEnd, it will never move due to code emission, and + /// all code emission requests will be ignored (this is the buffer overflow + /// condition). + unsigned char *CurBufferPtr; public: virtual ~MachineCodeEmitter() {} /// startFunction - This callback is invoked when the specified function is - /// about to be code generated. + /// about to be code generated. This initializes the BufferBegin/End/Ptr + /// fields. /// virtual void startFunction(MachineFunction &F) {} /// finishFunction - This callback is invoked when the specified function has - /// finished code generation. + /// finished code generation. If a buffer overflow has occurred, this method + /// returns true (the callee is required to try again), otherwise it returns + /// false. /// - virtual void finishFunction(MachineFunction &F) {} + virtual bool finishFunction(MachineFunction &F) { + return CurBufferPtr == BufferEnd; + } /// emitConstantPool - This callback is invoked to output the constant pool /// for the function. @@ -63,7 +94,8 @@ public: /// startFunctionStub - This callback is invoked when the JIT needs the /// address of a function that has not been code generated yet. The StubSize /// specifies the total size required by the stub. Stubs are not allowed to - /// have constant pools, the can only use the other emit* methods. + /// have constant pools, the can only use the other emitByte*/emitWord* + /// methods. /// virtual void startFunctionStub(unsigned StubSize) {} @@ -75,22 +107,36 @@ public: /// emitByte - This callback is invoked when a byte needs to be written to the /// output stream. /// - virtual void emitByte(unsigned char B) {} + void emitByte(unsigned char B) { + if (CurBufferPtr != BufferEnd) + *CurBufferPtr++ = B; + } /// emitWord - This callback is invoked when a word needs to be written to the /// output stream. /// - virtual void emitWord(unsigned W) = 0; + void emitWord(unsigned W) { + // FIXME: handle endian mismatches for .o file emission. + if (CurBufferPtr+4 <= BufferEnd) { + *(unsigned*)CurBufferPtr = W; + CurBufferPtr += 4; + } else { + CurBufferPtr = BufferEnd; + } + } /// getCurrentPCValue - This returns the address that the next emitted byte /// will be output to. /// - virtual uint64_t getCurrentPCValue() = 0; - + virtual intptr_t getCurrentPCValue() const { + return (intptr_t)CurBufferPtr; + } /// getCurrentPCOffset - Return the offset from the start of the emitted /// buffer that we are currently writing to. - virtual uint64_t getCurrentPCOffset() = 0; + intptr_t getCurrentPCOffset() const { + return CurBufferPtr-BufferBegin; + } /// addRelocation - Whenever a relocatable address is needed, it should be /// noted with this interface. @@ -108,12 +154,6 @@ public: // allocateGlobal - Allocate some space for a global variable. virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment) = 0; - - /// createFilePrinterEmitter - Return a dynamically allocated - /// machine code emitter, which prints binary code to a file. This - /// can be used for debugging users of the MachineCodeEmitter interface. - /// - static MachineCodeEmitter *createFilePrinterEmitter(MachineCodeEmitter&); }; } // End llvm namespace diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index a802c1aa793..c03b6272b56 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -56,24 +56,12 @@ namespace llvm { ELFCodeEmitter(ELFWriter &ew) : EW(ew), OutBuffer(0) {} void startFunction(MachineFunction &F); - void finishFunction(MachineFunction &F); + bool finishFunction(MachineFunction &F); void emitConstantPool(MachineConstantPool *MCP) { if (MCP->isEmpty()) return; assert(0 && "unimp"); } - virtual void emitByte(unsigned char B) { - OutBuffer->push_back(B); - } - virtual void emitWord(unsigned W) { - assert(0 && "ni"); - } - virtual uint64_t getCurrentPCValue() { - return OutBuffer->size(); - } - virtual uint64_t getCurrentPCOffset() { - return OutBuffer->size()-FnStart; - } void addRelocation(const MachineRelocation &MR) { assert(0 && "relo not handled yet!"); } @@ -113,6 +101,10 @@ void ELFCodeEmitter::startFunction(MachineFunction &F) { ELFWriter::ELFSection::SHF_EXECINSTR | ELFWriter::ELFSection::SHF_ALLOC); OutBuffer = &ES->SectionData; + std::cerr << "FIXME: This code needs to be updated for changes in the" + << " CodeEmitter interfaces. In particular, this should set " + << "BufferBegin/BufferEnd/CurBufferPtr, not deal with OutBuffer!"; + abort(); // Upgrade the section alignment if required. if (ES->Align < Align) ES->Align = Align; @@ -127,7 +119,7 @@ void ELFCodeEmitter::startFunction(MachineFunction &F) { /// finishFunction - This callback is invoked after the function is completely /// finished. -void ELFCodeEmitter::finishFunction(MachineFunction &F) { +bool ELFCodeEmitter::finishFunction(MachineFunction &F) { // We now know the size of the function, add a symbol to represent it. ELFWriter::ELFSym FnSym(F.getFunction()); @@ -157,6 +149,7 @@ void ELFCodeEmitter::finishFunction(MachineFunction &F) { // Finally, add it to the symtab. EW.SymbolTable.push_back(FnSym); + return false; } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/MachineCodeEmitter.cpp b/lib/CodeGen/MachineCodeEmitter.cpp deleted file mode 100644 index 301d9afb8ae..00000000000 --- a/lib/CodeGen/MachineCodeEmitter.cpp +++ /dev/null @@ -1,131 +0,0 @@ -//===-- MachineCodeEmitter.cpp - Implement the MachineCodeEmitter itf -----===// -// -// 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 MachineCodeEmitter interface. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include -#include -using namespace llvm; - -namespace { - class FilePrinterEmitter : public MachineCodeEmitter { - std::ofstream actual; - std::ostream &o; - MachineCodeEmitter &MCE; - unsigned counter; - unsigned values[4]; - - public: - FilePrinterEmitter(MachineCodeEmitter &M, std::ostream &os) - : o(os), MCE(M), counter(0) { - openActual(); - } - - ~FilePrinterEmitter() { - o << "\n"; - actual.close(); - } - - void openActual() { - actual.open("lli.actual.obj"); - if (!actual.good()) { - std::cerr << "Cannot open 'lli.actual.obj' for writing\n"; - abort(); - } - } - - void startFunction(MachineFunction &F) { - // resolve any outstanding calls - MCE.startFunction(F); - } - void finishFunction(MachineFunction &F) { - MCE.finishFunction(F); - } - - void emitConstantPool(MachineConstantPool *MCP) { - MCE.emitConstantPool(MCP); - } - void initJumpTableInfo(MachineJumpTableInfo *MJTI) { - MCE.initJumpTableInfo(MJTI); - } - void emitJumpTableInfo(MachineJumpTableInfo *MJTI, - std::map &MBBM) { - MCE.emitJumpTableInfo(MJTI, MBBM); - } - - void startFunctionStub(unsigned StubSize) { - MCE.startFunctionStub(StubSize); - } - - void *finishFunctionStub(const Function *F) { - return MCE.finishFunctionStub(F); - } - - void emitByte(unsigned char B) { - MCE.emitByte(B); - actual << B; actual.flush(); - - values[counter] = (unsigned int) B; - if (++counter % 4 == 0 && counter != 0) { - o << std::hex; - for (unsigned i=0; i<4; ++i) { - if (values[i] < 16) o << "0"; - o << values[i] << " "; - } - - o << std::dec << "\t"; - for (unsigned i=0; i<4; ++i) { - for (int j=7; j>=0; --j) { - o << ((values[i] >> j) & 1); - } - o << " "; - } - - o << "\n"; - - unsigned instr = 0; - for (unsigned i=0; i<4; ++i) - instr |= values[i] << (i*8); - - o << "--- * --- * --- * --- * ---\n"; - counter %= 4; - } - } - - void emitWord(unsigned W) { - MCE.emitWord(W); - } - uint64_t getConstantPoolEntryAddress(unsigned Num) { - return MCE.getConstantPoolEntryAddress(Num); - } - uint64_t getJumpTableEntryAddress(unsigned Num) { - return MCE.getJumpTableEntryAddress(Num); - } - virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment) - { return MCE.allocateGlobal(size, alignment); } - - uint64_t getCurrentPCValue() { - return MCE.getCurrentPCValue(); - } - uint64_t getCurrentPCOffset() { - return MCE.getCurrentPCOffset(); - } - void addRelocation(const MachineRelocation &MR) { - return MCE.addRelocation(MR); - } - }; -} - -MachineCodeEmitter * -MachineCodeEmitter::createFilePrinterEmitter(MachineCodeEmitter &MCE) { - return new FilePrinterEmitter(MCE, std::cerr); -} diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index cbe8f7af555..108b6b85833 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -413,13 +413,9 @@ namespace { class JITEmitter : public MachineCodeEmitter { JITMemoryManager MemMgr; - // CurBlock - The start of the current block of memory. CurByte - The - // current byte being emitted to. - unsigned char *CurBlock, *CurByte; - // When outputting a function stub in the context of some other function, we - // save CurBlock and CurByte here. - unsigned char *SavedCurBlock, *SavedCurByte; + // save BufferBegin/BufferEnd/CurBufferPtr here. + unsigned char *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr; /// Relocations - These are the relocations that the function needs, as /// emitted. @@ -449,22 +445,18 @@ public: } virtual void startFunction(MachineFunction &F); - virtual void finishFunction(MachineFunction &F); + virtual bool finishFunction(MachineFunction &F); virtual void emitConstantPool(MachineConstantPool *MCP); virtual void initJumpTableInfo(MachineJumpTableInfo *MJTI); virtual void emitJumpTableInfo(MachineJumpTableInfo *MJTI, std::map &MBBM); virtual void startFunctionStub(unsigned StubSize); virtual void* finishFunctionStub(const Function *F); - virtual void emitByte(unsigned char B); - virtual void emitWord(unsigned W); virtual void addRelocation(const MachineRelocation &MR) { Relocations.push_back(MR); } - virtual uint64_t getCurrentPCValue(); - virtual uint64_t getCurrentPCOffset(); virtual uint64_t getConstantPoolEntryAddress(unsigned Entry); virtual uint64_t getJumpTableEntryAddress(unsigned Entry); virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment); @@ -511,13 +503,16 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference, } void JITEmitter::startFunction(MachineFunction &F) { - CurByte = CurBlock = MemMgr.startFunctionBody(); - TheJIT->addGlobalMapping(F.getFunction(), CurBlock); + BufferBegin = CurBufferPtr = MemMgr.startFunctionBody(); + TheJIT->updateGlobalMapping(F.getFunction(), BufferBegin); + + /// FIXME: implement out of space handling correctly! + BufferEnd = (unsigned char*)(intptr_t)~0ULL; } -void JITEmitter::finishFunction(MachineFunction &F) { - MemMgr.endFunctionBody(CurByte); - NumBytes += CurByte-CurBlock; +bool JITEmitter::finishFunction(MachineFunction &F) { + MemMgr.endFunctionBody(CurBufferPtr); + NumBytes += getCurrentPCOffset(); if (!Relocations.empty()) { NumRelos += Relocations.size(); @@ -534,7 +529,7 @@ void JITEmitter::finishFunction(MachineFunction &F) { ResultPtr = getJITResolver(this).getExternalFunctionStub(ResultPtr); } else if (MR.isGlobalValue()) ResultPtr = getPointerToGlobal(MR.getGlobalValue(), - CurBlock+MR.getMachineCodeOffset(), + BufferBegin+MR.getMachineCodeOffset(), MR.doesntNeedFunctionStub()); else //ConstantPoolIndex ResultPtr = @@ -557,25 +552,26 @@ void JITEmitter::finishFunction(MachineFunction &F) { } } - TheJIT->getJITInfo().relocate(CurBlock, &Relocations[0], + TheJIT->getJITInfo().relocate(BufferBegin, &Relocations[0], Relocations.size(), MemMgr.getGOTBase()); } //Update the GOT entry for F to point to the new code. if(MemMgr.isManagingGOT()) { - unsigned idx = getJITResolver(this).getGOTIndexForAddr((void*)CurBlock); - if (((void**)MemMgr.getGOTBase())[idx] != (void*)CurBlock) { - DEBUG(std::cerr << "GOT was out of date for " << (void*)CurBlock + unsigned idx = getJITResolver(this).getGOTIndexForAddr((void*)BufferBegin); + if (((void**)MemMgr.getGOTBase())[idx] != (void*)BufferBegin) { + DEBUG(std::cerr << "GOT was out of date for " << (void*)BufferBegin << " pointing at " << ((void**)MemMgr.getGOTBase())[idx] << "\n"); - ((void**)MemMgr.getGOTBase())[idx] = (void*)CurBlock; + ((void**)MemMgr.getGOTBase())[idx] = (void*)BufferBegin; } } - DEBUG(std::cerr << "JIT: Finished CodeGen of [" << (void*)CurBlock + DEBUG(std::cerr << "JIT: Finished CodeGen of [" << (void*)BufferBegin << "] Function: " << F.getFunction()->getName() - << ": " << CurByte-CurBlock << " bytes of text, " + << ": " << getCurrentPCOffset() << " bytes of text, " << Relocations.size() << " relocations\n"); Relocations.clear(); + return false; } void JITEmitter::emitConstantPool(MachineConstantPool *MCP) { @@ -648,26 +644,20 @@ void JITEmitter::emitJumpTableInfo(MachineJumpTableInfo *MJTI, } void JITEmitter::startFunctionStub(unsigned StubSize) { - SavedCurBlock = CurBlock; SavedCurByte = CurByte; - CurByte = CurBlock = MemMgr.allocateStub(StubSize); + SavedBufferBegin = BufferBegin; + SavedBufferEnd = BufferEnd; + SavedCurBufferPtr = CurBufferPtr; + + BufferBegin = CurBufferPtr = MemMgr.allocateStub(StubSize); + BufferEnd = BufferBegin+StubSize+1; } void *JITEmitter::finishFunctionStub(const Function *F) { - NumBytes += CurByte-CurBlock; - std::swap(CurBlock, SavedCurBlock); - CurByte = SavedCurByte; - return SavedCurBlock; -} - -void JITEmitter::emitByte(unsigned char B) { - *CurByte++ = B; // Write the byte to memory -} - -void JITEmitter::emitWord(unsigned W) { - // This won't work if the endianness of the host and target don't agree! (For - // a JIT this can't happen though. :) - *(unsigned*)CurByte = W; - CurByte += sizeof(unsigned); + NumBytes += getCurrentPCOffset(); + std::swap(SavedBufferBegin, BufferBegin); + BufferEnd = SavedBufferEnd; + CurBufferPtr = SavedCurBufferPtr; + return SavedBufferBegin; } // getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry @@ -702,17 +692,6 @@ unsigned char* JITEmitter::allocateGlobal(unsigned size, unsigned alignment) return MemMgr.allocateGlobal(size, alignment); } -// getCurrentPCValue - This returns the address that the next emitted byte -// will be output to. -// -uint64_t JITEmitter::getCurrentPCValue() { - return (intptr_t)CurByte; -} - -uint64_t JITEmitter::getCurrentPCOffset() { - return (intptr_t)CurByte-(intptr_t)CurBlock; -} - // getPointerToNamedFunction - This function is used as a global wrapper to // JIT::getPointerToNamedFunction for the purpose of resolving symbols when // bugpoint is debugging the JIT. In that scenario, we are loading an .so and diff --git a/lib/Target/Alpha/AlphaCodeEmitter.cpp b/lib/Target/Alpha/AlphaCodeEmitter.cpp index f5d517fadd4..dfb7820cae8 100644 --- a/lib/Target/Alpha/AlphaCodeEmitter.cpp +++ b/lib/Target/Alpha/AlphaCodeEmitter.cpp @@ -80,11 +80,15 @@ FunctionPass *llvm::createAlphaCodeEmitterPass(MachineCodeEmitter &MCE) { bool AlphaCodeEmitter::runOnMachineFunction(MachineFunction &MF) { II = ((AlphaTargetMachine&)MF.getTarget()).getInstrInfo(); - MCE.startFunction(MF); - MCE.emitConstantPool(MF.getConstantPool()); - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - emitBasicBlock(*I); - MCE.finishFunction(MF); + do { + BBRefs.clear(); + BasicBlockAddrs.clear(); + + MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) + emitBasicBlock(*I); + } while (MCE.finishFunction(MF)); // Resolve all forward branches now... for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { diff --git a/lib/Target/PowerPC/PPCCodeEmitter.cpp b/lib/Target/PowerPC/PPCCodeEmitter.cpp index c7f2acbd77c..1b305f4b243 100644 --- a/lib/Target/PowerPC/PPCCodeEmitter.cpp +++ b/lib/Target/PowerPC/PPCCodeEmitter.cpp @@ -89,13 +89,17 @@ bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) { assert((MF.getTarget().getRelocationModel() != Reloc::Default || MF.getTarget().getRelocationModel() != Reloc::Static) && "JIT relocation model must be set to static or default!"); - MCE.startFunction(MF); - MCE.emitConstantPool(MF.getConstantPool()); - MCE.initJumpTableInfo(MF.getJumpTableInfo()); - for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB) - emitBasicBlock(*BB); - MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BBLocations); - MCE.finishFunction(MF); + do { + BBRefs.clear(); + BBLocations.clear(); + + MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); + MCE.initJumpTableInfo(MF.getJumpTableInfo()); + for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB) + emitBasicBlock(*BB); + MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BBLocations); + } while (MCE.finishFunction(MF)); // Resolve branches to BasicBlocks for the entire function for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp index 75bc6ce1e33..a278fd548b5 100644 --- a/lib/Target/X86/X86CodeEmitter.cpp +++ b/lib/Target/X86/X86CodeEmitter.cpp @@ -81,13 +81,17 @@ bool Emitter::runOnMachineFunction(MachineFunction &MF) { "JIT relocation model must be set to static or default!"); II = ((X86TargetMachine&)MF.getTarget()).getInstrInfo(); - MCE.startFunction(MF); - MCE.emitConstantPool(MF.getConstantPool()); - MCE.initJumpTableInfo(MF.getJumpTableInfo()); - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - emitBasicBlock(*I); - MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BasicBlockAddrs); - MCE.finishFunction(MF); + do { + BBRefs.clear(); + BasicBlockAddrs.clear(); + + MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); + MCE.initJumpTableInfo(MF.getJumpTableInfo()); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) + emitBasicBlock(*I); + MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BasicBlockAddrs); + } while (MCE.finishFunction(MF)); // Resolve all forward branches now. for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) {