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.
/// 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) {}
/// 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.
// 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
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!");
}
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;
/// 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());
// Finally, add it to the symtab.
EW.SymbolTable.push_back(FnSym);
+ return false;
}
//===----------------------------------------------------------------------===//
+++ /dev/null
-//===-- 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 <fstream>
-#include <iostream>
-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<MachineBasicBlock*,uint64_t> &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);
-}
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.
}
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<MachineBasicBlock*,uint64_t> &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);
}
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();
ResultPtr = getJITResolver(this).getExternalFunctionStub(ResultPtr);
} else if (MR.isGlobalValue())
ResultPtr = getPointerToGlobal(MR.getGlobalValue(),
- CurBlock+MR.getMachineCodeOffset(),
+ BufferBegin+MR.getMachineCodeOffset(),
MR.doesntNeedFunctionStub());
else //ConstantPoolIndex
ResultPtr =
}
}
- 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) {
}
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
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
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) {
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) {
"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) {