Hi everyone,
Here's a patch that enables exception handling when jitting. I've
copy/pasted _many_code from lib/Codegen/DwarfWriter.cpp, so we may need
to factorize it, but the functionality is there and I'm very happy with
it ![:slight_smile: :slight_smile:](https://emoji.discourse-cdn.com/google/slight_smile.png?v=12)
Very nice! I don't know enough about EH, someone else please review.
It does look like it's in need of some refactoring. How much work is it?
lli should now be able to execute the output from llvm-gcc when using
exceptions (the UnwindInst instruction is not involved in this patch).
Just add the -enable-eh command line argument.
There is room for improvement here: I generate a common EH frame table
and an EH frame table for each generated function. The common EH frame
table should be shared between functions with the same personality
function (EH gurus, correct me if I'm wrong)
Note that since only x86 generates correct exception tables (that I know
of), you can only test this on x86.
Let me know what you think about it.
Nicolas
Index: include/llvm/CodeGen/DwarfEmitter.h
--- include/llvm/CodeGen/DwarfEmitter.h (revision 0)
+++ include/llvm/CodeGen/DwarfEmitter.h (revision 0)
@@ -0,0 +1,167 @@
+//===------- llvm/CodeGen/DwarfEmitter.h - Dwarf emission -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
^
Your name here. ----------------------------|
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_DWARFEMITTER_H
+#define LLVM_CODEGEN_DWARFEMITTER_H
+
+#include "llvm/Support/DataTypes.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class Function;
+class MachineCodeEmitter;
+class TargetData;
+class TargetMachine;
+class MachineFunction;
+class MachineModuleInfo;
+class MachineMove;
+class MRegisterInfo;
+
+class DwarfEmitter {
+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;
I am not sure if it makes sense for this to maintain it's own buffers. Can it be modified to use MachineCodeEmitter?
+
+ MachineModuleInfo* MMI;
+public:
+ virtual ~DwarfEmitter() {}
+
+ /// startFunction - This callback is invoked when the specified function is
+ /// about to be code generated. This initializes the BufferBegin/End/Ptr
+ /// fields.
+ ///
+ virtual void startFunction(MachineFunction &F) = 0;
+
+ /// finishFunction - This callback is invoked when the specified function has
+ /// 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 bool finishFunction(MachineFunction &F, unsigned char* FnStart,
+ unsigned char* FnEnd) = 0;
+
+ /// EmitInt8 - This callback is invoked when a byte needs to be written to the
+ /// output stream.
+ ///
+ void EmitInt8(unsigned char B, bool print=true) {
+// if (print) printf(".byte 0x%x\n", B);
+ if (CurBufferPtr != BufferEnd)
+ *CurBufferPtr++ = B;
+ }
Please use DOUT instead leaving debugging code around. What's the relationship between this module and MachineCodeEmitter? Does it make sense to move the common facility to MachineCodeEmitter?
+
+ /// EmitULEB128Bytes - This callback is invoked when a ULEB128 needs to be
+ /// written to the output stream.
+ void EmitULEB128Bytes(unsigned Value) {
+// printf(".uleb128 %d\n", Value);
+ do {
+ unsigned char Byte = Value & 0x7f;
+ Value >>= 7;
+ if (Value) Byte |= 0x80;
+ EmitInt8(Byte, false);
+ } while (Value);
+ }
+
+ /// EmitSLEB128Bytes - This callback is invoked when a SLEB128 needs to be
+ /// written to the output stream.
+ void EmitSLEB128Bytes(int Value) {
+// printf(".sleb128 %d\n", Value);
+ int Sign = Value >> (8 * sizeof(Value) - 1);
+ bool IsMore;
+
+ do {
+ unsigned char Byte = Value & 0x7f;
+ Value >>= 7;
+ IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
+ if (IsMore) Byte |= 0x80;
+ EmitInt8(Byte, false);
+ } while (IsMore);
+ }
+
+ void EmitString(const std::string &String) {
+// printf(".asciiz %s\n", String.c_str());
+ for (unsigned i = 0, N = String.size(); i < N; ++i) {
+ unsigned char C = String[i];
+ EmitInt8(C, false);
+ }
+ EmitInt8(0, false);
+ }
+
+ void EmitInt32(int Value) {
+// printf(".long 0x%x\n", Value);
+ if (CurBufferPtr+4 <= BufferEnd) {
+ *((uint32_t*)CurBufferPtr) = Value;
+ CurBufferPtr += 4;
+ } else {
+ CurBufferPtr = BufferEnd;
+ }
+ }
+
+ /// EmitInt64 - Emit a long long directive and value.
+ ///
+ void EmitInt64(uint64_t Value) {
+ if (CurBufferPtr+8 <= BufferEnd) {
+ *((uint64_t*)CurBufferPtr) = Value;
+ CurBufferPtr += 8;
+ } else {
+ CurBufferPtr = BufferEnd;
+ }
+ }
+
+ /// emitAlignment - Move the CurBufferPtr pointer up the the specified
+ /// alignment (saturated to BufferEnd of course).
+ void EmitAlignment(unsigned Alignment) {
+// printf(".align %x\n", 1 << Alignment);
+ if (Alignment == 0) Alignment = 1;
+ // Move the current buffer ptr up to the specified alignment.
+ CurBufferPtr =
+ (unsigned char*)(((intptr_t)CurBufferPtr+Alignment-1) &
+ ~(intptr_t)(Alignment-1));
+ if (CurBufferPtr > BufferEnd)
+ CurBufferPtr = BufferEnd;
+ }
Comment says "emitAlignment". Function definition is EmitAlignment. To be consistent with MachineModuleInfo, please use the former convention.
+
+ /// allocateSpace - Allocate a block of space in the current output buffer,
+ /// returning null (and setting conditions to indicate buffer overflow) on
+ /// failure. Alignment is the alignment in bytes of the buffer desired.
+ void *allocateSpace(intptr_t Size, unsigned Alignment) {
+ EmitAlignment(Alignment);
+ void *Result = CurBufferPtr;
+
+ // Allocate the space.
+ CurBufferPtr += Size;
+
+ // Check for buffer overflow.
+ if (CurBufferPtr >= BufferEnd) {
+ CurBufferPtr = BufferEnd;
+ Result = 0;
+ }
+ return Result;
+ }
+
+ void setModuleInfo(MachineModuleInfo* M) {
+ MMI = M;
+ }
+};
+
+} // End llvm namespace
+
+#endif
Index: include/llvm/CodeGen/MachineCodeEmitter.h
--- include/llvm/CodeGen/MachineCodeEmitter.h (revision 44794)
+++ include/llvm/CodeGen/MachineCodeEmitter.h (working copy)
@@ -22,10 +22,12 @@
namespace llvm {
+class DwarfEmitter;
class MachineBasicBlock;
class MachineConstantPool;
class MachineJumpTableInfo;
class MachineFunction;
+class MachineModuleInfo;
class MachineRelocation;
class Value;
class GlobalValue;
@@ -58,6 +60,7 @@
/// all code emission requests will be ignored (this is the buffer overflow
/// condition).
unsigned char *CurBufferPtr;
+
public:
virtual ~MachineCodeEmitter() {}
@@ -158,6 +161,9 @@
/// start of the block is, and can implement getMachineBasicBlockAddress.
virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) = 0;
+ virtual void EmitLabel(uint64_t LabelID) = 0;
+
/// getCurrentPCValue - This returns the address that the next emitted byte
/// will be output to.
///
@@ -193,6 +199,10 @@
/// emitted.
///
virtual intptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const= 0;
+
+ virtual intptr_t getLabelAddress(uint64_t LabelID) const = 0;
+
+ virtual void setModuleInfo(MachineModuleInfo* Info) = 0;
};
} // End llvm namespace
Index: lib/CodeGen/LLVMTargetMachine.cpp
--- lib/CodeGen/LLVMTargetMachine.cpp (revision 44794)
+++ lib/CodeGen/LLVMTargetMachine.cpp (working copy)
@@ -158,7 +158,8 @@
PM.add(createLowerGCPass());
// FIXME: Implement the invoke/unwind instructions!
- PM.add(createLowerInvokePass(getTargetLowering()));
+ if (!ExceptionHandling)
+ PM.add(createLowerInvokePass(getTargetLowering()));
Is this right?
// Make sure that no unreachable blocks are instruction selected.
PM.add(createUnreachableBlockEliminationPass());
Index: lib/CodeGen/ELFWriter.cpp
--- lib/CodeGen/ELFWriter.cpp (revision 44794)
+++ lib/CodeGen/ELFWriter.cpp (working copy)
@@ -98,6 +98,18 @@
return 0;
}
+ virtual intptr_t getLabelAddress(uint64_t Label) const {
+ assert(0 && "JT not implementated yet!");
+ return 0;
+ }
+
+ virtual void EmitLabel(uint64_t LabelID) {
+ }
+
+ virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) { }
+
/// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE!
void startFunctionStub(unsigned StubSize, unsigned Alignment = 1) {
assert(0 && "JIT specific function called!");
Index: lib/CodeGen/MachOWriter.cpp
--- lib/CodeGen/MachOWriter.cpp (revision 44794)
+++ lib/CodeGen/MachOWriter.cpp (working copy)
@@ -125,6 +125,20 @@
return MBBLocations[MBB->getNumber()];
}
+ virtual intptr_t getLabelAddress(uint64_t Label) const {
+ assert(0 && "Implement me");
+ abort();
+ return 0;
+ }
+
+ virtual void EmitLabel(uint64_t LabelID) {
+ assert(0 && "Implement me");
+ abort();
+ }
+
+ virtual void setModuleInfo(llvm::MachineModuleInfo* MMI) { }
+
/// JIT SPECIFIC FUNCTIONS - DO NOT IMPLEMENT THESE HERE!
virtual void startFunctionStub(unsigned StubSize, unsigned Alignment = 1) {
assert(0 && "JIT specific function called!");
Index: lib/Target/PowerPC/PPCCodeEmitter.cpp
--- lib/Target/PowerPC/PPCCodeEmitter.cpp (revision 44794)
+++ lib/Target/PowerPC/PPCCodeEmitter.cpp (working copy)
@@ -38,6 +38,11 @@
/// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr
///
int getMachineOpValue(MachineInstr &MI, MachineOperand &MO);
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<MachineModuleInfo>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
public:
static char ID;
@@ -82,6 +87,8 @@
assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
MF.getTarget().getRelocationModel() != Reloc::Static) &&
"JIT relocation model must be set to static or default!");
+
+ MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>());
do {
MovePCtoLROffset = 0;
MCE.startFunction(MF);
@@ -101,6 +108,9 @@
default:
MCE.emitWordBE(getBinaryCodeForInstr(*I));
break;
+ case TargetInstrInfo:![:label: :label:](https://emoji.discourse-cdn.com/google/label.png?v=12)
+ MCE.EmitLabel(MI.getOperand(0).getImm());
+ break;
case PPC::IMPLICIT_DEF_GPRC:
case PPC::IMPLICIT_DEF_G8RC:
case PPC::IMPLICIT_DEF_F8:
Index: lib/Target/X86/X86CodeEmitter.cpp
--- lib/Target/X86/X86CodeEmitter.cpp (revision 44794)
+++ lib/Target/X86/X86CodeEmitter.cpp (working copy)
@@ -55,6 +55,11 @@
}
void emitInstruction(const MachineInstr &MI);
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<MachineModuleInfo>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
private:
void emitPCRelativeBlockAddress(MachineBasicBlock *MBB);
@@ -96,11 +101,14 @@
assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
MF.getTarget().getRelocationModel() != Reloc::Static) &&
"JIT relocation model must be set to static or default!");
+
+ MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>());
+
II = ((X86TargetMachine&)MF.getTarget()).getInstrInfo();
TD = ((X86TargetMachine&)MF.getTarget()).getTargetData();
Is64BitMode =
((X86TargetMachine&)MF.getTarget()).getSubtarget<X86Subtarget>().is64Bit();
-
+
do {
MCE.startFunction(MF);
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
@@ -577,7 +585,8 @@
case TargetInstrInfo::INLINEASM:
assert(0 && "JIT does not support inline asm!\n");
case TargetInstrInfo:![:label: :label:](https://emoji.discourse-cdn.com/google/label.png?v=12)
- assert(0 && "JIT does not support meta labels!\n");
+ MCE.EmitLabel(MI.getOperand(0).getImm());
+ break;
case X86::IMPLICIT_USE:
case X86::IMPLICIT_DEF:
case X86::IMPLICIT_DEF_GR8:
Index: lib/ExecutionEngine/JIT/JITEmitter.cpp
--- lib/ExecutionEngine/JIT/JITEmitter.cpp (revision 44794)
+++ lib/ExecutionEngine/JIT/JITEmitter.cpp (working copy)
@@ -17,19 +17,31 @@
#include "llvm/Constant.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DwarfEmitter.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/MachineLocation.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRelocation.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/Target/MRegisterInfo.h"
+#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetFrameInfo.h"
+#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetJITInfo.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/System/Disassembler.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/System/Memory.h"
#include <algorithm>
using namespace llvm;
@@ -37,7 +49,10 @@
STATISTIC(NumRelos, "Number of relocations applied");
static JIT *TheJIT = 0;
+extern "C" void __register_frame(void*);
+extern "C" void __register_frame_table(void*);
Can you explain what these are?
+
//===----------------------------------------------------------------------===//
// JIT lazy compilation code.
//
@@ -275,6 +290,71 @@
// JITEmitter code.
//
namespace {
+
+ class DwarfJITEmitter : public DwarfEmitter {
+ JITMemoryManager *MemMgr;
+ const TargetData& TD;
+ TargetMachine &TM;
+ MachineCodeEmitter& MCE;
+ const MRegisterInfo* RI;
+
+ public:
+ DwarfJITEmitter(MachineCodeEmitter &mce, const TargetData& td,
+ TargetMachine& tm) : TD(td), TM(tm), MCE(mce) {
+ RI = TM.getRegisterInfo();
+ MemMgr = JITMemoryManager::CreateDefaultMemManager();
+ }
+
+ unsigned char* EmitExceptionTable(MachineFunction* MF,
+ unsigned char* StartFunction,
+ unsigned char* EndFunction);
+
+ void EmitFrameMoves(intptr_t BaseLabelPtr,
+ const std::vector<MachineMove> &Moves);
+
+ unsigned char* EmitCommonEHFrame(const Function* Personality);
+
+ unsigned char* EmitEHFrame(const Function* Personality,
+ unsigned char* StartBufferPtr,
+ unsigned char* StartFunction,
+ unsigned char* EndFunction,
+ unsigned char* ExceptionTable);
+
+ virtual void startFunction(MachineFunction& F) {
+ MMI->BeginFunction(&F);
+ }
+
+ virtual bool finishFunction(MachineFunction& F,
+ unsigned char* StartFunction,
+ unsigned char* EndFunction) {
+ uintptr_t ActualSize;
+ BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(),
+ ActualSize);
+ BufferEnd = BufferBegin+ActualSize;
+
+ unsigned char* ExceptionTable = EmitExceptionTable(&F, StartFunction,
+ EndFunction);
+
+ unsigned char* Result = 0;
+ unsigned char* EHFramePtr = 0;
+
+ const std::vector<Function *> Personalities = MMI->getPersonalities();
+ EHFramePtr = EmitCommonEHFrame(Personalities[MMI->getPersonalityIndex()]);
+
+ Result = EmitEHFrame(Personalities[Personalities.size() - 1], EHFramePtr,
+ StartFunction, EndFunction, ExceptionTable);
+
+ unsigned char *FnEnd = CurBufferPtr;
+ MemMgr->endFunctionBody(F.getFunction(), BufferBegin, FnEnd);
+ MMI->EndFunction();
+
+ __register_frame(Result);
+
+ return false;
+ }
+
+ };
+
/// JITEmitter - The JIT implementation of the MachineCodeEmitter, which is
/// used to output functions to memory for execution.
class JITEmitter : public MachineCodeEmitter {
@@ -311,6 +391,11 @@
/// Resolver - This contains info about the currently resolved functions.
JITResolver Resolver;
+
+ DwarfJITEmitter *DE;
+
+ std::vector<intptr_t> LabelLocations;
+
public:
JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit) {
MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
@@ -318,9 +403,14 @@
MemMgr->AllocateGOT();
DOUT << "JIT is managing a GOT\n";
}
+ if (ExceptionHandling)
+ DE = new DwarfJITEmitter(*this, *jit.getTargetData(),
+ jit.getTargetMachine());
+
Please don't add getTargetMachine() to jit. MachineCodeEmitter can keep a reference to MachineFunction or something like that.
}
~JITEmitter() {
delete MemMgr;
+ if (ExceptionHandling) delete DE;
}
JITResolver &getJITResolver() { return Resolver; }
@@ -359,11 +449,606 @@
void deallocateMemForFunction(Function *F) {
MemMgr->deallocateMemForFunction(F);
}
+
+ virtual void EmitLabel(uint64_t LabelID) {
+ if (LabelLocations.size() <= LabelID)
+ LabelLocations.resize((LabelID+1)*2);
+ LabelLocations[LabelID] = getCurrentPCValue();
+ }
+
+ virtual intptr_t getLabelAddress(uint64_t LabelID) const {
+ assert(LabelLocations.size() > (unsigned)LabelID &&
+ LabelLocations[LabelID] && "Label not emitted!");
+ return LabelLocations[LabelID];
+ }
+
+ virtual void setModuleInfo(MachineModuleInfo* Info) {
+ if (ExceptionHandling) DE->setModuleInfo(Info);
Doesn't seem to need the check.
+ }
+
private:
void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
};
}
+void DwarfJITEmitter::EmitFrameMoves(intptr_t BaseLabelPtr,
+ const std::vector<MachineMove> &Moves) {
+ unsigned PointerSize = TD.getPointerSize();
+ int stackGrowth =
+ TM.getFrameInfo()->getStackGrowthDirection() ==
+ TargetFrameInfo::StackGrowsUp ?
+ PointerSize : -PointerSize;
+ // TODO bool IsLocal = BaseLabel && strcmp(BaseLabel, "label") == 0;
+ bool IsLocal = BaseLabelPtr;
+
+ for (unsigned i = 0, N = Moves.size(); i < N; ++i) {
+ const MachineMove &Move = Moves[i];
+ unsigned LabelID = Move.getLabelID();
+
+ if (LabelID) {
+ LabelID = MMI->MappedLabel(LabelID);
+
+ // Throw out move if the label is invalid.
+ if (!LabelID) continue;
+ }
+
+ intptr_t LabelPtr = 0;
+ if (LabelID) LabelPtr = MCE.getLabelAddress(LabelID);
+
+ const MachineLocation &Dst = Move.getDestination();
+ const MachineLocation &Src = Move.getSource();
+
+ // Advance row if new location.
+ if (BaseLabelPtr && LabelID && (BaseLabelPtr != LabelPtr || !IsLocal)) {
+ EmitInt8(dwarf::DW_CFA_advance_loc4);
+ if (PointerSize == 8) {
+ EmitInt64(LabelPtr - BaseLabelPtr);
+ } else {
+ EmitInt32(LabelPtr - BaseLabelPtr);
+ }
+
+ BaseLabelPtr = LabelPtr;
+ IsLocal = true;
+ }
+
+ // If advancing cfa.
+ if (Dst.isRegister() && Dst.getRegister() == MachineLocation::VirtualFP) {
+ if (!Src.isRegister()) {
+ if (Src.getRegister() == MachineLocation::VirtualFP) {
+ EmitInt8(dwarf::DW_CFA_def_cfa_offset);
+ } else {
+ EmitInt8(dwarf::DW_CFA_def_cfa);
+ EmitULEB128Bytes(RI->getDwarfRegNum(Src.getRegister(), true));
+ }
+
+ int Offset = -Src.getOffset();
+
+ EmitULEB128Bytes(Offset);
+ } else {
+ assert(0 && "Machine move no supported yet.");
+ }
+ } else if (Src.isRegister() &&
+ Src.getRegister() == MachineLocation::VirtualFP) {
+ if (Dst.isRegister()) {
+ EmitInt8(dwarf::DW_CFA_def_cfa_register);
+ EmitULEB128Bytes(RI->getDwarfRegNum(Dst.getRegister(), true));
+ } else {
+ assert(0 && "Machine move no supported yet.");
+ }
+ } else {
+ unsigned Reg = RI->getDwarfRegNum(Src.getRegister(), true);
+ int Offset = Dst.getOffset() / stackGrowth;
+
+ if (Offset < 0) {
+ EmitInt8(dwarf::DW_CFA_offset_extended_sf);
+ EmitULEB128Bytes(Reg);
+ EmitSLEB128Bytes(Offset);
+ } else if (Reg < 64) {
+ EmitInt8(dwarf::DW_CFA_offset + Reg);
+ EmitULEB128Bytes(Offset);
+ } else {
+ EmitInt8(dwarf::DW_CFA_offset_extended);
+ EmitULEB128Bytes(Reg);
+ EmitULEB128Bytes(Offset);
+ }
+ }
+ }
+}
+
+/// SharedTypeIds - How many leading type ids two landing pads have in common.
+static unsigned SharedTypeIds(const LandingPadInfo *L,
+ const LandingPadInfo *R) {
+ const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;
+ unsigned LSize = LIds.size(), RSize = RIds.size();
+ unsigned MinSize = LSize < RSize ? LSize : RSize;
+ unsigned Count = 0;
+
+ for (; Count != MinSize; ++Count)
+ if (LIds[Count] != RIds[Count])
+ return Count;
+
+ return Count;
+}
+
+/// PadLT - Order landing pads lexicographically by type id.
+static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R) {
+ const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;
+ unsigned LSize = LIds.size(), RSize = RIds.size();
+ unsigned MinSize = LSize < RSize ? LSize : RSize;
+
+ for (unsigned i = 0; i != MinSize; ++i)
+ if (LIds[i] != RIds[i])
+ return LIds[i] < RIds[i];
+
+ return LSize < RSize;
+}
+
+struct KeyInfo {
+ static inline unsigned getEmptyKey() { return -1U; }
+ static inline unsigned getTombstoneKey() { return -2U; }
+ static unsigned getHashValue(const unsigned &Key) { return Key; }
+ static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; }
+ static bool isPod() { return true; }
+};
+
+/// ActionEntry - Structure describing an entry in the actions table.
+struct ActionEntry {
+ int ValueForTypeID; // The value to write - may not be equal to the type id.
+ int NextAction;
+ struct ActionEntry *Previous;
+};
+
+/// PadRange - Structure holding a try-range and the associated landing pad.
+struct PadRange {
+ // The index of the landing pad.
+ unsigned PadIndex;
+ // The index of the begin and end labels in the landing pad's label lists.
+ unsigned RangeIndex;
+};
+
+typedef DenseMap<unsigned, PadRange, KeyInfo> RangeMapType;
+
+/// CallSiteEntry - Structure describing an entry in the call-site table.
+struct CallSiteEntry {
+ unsigned BeginLabel; // zero indicates the start of the function.
+ unsigned EndLabel; // zero indicates the end of the function.
+ unsigned PadLabel; // zero indicates that there is no landing pad.
+ unsigned Action;
+};
+
+unsigned char* DwarfJITEmitter::EmitExceptionTable(MachineFunction* MF,
+ unsigned char* StartFunction,
+ unsigned char* EndFunction) {
+ // Map all labels and get rid of any dead landing pads.
+ MMI->TidyLandingPads();
+
+ const std::vector<GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
+ const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
+ const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+ if (PadInfos.empty()) return 0;
+
+ // Sort the landing pads in order of their type ids. This is used to fold
+ // duplicate actions.
+ SmallVector<const LandingPadInfo *, 64> LandingPads;
+ LandingPads.reserve(PadInfos.size());
+ for (unsigned i = 0, N = PadInfos.size(); i != N; ++i)
+ LandingPads.push_back(&PadInfos[i]);
+ std::sort(LandingPads.begin(), LandingPads.end(), PadLT);
stable_sort instead? Does it matter?
+
+ // Negative type ids index into FilterIds, positive type ids index into
+ // TypeInfos. The value written for a positive type id is just the type
+ // id itself. For a negative type id, however, the value written is the
+ // (negative) byte offset of the corresponding FilterIds entry. The byte
+ // offset is usually equal to the type id, because the FilterIds entries
+ // are written using a variable width encoding which outputs one byte per
+ // entry as long as the value written is not too large, but can differ.
+ // This kind of complication does not occur for positive type ids because
+ // type infos are output using a fixed width encoding.
+ // FilterOffsets[i] holds the byte offset corresponding to FilterIds[i].
+ SmallVector<int, 16> FilterOffsets;
+ FilterOffsets.reserve(FilterIds.size());
+ int Offset = -1;
+ for(std::vector<unsigned>::const_iterator I = FilterIds.begin(),
+ E = FilterIds.end(); I != E; ++I) {
+ FilterOffsets.push_back(Offset);
+ Offset -= AsmPrinter::SizeULEB128(*I);
+ }
+
+ // Compute the actions table and gather the first action index for each
+ // landing pad site.
+ SmallVector<ActionEntry, 32> Actions;
+ SmallVector<unsigned, 64> FirstActions;
+ FirstActions.reserve(LandingPads.size());
+
+ int FirstAction = 0;
+ unsigned SizeActions = 0;
+ for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
+ const LandingPadInfo *LP = LandingPads[i];
+ const std::vector<int> &TypeIds = LP->TypeIds;
+ const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0;
+ unsigned SizeSiteActions = 0;
+
+ if (NumShared < TypeIds.size()) {
+ unsigned SizeAction = 0;
+ ActionEntry *PrevAction = 0;
+
+ if (NumShared) {
+ const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size();
+ assert(Actions.size());
+ PrevAction = &Actions.back();
+ SizeAction = AsmPrinter::SizeSLEB128(PrevAction->NextAction) +
+ AsmPrinter::SizeSLEB128(PrevAction->ValueForTypeID);
+ for (unsigned j = NumShared; j != SizePrevIds; ++j) {
+ SizeAction -= AsmPrinter::SizeSLEB128(PrevAction->ValueForTypeID);
+ SizeAction += -PrevAction->NextAction;
+ PrevAction = PrevAction->Previous;
+ }
+ }
+
+ // Compute the actions.
+ for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) {
+ int TypeID = TypeIds[I];
+ assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
+ int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
+ unsigned SizeTypeID = AsmPrinter::SizeSLEB128(ValueForTypeID);
+
+ int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
+ SizeAction = SizeTypeID + AsmPrinter::SizeSLEB128(NextAction);
+ SizeSiteActions += SizeAction;
+
+ ActionEntry Action = {ValueForTypeID, NextAction, PrevAction};
+ Actions.push_back(Action);
+
+ PrevAction = &Actions.back();
+ }
+
+ // Record the first action of the landing pad site.
+ FirstAction = SizeActions + SizeSiteActions - SizeAction + 1;
+ } // else identical - re-use previous FirstAction
+
+ FirstActions.push_back(FirstAction);
+
+ // Compute this sites contribution to size.
+ SizeActions += SizeSiteActions;
+ }
+
+ // Compute the call-site table. Entries must be ordered by address.
+ SmallVector<CallSiteEntry, 64> CallSites;
+
+ RangeMapType PadMap;
+ for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
+ const LandingPadInfo *LandingPad = LandingPads[i];
+ for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
+ unsigned BeginLabel = LandingPad->BeginLabels[j];
+ assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
+ PadRange P = { i, j };
+ PadMap[BeginLabel] = P;
+ }
+ }
+
+ bool MayThrow = false;
+ unsigned LastLabel = 0;
+ const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
+ for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
+ I != E; ++I) {
+ for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
+ MI != E; ++MI) {
+ if (MI->getOpcode() != TargetInstrInfo::LABEL) {
+ MayThrow |= TII->isCall(MI->getOpcode());
+ continue;
+ }
+
+ unsigned BeginLabel = MI->getOperand(0).getImmedValue();
+ assert(BeginLabel && "Invalid label!");
+
+ if (BeginLabel == LastLabel)
+ MayThrow = false;
+
+ RangeMapType::iterator L = PadMap.find(BeginLabel);
+
+ if (L == PadMap.end())
+ continue;
+
+ PadRange P = L->second;
+ const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
+
+ assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
+ "Inconsistent landing pad map!");
+
+ // If some instruction between the previous try-range and this one may
+ // throw, create a call-site entry with no landing pad for the region
+ // between the try-ranges.
+ if (MayThrow) {
+ CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
+ CallSites.push_back(Site);
+ }
+
+ LastLabel = LandingPad->EndLabels[P.RangeIndex];
+ CallSiteEntry Site = {BeginLabel, LastLabel,
+ LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};
+
+ assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel &&
+ "Invalid landing pad!");
+
+ // Try to merge with the previous call-site.
+ if (CallSites.size()) {
+ CallSiteEntry &Prev = CallSites[CallSites.size()-1];
+ if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
+ // Extend the range of the previous entry.
+ Prev.EndLabel = Site.EndLabel;
+ continue;
+ }
+ }
+
+ // Otherwise, create a new call-site.
+ CallSites.push_back(Site);
+ }
+ }
+ // If some instruction between the previous try-range and the end of the
+ // function may throw, create a call-site entry with no landing pad for the
+ // region following the try-range.
+ if (MayThrow) {
+ CallSiteEntry Site = {LastLabel, 0, 0, 0};
+ CallSites.push_back(Site);
+ }
+
+ // Final tallies.
+ unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start.
+ sizeof(int32_t) + // Site length.
+ sizeof(int32_t)); // Landing pad.
+ for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
+ SizeSites += AsmPrinter::SizeULEB128(CallSites[i].Action);
+
+ unsigned SizeTypes = TypeInfos.size() * TD.getPointerSize();
+
+ unsigned TypeOffset = sizeof(int8_t) + // Call site format
+ // Call-site table length
+ AsmPrinter::SizeULEB128(SizeSites) +
+ SizeSites + SizeActions + SizeTypes;
+
+ unsigned TotalSize = sizeof(int8_t) + // LPStart format
+ sizeof(int8_t) + // TType format
+ AsmPrinter::SizeULEB128(TypeOffset) + // TType base offset
+ TypeOffset;
+
+ unsigned SizeAlign = (4 - TotalSize) & 3;
+
+ // Begin the exception table.
+ EmitAlignment(4);
+ for (unsigned i = 0; i != SizeAlign; ++i) {
+ EmitInt8(0);
+ // Asm->EOL("Padding");
+ }
+
+ unsigned char* DwarfExceptionTable = CurBufferPtr;
+
+ // Emit the header.
+ EmitInt8(dwarf::DW_EH_PE_omit);
+ // Asm->EOL("LPStart format (DW_EH_PE_omit)");
+ EmitInt8(dwarf::DW_EH_PE_absptr);
+ // Asm->EOL("TType format (DW_EH_PE_absptr)");
+ EmitULEB128Bytes(TypeOffset);
+ // Asm->EOL("TType base offset");
+ EmitInt8(dwarf::DW_EH_PE_udata4);
+ // Asm->EOL("Call site format (DW_EH_PE_udata4)");
+ EmitULEB128Bytes(SizeSites);
+ // Asm->EOL("Call-site table length");
+
+ // Emit the landing pad site information.
+ for (unsigned i = 0; i < CallSites.size(); ++i) {
+ CallSiteEntry &S = CallSites[i];
+ intptr_t BeginLabelPtr = 0;
+ intptr_t EndLabelPtr = 0;
+
+ if (!S.BeginLabel) {
+ BeginLabelPtr = (intptr_t)StartFunction;
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(0);
+ else
+ EmitInt64(0);
+ } else {
+ BeginLabelPtr = MCE.getLabelAddress(S.BeginLabel);
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(BeginLabelPtr - (intptr_t)StartFunction);
+ else
+ EmitInt64(BeginLabelPtr - (intptr_t)StartFunction);
+ }
+
+ // Asm->EOL("Region start");
+
+ if (!S.EndLabel) {
+ EndLabelPtr = (intptr_t)EndFunction;
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32((intptr_t)EndFunction - BeginLabelPtr);
+ else
+ EmitInt64((intptr_t)EndFunction - BeginLabelPtr);
+ } else {
+ EndLabelPtr = MCE.getLabelAddress(S.EndLabel);
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(EndLabelPtr - BeginLabelPtr);
+ else
+ EmitInt64(EndLabelPtr - BeginLabelPtr);
+ }
+ //Asm->EOL("Region length");
+
+ if (!S.PadLabel) {
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(0);
+ else
+ EmitInt64(0);
+ } else {
+ unsigned PadLabelPtr = MCE.getLabelAddress(S.PadLabel);
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(PadLabelPtr - (intptr_t)StartFunction);
+ else
+ EmitInt64(PadLabelPtr - (intptr_t)StartFunction);
+ }
+ // Asm->EOL("Landing pad");
+
+ EmitULEB128Bytes(S.Action);
+ // Asm->EOL("Action");
+ }
+
+ // Emit the actions.
+ for (unsigned I = 0, N = Actions.size(); I != N; ++I) {
+ ActionEntry &Action = Actions[I];
+
+ EmitSLEB128Bytes(Action.ValueForTypeID);
+ //Asm->EOL("TypeInfo index");
+ EmitSLEB128Bytes(Action.NextAction);
+ //Asm->EOL("Next action");
+ }
+
+ // Emit the type ids.
+ for (unsigned M = TypeInfos.size(); M; --M) {
+ GlobalVariable *GV = TypeInfos[M - 1];
+
+ if (GV) {
+ if (TD.getPointerSize() == sizeof(int32_t)) {
+ EmitInt32((intptr_t)TheJIT->getOrEmitGlobalVariable(GV));
+ } else {
+ EmitInt64((intptr_t)TheJIT->getOrEmitGlobalVariable(GV));
+ }
+ } else {
+ if (TD.getPointerSize() == sizeof(int32_t))
+ EmitInt32(0);
+ else
+ EmitInt64(0);
+ }
+ // Asm->EOL("TypeInfo");
+ }
+
+ // Emit the filter typeids.
+ for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) {
+ unsigned TypeID = FilterIds[j];
+ EmitULEB128Bytes(TypeID);
+ //Asm->EOL("Filter TypeInfo index");
+ }
+
+ EmitAlignment(4);
+
+ return DwarfExceptionTable;
+}
+
+unsigned char* DwarfJITEmitter::EmitCommonEHFrame(const Function* Personality) {
+ unsigned PointerSize = TD.getPointerSize();
+ int stackGrowth = TM.getFrameInfo()->getStackGrowthDirection() ==
+ TargetFrameInfo::StackGrowsUp ?
+ PointerSize : -PointerSize;
+
+ unsigned char* StartCommonPtr = CurBufferPtr;
+ // EH Common Frame header
+ allocateSpace(PointerSize, 0);
+ unsigned char* FrameCommonBeginPtr = CurBufferPtr;
+ EmitInt32((int)0);
+ EmitInt8(dwarf::DW_CIE_VERSION);
+ EmitString(Personality ? "zPLR" : "zR");
+ EmitULEB128Bytes(1);
+ EmitSLEB128Bytes(stackGrowth);
+ EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true));
+
+ if (Personality) {
+ EmitULEB128Bytes(7);
+
+ if (TM.getTargetAsmInfo()->getNeedsIndirectEncoding())
+ EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 |
+ dwarf::DW_EH_PE_indirect);
+ else
+ EmitInt8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
+
+ if (PointerSize == 8)
+ EmitInt64((intptr_t)TheJIT->getPointerToGlobal(Personality) -
+ (intptr_t)CurBufferPtr);
+ else
+ EmitInt32((intptr_t)TheJIT->getPointerToGlobal(Personality) -
+ (intptr_t)CurBufferPtr);
+
+ EmitULEB128Bytes(dwarf::DW_EH_PE_pcrel);
+
+ } else {
+ EmitULEB128Bytes(1);
+ EmitULEB128Bytes(dwarf::DW_EH_PE_pcrel);
+ }
+
+ std::vector<MachineMove> Moves;
+ RI->getInitialFrameState(Moves);
+ EmitFrameMoves(0, Moves);
+ EmitAlignment(4);
+
+ *((int*)StartCommonPtr) = CurBufferPtr - FrameCommonBeginPtr;
+
+ return StartCommonPtr;
+}
+
+unsigned char* DwarfJITEmitter::EmitEHFrame(const Function* Personality,
+ unsigned char* StartCommonPtr,
+ unsigned char* StartFunction,
+ unsigned char* EndFunction,
+ unsigned char* ExceptionTable) {
+ unsigned PointerSize = TD.getPointerSize();
+
+ // EH frame header.
+ unsigned char* StartEHPtr = CurBufferPtr;
+ allocateSpace(PointerSize, 0);
+ unsigned char* FrameBeginPtr = CurBufferPtr;
+ // FDE CIE Offset
+ if (PointerSize == 8) {
+ EmitInt64(FrameBeginPtr - StartCommonPtr);
+ EmitInt64(StartFunction - CurBufferPtr);
+ EmitInt64(EndFunction - StartFunction);
+ } else {
+ EmitInt32(FrameBeginPtr - StartCommonPtr);
+ EmitInt32(StartFunction - CurBufferPtr);
+ EmitInt32(EndFunction - StartFunction);
+ }
+
+ // If there is a personality and landing pads then point to the language
+ // specific data area in the exception table.
+ if (MMI->getPersonalityIndex()) {
+ EmitULEB128Bytes(4);
+
+ if (!MMI->getLandingPads().empty()) {
+ if (PointerSize == 8)
+ EmitInt64(ExceptionTable - CurBufferPtr);
+ else
+ EmitInt32(ExceptionTable - CurBufferPtr);
+ } else if (PointerSize == 8) {
+ EmitInt64((int)0);
+ } else {
+ EmitInt32((int)0);
+ }
+ } else {
+ EmitULEB128Bytes(0);
+ }
+
+ // Indicate locations of function specific callee saved registers in
+ // frame.
+ EmitFrameMoves((intptr_t)StartFunction, MMI->getFrameMoves());
+
+ EmitAlignment(4);
+
+ // Indicate the size of the table
+ *((int*)StartEHPtr) = CurBufferPtr - StartEHPtr;
+
+ // Double zeroes for the unwind runtime
+ if (PointerSize == 8) {
+ EmitInt64(0);
+ } else {
+ EmitInt32(0);
+ }
+
+ return StartEHPtr;
+}
+
void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
bool DoesntNeedStub) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) {
@@ -413,6 +1098,7 @@
TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr);
MBBLocations.clear();
+ if (ExceptionHandling) DE->startFunction(F);
}
bool JITEmitter::finishFunction(MachineFunction &F) {
@@ -504,6 +1190,7 @@
<< sys::disassembleBuffer(FnStart, FnEnd-FnStart, (uintptr_t)FnStart);
#endif
+ if (ExceptionHandling) DE->finishFunction(F, FnStart, FnEnd);
return false;
}
Index: lib/ExecutionEngine/JIT/JIT.h
--- lib/ExecutionEngine/JIT/JIT.h (revision 44794)
+++ lib/ExecutionEngine/JIT/JIT.h (working copy)
@@ -124,6 +124,9 @@
/// getCodeEmitter - Return the code emitter this JIT is emitting into.
MachineCodeEmitter *getCodeEmitter() const { return MCE; }
+ /// getTargetMachine - Return the target machine
+ TargetMachine &getTargetMachine() const { return TM; }
+
I don't think this belong here. Probably ok for MachineCodeEmitter to keep a reference to MachineFunction.