summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp15
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/EHStreamer.h17
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp149
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Win64Exception.h4
4 files changed, 173 insertions, 12 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
index f112120c1ab..1bc86f6c222 100644
--- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
@@ -121,7 +121,8 @@ computeActionsTable(const SmallVectorImpl<const LandingPadInfo*> &LandingPads,
for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
int TypeID = TypeIds[J];
assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
- int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID;
+ int ValueForTypeID =
+ isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0;
@@ -269,14 +270,14 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
CallSiteEntry Site = {
BeginLabel,
LastLabel,
- LandingPad->LandingPadLabel,
+ LandingPad,
FirstActions[P.PadIndex]
};
// Try to merge with the previous call-site. SJLJ doesn't do this
if (PreviousIsInvoke && !IsSJLJ) {
CallSiteEntry &Prev = CallSites.back();
- if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
+ if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
// Extend the range of the previous entry.
Prev.EndLabel = Site.EndLabel;
continue;
@@ -576,15 +577,15 @@ void EHStreamer::emitExceptionTable() {
// Offset of the landing pad, counted in 16-byte bundles relative to the
// @LPStart address.
- if (!S.PadLabel) {
+ if (!S.LPad) {
if (VerboseAsm)
Asm->OutStreamer.AddComment(" has no landing pad");
Asm->OutStreamer.EmitIntValue(0, 4/*size*/);
} else {
if (VerboseAsm)
Asm->OutStreamer.AddComment(Twine(" jumps to ") +
- S.PadLabel->getName());
- Asm->EmitLabelDifference(S.PadLabel, EHFuncBeginSym, 4);
+ S.LPad->LandingPadLabel->getName());
+ Asm->EmitLabelDifference(S.LPad->LandingPadLabel, EHFuncBeginSym, 4);
}
// Offset of the first associated action record, relative to the start of
@@ -681,7 +682,7 @@ void EHStreamer::emitTypeInfos(unsigned TTypeEncoding) {
unsigned TypeID = *I;
if (VerboseAsm) {
--Entry;
- if (TypeID != 0)
+ if (isFilterEHSelector(TypeID))
Asm->OutStreamer.AddComment("FilterInfo " + Twine(Entry));
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
index e93055ce865..9b316ff00e9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
+++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
@@ -23,6 +23,8 @@ class MachineModuleInfo;
class MachineInstr;
class MachineFunction;
class AsmPrinter;
+class MCSymbol;
+class MCSymbolRefExpr;
template <typename T>
class SmallVectorImpl;
@@ -60,11 +62,11 @@ protected:
/// Structure describing an entry in the call-site table.
struct CallSiteEntry {
// The 'try-range' is BeginLabel .. EndLabel.
- MCSymbol *BeginLabel; // zero indicates the start of the function.
- MCSymbol *EndLabel; // zero indicates the end of the function.
+ MCSymbol *BeginLabel; // Null indicates the start of the function.
+ MCSymbol *EndLabel; // Null indicates the end of the function.
- // The landing pad starts at PadLabel.
- MCSymbol *PadLabel; // zero indicates that there is no landing pad.
+ // LPad contains the landing pad start labels.
+ const LandingPadInfo *LPad; // Null indicates that there is no landing pad.
unsigned Action;
};
@@ -112,6 +114,13 @@ protected:
virtual void emitTypeInfos(unsigned TTypeEncoding);
+ // Helpers for for identifying what kind of clause an EH typeid or selector
+ // corresponds to. Negative selectors are for filter clauses, the zero
+ // selector is for cleanups, and positive selectors are for catch clauses.
+ static bool isFilterEHSelector(int Selector) { return Selector < 0; }
+ static bool isCleanupEHSelector(int Selector) { return Selector == 0; }
+ static bool isCatchEHSelector(int Selector) { return Selector > 0; }
+
public:
EHStreamer(AsmPrinter *A);
virtual ~EHStreamer();
diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
index 0f0ad755835..2138cb9514f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
@@ -99,9 +99,156 @@ void Win64Exception::endFunction(const MachineFunction *) {
if (shouldEmitPersonality) {
Asm->OutStreamer.PushSection();
+
+ // Emit an UNWIND_INFO struct describing the prologue.
Asm->OutStreamer.EmitWinEHHandlerData();
- emitExceptionTable();
+
+ // Emit either MSVC-compatible tables or the usual Itanium-style LSDA after
+ // the UNWIND_INFO struct.
+ if (Asm->MAI->getExceptionHandlingType() == ExceptionHandling::MSVC) {
+ const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];
+ if (Per->getName() == "__C_specific_handler")
+ emitCSpecificHandlerTable();
+ else
+ report_fatal_error(Twine("unexpected personality function: ") +
+ Per->getName());
+ } else {
+ emitExceptionTable();
+ }
+
Asm->OutStreamer.PopSection();
}
Asm->OutStreamer.EmitWinCFIEndProc();
}
+
+const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
+ return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
+ Asm->OutContext);
+}
+
+/// Emit the language-specific data that __C_specific_handler expects. This
+/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
+/// up after faults with __try, __except, and __finally. The typeinfo values
+/// are not really RTTI data, but pointers to filter functions that return an
+/// integer (1, 0, or -1) indicating how to handle the exception. For __finally
+/// blocks and other cleanups, the landing pad label is zero, and the filter
+/// function is actually a cleanup handler with the same prototype. A catch-all
+/// entry is modeled with a null filter function field and a non-zero landing
+/// pad label.
+///
+/// Possible filter function return values:
+/// EXCEPTION_EXECUTE_HANDLER (1):
+/// Jump to the landing pad label after cleanups.
+/// EXCEPTION_CONTINUE_SEARCH (0):
+/// Continue searching this table or continue unwinding.
+/// EXCEPTION_CONTINUE_EXECUTION (-1):
+/// Resume execution at the trapping PC.
+///
+/// Inferred table structure:
+/// struct Table {
+/// int NumEntries;
+/// struct Entry {
+/// imagerel32 LabelStart;
+/// imagerel32 LabelEnd;
+/// imagerel32 FilterOrFinally; // Zero means catch-all.
+/// imagerel32 LabelLPad; // Zero means __finally.
+/// } Entries[NumEntries];
+/// };
+void Win64Exception::emitCSpecificHandlerTable() {
+ const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+
+ // Simplifying assumptions for first implementation:
+ // - Cleanups are not implemented.
+ // - Filters are not implemented.
+
+ // The Itanium LSDA table sorts similar landing pads together to simplify the
+ // actions table, but we don't need that.
+ SmallVector<const LandingPadInfo *, 64> LandingPads;
+ LandingPads.reserve(PadInfos.size());
+ for (const auto &LP : PadInfos)
+ LandingPads.push_back(&LP);
+
+ // Compute label ranges for call sites as we would for the Itanium LSDA, but
+ // use an all zero action table because we aren't using these actions.
+ SmallVector<unsigned, 64> FirstActions;
+ FirstActions.resize(LandingPads.size());
+ SmallVector<CallSiteEntry, 64> CallSites;
+ computeCallSiteTable(CallSites, LandingPads, FirstActions);
+
+ MCSymbol *EHFuncBeginSym =
+ Asm->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber());
+ MCSymbol *EHFuncEndSym =
+ Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber());
+
+ // Emit the number of table entries.
+ unsigned NumEntries = 0;
+ for (const CallSiteEntry &CSE : CallSites) {
+ if (!CSE.LPad)
+ continue; // Ignore gaps.
+ for (int Selector : CSE.LPad->TypeIds) {
+ // Ignore C++ filter clauses in SEH.
+ // FIXME: Implement cleanup clauses.
+ if (isCatchEHSelector(Selector))
+ ++NumEntries;
+ }
+ }
+ Asm->OutStreamer.EmitIntValue(NumEntries, 4);
+
+ // Emit the four-label records for each call site entry. The table has to be
+ // sorted in layout order, and the call sites should already be sorted.
+ for (const CallSiteEntry &CSE : CallSites) {
+ // Ignore gaps. Unlike the Itanium model, unwinding through a frame without
+ // an EH table entry will propagate the exception rather than terminating
+ // the program.
+ if (!CSE.LPad)
+ continue;
+ const LandingPadInfo *LPad = CSE.LPad;
+
+ // Compute the label range. We may reuse the function begin and end labels
+ // rather than forming new ones.
+ const MCExpr *Begin =
+ createImageRel32(CSE.BeginLabel ? CSE.BeginLabel : EHFuncBeginSym);
+ const MCExpr *End;
+ if (CSE.EndLabel) {
+ // The interval is half-open, so we have to add one to include the return
+ // address of the last invoke in the range.
+ End = MCBinaryExpr::CreateAdd(createImageRel32(CSE.EndLabel),
+ MCConstantExpr::Create(1, Asm->OutContext),
+ Asm->OutContext);
+ } else {
+ End = createImageRel32(EHFuncEndSym);
+ }
+
+ // These aren't really type info globals, they are actually pointers to
+ // filter functions ordered by selector. The zero selector is used for
+ // cleanups, so slot zero corresponds to selector 1.
+ const std::vector<const GlobalValue *> &SelectorToFilter = MMI->getTypeInfos();
+
+ // Do a parallel iteration across typeids and clause labels, skipping filter
+ // clauses.
+ assert(LPad->TypeIds.size() == LPad->ClauseLabels.size());
+ for (size_t I = 0, E = LPad->TypeIds.size(); I < E; ++I) {
+ // AddLandingPadInfo stores the clauses in reverse, but there is a FIXME
+ // to change that.
+ int Selector = LPad->TypeIds[E - I - 1];
+ MCSymbol *ClauseLabel = LPad->ClauseLabels[I];
+
+ // Ignore C++ filter clauses in SEH.
+ // FIXME: Implement cleanup clauses.
+ if (!isCatchEHSelector(Selector))
+ continue;
+
+ Asm->OutStreamer.EmitValue(Begin, 4);
+ Asm->OutStreamer.EmitValue(End, 4);
+ if (isCatchEHSelector(Selector)) {
+ assert(unsigned(Selector - 1) < SelectorToFilter.size());
+ const GlobalValue *TI = SelectorToFilter[Selector - 1];
+ if (TI) // Emit the filter function pointer.
+ Asm->OutStreamer.EmitValue(createImageRel32(Asm->getSymbol(TI)), 4);
+ else // Otherwise, this is a "catch i8* null", or catch all.
+ Asm->OutStreamer.EmitIntValue(0, 4);
+ }
+ Asm->OutStreamer.EmitValue(createImageRel32(ClauseLabel), 4);
+ }
+ }
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
index 538e1328157..b2d5d1bce56 100644
--- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
+++ b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
@@ -29,6 +29,10 @@ class Win64Exception : public EHStreamer {
/// Per-function flag to indicate if frame moves info should be emitted.
bool shouldEmitMoves;
+ void emitCSpecificHandlerTable();
+
+ const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value);
+
public:
//===--------------------------------------------------------------------===//
// Main entry points.
OpenPOWER on IntegriCloud