1149178d9SEugene Zelenko //===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===//
28076cab0SSaleem Abdulrasool //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68076cab0SSaleem Abdulrasool //
78076cab0SSaleem Abdulrasool //===----------------------------------------------------------------------===//
88076cab0SSaleem Abdulrasool //
98076cab0SSaleem Abdulrasool // This file contains support for writing exception info into assembly files.
108076cab0SSaleem Abdulrasool //
118076cab0SSaleem Abdulrasool //===----------------------------------------------------------------------===//
128076cab0SSaleem Abdulrasool 
138076cab0SSaleem Abdulrasool #include "EHStreamer.h"
14149178d9SEugene Zelenko #include "llvm/ADT/SmallVector.h"
15149178d9SEugene Zelenko #include "llvm/ADT/Twine.h"
16149178d9SEugene Zelenko #include "llvm/ADT/iterator_range.h"
17149178d9SEugene Zelenko #include "llvm/BinaryFormat/Dwarf.h"
188076cab0SSaleem Abdulrasool #include "llvm/CodeGen/AsmPrinter.h"
198076cab0SSaleem Abdulrasool #include "llvm/CodeGen/MachineFunction.h"
208076cab0SSaleem Abdulrasool #include "llvm/CodeGen/MachineInstr.h"
21149178d9SEugene Zelenko #include "llvm/CodeGen/MachineOperand.h"
228076cab0SSaleem Abdulrasool #include "llvm/IR/Function.h"
238076cab0SSaleem Abdulrasool #include "llvm/MC/MCAsmInfo.h"
24149178d9SEugene Zelenko #include "llvm/MC/MCContext.h"
258076cab0SSaleem Abdulrasool #include "llvm/MC/MCStreamer.h"
268076cab0SSaleem Abdulrasool #include "llvm/MC/MCSymbol.h"
27149178d9SEugene Zelenko #include "llvm/MC/MCTargetOptions.h"
28149178d9SEugene Zelenko #include "llvm/Support/Casting.h"
298076cab0SSaleem Abdulrasool #include "llvm/Support/LEB128.h"
306054e650SDavid Blaikie #include "llvm/Target/TargetLoweringObjectFile.h"
31149178d9SEugene Zelenko #include <algorithm>
32149178d9SEugene Zelenko #include <cassert>
33149178d9SEugene Zelenko #include <cstdint>
34149178d9SEugene Zelenko #include <vector>
358076cab0SSaleem Abdulrasool 
368076cab0SSaleem Abdulrasool using namespace llvm;
378076cab0SSaleem Abdulrasool 
EHStreamer(AsmPrinter * A)38dc4263c7SRafael Espindola EHStreamer::EHStreamer(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}
398076cab0SSaleem Abdulrasool 
40149178d9SEugene Zelenko EHStreamer::~EHStreamer() = default;
418076cab0SSaleem Abdulrasool 
428076cab0SSaleem Abdulrasool /// How many leading type ids two landing pads have in common.
sharedTypeIDs(const LandingPadInfo * L,const LandingPadInfo * R)438076cab0SSaleem Abdulrasool unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L,
448076cab0SSaleem Abdulrasool                                    const LandingPadInfo *R) {
458076cab0SSaleem Abdulrasool   const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;
46bd08a87cSFangrui Song   return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end())
47bd08a87cSFangrui Song              .first -
48bd08a87cSFangrui Song          LIds.begin();
498076cab0SSaleem Abdulrasool }
508076cab0SSaleem Abdulrasool 
518076cab0SSaleem Abdulrasool /// Compute the actions table and gather the first action index for each landing
528076cab0SSaleem Abdulrasool /// pad site.
computeActionsTable(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,SmallVectorImpl<ActionEntry> & Actions,SmallVectorImpl<unsigned> & FirstActions)53d09b4169SRafael Espindola void EHStreamer::computeActionsTable(
54d09b4169SRafael Espindola     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
558076cab0SSaleem Abdulrasool     SmallVectorImpl<ActionEntry> &Actions,
568076cab0SSaleem Abdulrasool     SmallVectorImpl<unsigned> &FirstActions) {
578076cab0SSaleem Abdulrasool   // The action table follows the call-site table in the LSDA. The individual
588076cab0SSaleem Abdulrasool   // records are of two types:
598076cab0SSaleem Abdulrasool   //
608076cab0SSaleem Abdulrasool   //   * Catch clause
618076cab0SSaleem Abdulrasool   //   * Exception specification
628076cab0SSaleem Abdulrasool   //
638076cab0SSaleem Abdulrasool   // The two record kinds have the same format, with only small differences.
648076cab0SSaleem Abdulrasool   // They are distinguished by the "switch value" field: Catch clauses
658076cab0SSaleem Abdulrasool   // (TypeInfos) have strictly positive switch values, and exception
668076cab0SSaleem Abdulrasool   // specifications (FilterIds) have strictly negative switch values. Value 0
678076cab0SSaleem Abdulrasool   // indicates a catch-all clause.
688076cab0SSaleem Abdulrasool   //
698076cab0SSaleem Abdulrasool   // Negative type IDs index into FilterIds. Positive type IDs index into
708076cab0SSaleem Abdulrasool   // TypeInfos.  The value written for a positive type ID is just the type ID
718076cab0SSaleem Abdulrasool   // itself.  For a negative type ID, however, the value written is the
728076cab0SSaleem Abdulrasool   // (negative) byte offset of the corresponding FilterIds entry.  The byte
738076cab0SSaleem Abdulrasool   // offset is usually equal to the type ID (because the FilterIds entries are
748076cab0SSaleem Abdulrasool   // written using a variable width encoding, which outputs one byte per entry
758076cab0SSaleem Abdulrasool   // as long as the value written is not too large) but can differ.  This kind
768076cab0SSaleem Abdulrasool   // of complication does not occur for positive type IDs because type infos are
778076cab0SSaleem Abdulrasool   // output using a fixed width encoding.  FilterOffsets[i] holds the byte
788076cab0SSaleem Abdulrasool   // offset corresponding to FilterIds[i].
798076cab0SSaleem Abdulrasool 
80d0ee66c2SMatthias Braun   const std::vector<unsigned> &FilterIds = Asm->MF->getFilterIds();
818076cab0SSaleem Abdulrasool   SmallVector<int, 16> FilterOffsets;
828076cab0SSaleem Abdulrasool   FilterOffsets.reserve(FilterIds.size());
838076cab0SSaleem Abdulrasool   int Offset = -1;
848076cab0SSaleem Abdulrasool 
85c5e90a88SKazu Hirata   for (unsigned FilterId : FilterIds) {
868076cab0SSaleem Abdulrasool     FilterOffsets.push_back(Offset);
87c5e90a88SKazu Hirata     Offset -= getULEB128Size(FilterId);
888076cab0SSaleem Abdulrasool   }
898076cab0SSaleem Abdulrasool 
908076cab0SSaleem Abdulrasool   FirstActions.reserve(LandingPads.size());
918076cab0SSaleem Abdulrasool 
928076cab0SSaleem Abdulrasool   int FirstAction = 0;
939d224346SHeejin Ahn   unsigned SizeActions = 0; // Total size of all action entries for a function
948076cab0SSaleem Abdulrasool   const LandingPadInfo *PrevLPI = nullptr;
958076cab0SSaleem Abdulrasool 
96c5e90a88SKazu Hirata   for (const LandingPadInfo *LPI : LandingPads) {
978076cab0SSaleem Abdulrasool     const std::vector<int> &TypeIds = LPI->TypeIds;
988076cab0SSaleem Abdulrasool     unsigned NumShared = PrevLPI ? sharedTypeIDs(LPI, PrevLPI) : 0;
999d224346SHeejin Ahn     unsigned SizeSiteActions = 0; // Total size of all entries for a landingpad
1008076cab0SSaleem Abdulrasool 
1018076cab0SSaleem Abdulrasool     if (NumShared < TypeIds.size()) {
1029d224346SHeejin Ahn       // Size of one action entry (typeid + next action)
1039d224346SHeejin Ahn       unsigned SizeActionEntry = 0;
1048076cab0SSaleem Abdulrasool       unsigned PrevAction = (unsigned)-1;
1058076cab0SSaleem Abdulrasool 
1068076cab0SSaleem Abdulrasool       if (NumShared) {
1078076cab0SSaleem Abdulrasool         unsigned SizePrevIds = PrevLPI->TypeIds.size();
1088076cab0SSaleem Abdulrasool         assert(Actions.size());
1098076cab0SSaleem Abdulrasool         PrevAction = Actions.size() - 1;
1109d224346SHeejin Ahn         SizeActionEntry = getSLEB128Size(Actions[PrevAction].NextAction) +
1118076cab0SSaleem Abdulrasool                           getSLEB128Size(Actions[PrevAction].ValueForTypeID);
1128076cab0SSaleem Abdulrasool 
1138076cab0SSaleem Abdulrasool         for (unsigned j = NumShared; j != SizePrevIds; ++j) {
1148076cab0SSaleem Abdulrasool           assert(PrevAction != (unsigned)-1 && "PrevAction is invalid!");
1159d224346SHeejin Ahn           SizeActionEntry -= getSLEB128Size(Actions[PrevAction].ValueForTypeID);
1169d224346SHeejin Ahn           SizeActionEntry += -Actions[PrevAction].NextAction;
1178076cab0SSaleem Abdulrasool           PrevAction = Actions[PrevAction].Previous;
1188076cab0SSaleem Abdulrasool         }
1198076cab0SSaleem Abdulrasool       }
1208076cab0SSaleem Abdulrasool 
1218076cab0SSaleem Abdulrasool       // Compute the actions.
1228076cab0SSaleem Abdulrasool       for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
1238076cab0SSaleem Abdulrasool         int TypeID = TypeIds[J];
1248076cab0SSaleem Abdulrasool         assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
1250a57f655SReid Kleckner         int ValueForTypeID =
1260a57f655SReid Kleckner             isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
1278076cab0SSaleem Abdulrasool         unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
1288076cab0SSaleem Abdulrasool 
1299d224346SHeejin Ahn         int NextAction = SizeActionEntry ? -(SizeActionEntry + SizeTypeID) : 0;
1309d224346SHeejin Ahn         SizeActionEntry = SizeTypeID + getSLEB128Size(NextAction);
1319d224346SHeejin Ahn         SizeSiteActions += SizeActionEntry;
1328076cab0SSaleem Abdulrasool 
1338076cab0SSaleem Abdulrasool         ActionEntry Action = { ValueForTypeID, NextAction, PrevAction };
1348076cab0SSaleem Abdulrasool         Actions.push_back(Action);
1358076cab0SSaleem Abdulrasool         PrevAction = Actions.size() - 1;
1368076cab0SSaleem Abdulrasool       }
1378076cab0SSaleem Abdulrasool 
1388076cab0SSaleem Abdulrasool       // Record the first action of the landing pad site.
1399d224346SHeejin Ahn       FirstAction = SizeActions + SizeSiteActions - SizeActionEntry + 1;
1408076cab0SSaleem Abdulrasool     } // else identical - re-use previous FirstAction
1418076cab0SSaleem Abdulrasool 
142d72f78e7SEric Christopher     // Information used when creating the call-site table. The action record
1438076cab0SSaleem Abdulrasool     // field of the call site record is the offset of the first associated
1448076cab0SSaleem Abdulrasool     // action record, relative to the start of the actions table. This value is
1458076cab0SSaleem Abdulrasool     // biased by 1 (1 indicating the start of the actions table), and 0
1468076cab0SSaleem Abdulrasool     // indicates that there are no actions.
1478076cab0SSaleem Abdulrasool     FirstActions.push_back(FirstAction);
1488076cab0SSaleem Abdulrasool 
1498076cab0SSaleem Abdulrasool     // Compute this sites contribution to size.
1508076cab0SSaleem Abdulrasool     SizeActions += SizeSiteActions;
1518076cab0SSaleem Abdulrasool 
1528076cab0SSaleem Abdulrasool     PrevLPI = LPI;
1538076cab0SSaleem Abdulrasool   }
1548076cab0SSaleem Abdulrasool }
1558076cab0SSaleem Abdulrasool 
1568076cab0SSaleem Abdulrasool /// Return `true' if this is a call to a function marked `nounwind'. Return
1578076cab0SSaleem Abdulrasool /// `false' otherwise.
callToNoUnwindFunction(const MachineInstr * MI)1588076cab0SSaleem Abdulrasool bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
1598076cab0SSaleem Abdulrasool   assert(MI->isCall() && "This should be a call instruction!");
1608076cab0SSaleem Abdulrasool 
1618076cab0SSaleem Abdulrasool   bool MarkedNoUnwind = false;
1628076cab0SSaleem Abdulrasool   bool SawFunc = false;
1638076cab0SSaleem Abdulrasool 
164bfd5dd15SKazu Hirata   for (const MachineOperand &MO : MI->operands()) {
1658076cab0SSaleem Abdulrasool     if (!MO.isGlobal()) continue;
1668076cab0SSaleem Abdulrasool 
1678076cab0SSaleem Abdulrasool     const Function *F = dyn_cast<Function>(MO.getGlobal());
1688076cab0SSaleem Abdulrasool     if (!F) continue;
1698076cab0SSaleem Abdulrasool 
1708076cab0SSaleem Abdulrasool     if (SawFunc) {
1718076cab0SSaleem Abdulrasool       // Be conservative. If we have more than one function operand for this
1728076cab0SSaleem Abdulrasool       // call, then we can't make the assumption that it's the callee and
1738076cab0SSaleem Abdulrasool       // not a parameter to the call.
1748076cab0SSaleem Abdulrasool       //
1758076cab0SSaleem Abdulrasool       // FIXME: Determine if there's a way to say that `F' is the callee or
1768076cab0SSaleem Abdulrasool       // parameter.
1778076cab0SSaleem Abdulrasool       MarkedNoUnwind = false;
1788076cab0SSaleem Abdulrasool       break;
1798076cab0SSaleem Abdulrasool     }
1808076cab0SSaleem Abdulrasool 
1818076cab0SSaleem Abdulrasool     MarkedNoUnwind = F->doesNotThrow();
1828076cab0SSaleem Abdulrasool     SawFunc = true;
1838076cab0SSaleem Abdulrasool   }
1848076cab0SSaleem Abdulrasool 
1858076cab0SSaleem Abdulrasool   return MarkedNoUnwind;
1868076cab0SSaleem Abdulrasool }
1878076cab0SSaleem Abdulrasool 
computePadMap(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,RangeMapType & PadMap)188cde33036SDavid Majnemer void EHStreamer::computePadMap(
189cde33036SDavid Majnemer     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
190cde33036SDavid Majnemer     RangeMapType &PadMap) {
191cde33036SDavid Majnemer   // Invokes and nounwind calls have entries in PadMap (due to being bracketed
192cde33036SDavid Majnemer   // by try-range labels when lowered).  Ordinary calls do not, so appropriate
193cde33036SDavid Majnemer   // try-ranges for them need be deduced so we can put them in the LSDA.
194cde33036SDavid Majnemer   for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
195cde33036SDavid Majnemer     const LandingPadInfo *LandingPad = LandingPads[i];
196cde33036SDavid Majnemer     for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
197cde33036SDavid Majnemer       MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
198cde33036SDavid Majnemer       assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
199cde33036SDavid Majnemer       PadRange P = { i, j };
200cde33036SDavid Majnemer       PadMap[BeginLabel] = P;
201cde33036SDavid Majnemer     }
202cde33036SDavid Majnemer   }
203cde33036SDavid Majnemer }
204cde33036SDavid Majnemer 
2058076cab0SSaleem Abdulrasool /// Compute the call-site table.  The entry for an invoke has a try-range
2068076cab0SSaleem Abdulrasool /// containing the call, a non-zero landing pad, and an appropriate action.  The
2078076cab0SSaleem Abdulrasool /// entry for an ordinary call has a try-range containing the call and zero for
2088076cab0SSaleem Abdulrasool /// the landing pad and the action.  Calls marked 'nounwind' have no entry and
2098076cab0SSaleem Abdulrasool /// must not be contained in the try-range of any entry - they form gaps in the
2108076cab0SSaleem Abdulrasool /// table.  Entries must be ordered by try-range address.
2118955950cSRahman Lavaee ///
2128955950cSRahman Lavaee /// Call-sites are split into one or more call-site ranges associated with
2138955950cSRahman Lavaee /// different sections of the function.
2148955950cSRahman Lavaee ///
2158955950cSRahman Lavaee ///   - Without -basic-block-sections, all call-sites are grouped into one
2168955950cSRahman Lavaee ///     call-site-range corresponding to the function section.
2178955950cSRahman Lavaee ///
2188955950cSRahman Lavaee ///   - With -basic-block-sections, one call-site range is created for each
2198955950cSRahman Lavaee ///     section, with its FragmentBeginLabel and FragmentEndLabel respectively
2208955950cSRahman Lavaee //      set to the beginning and ending of the corresponding section and its
2218955950cSRahman Lavaee //      ExceptionLabel set to the exception symbol dedicated for this section.
2228955950cSRahman Lavaee //      Later, one LSDA header will be emitted for each call-site range with its
2238955950cSRahman Lavaee //      call-sites following. The action table and type info table will be
2248955950cSRahman Lavaee //      shared across all ranges.
computeCallSiteTable(SmallVectorImpl<CallSiteEntry> & CallSites,SmallVectorImpl<CallSiteRange> & CallSiteRanges,const SmallVectorImpl<const LandingPadInfo * > & LandingPads,const SmallVectorImpl<unsigned> & FirstActions)2258955950cSRahman Lavaee void EHStreamer::computeCallSiteTable(
2268955950cSRahman Lavaee     SmallVectorImpl<CallSiteEntry> &CallSites,
2278955950cSRahman Lavaee     SmallVectorImpl<CallSiteRange> &CallSiteRanges,
2288076cab0SSaleem Abdulrasool     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
2298076cab0SSaleem Abdulrasool     const SmallVectorImpl<unsigned> &FirstActions) {
230f2acbbafSReid Kleckner   RangeMapType PadMap;
231cde33036SDavid Majnemer   computePadMap(LandingPads, PadMap);
232f2acbbafSReid Kleckner 
2338076cab0SSaleem Abdulrasool   // The end label of the previous invoke or nounwind try-range.
234bee68b29SFangrui Song   MCSymbol *LastLabel = Asm->getFunctionBegin();
2358076cab0SSaleem Abdulrasool 
2368076cab0SSaleem Abdulrasool   // Whether there is a potentially throwing instruction (currently this means
2378076cab0SSaleem Abdulrasool   // an ordinary call) between the end of the previous try-range and now.
2388076cab0SSaleem Abdulrasool   bool SawPotentiallyThrowing = false;
2398076cab0SSaleem Abdulrasool 
2408076cab0SSaleem Abdulrasool   // Whether the last CallSite entry was for an invoke.
2418076cab0SSaleem Abdulrasool   bool PreviousIsInvoke = false;
2428076cab0SSaleem Abdulrasool 
24393acac6cSReid Kleckner   bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
24493acac6cSReid Kleckner 
2458076cab0SSaleem Abdulrasool   // Visit all instructions in order of address.
2468076cab0SSaleem Abdulrasool   for (const auto &MBB : *Asm->MF) {
2478955950cSRahman Lavaee     if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) {
2488955950cSRahman Lavaee       // We start a call-site range upon function entry and at the beginning of
2498955950cSRahman Lavaee       // every basic block section.
2508955950cSRahman Lavaee       CallSiteRanges.push_back(
2518955950cSRahman Lavaee           {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel,
2528955950cSRahman Lavaee            Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel,
2538955950cSRahman Lavaee            Asm->getMBBExceptionSym(MBB), CallSites.size()});
2548955950cSRahman Lavaee       PreviousIsInvoke = false;
2558955950cSRahman Lavaee       SawPotentiallyThrowing = false;
2568955950cSRahman Lavaee       LastLabel = nullptr;
2578955950cSRahman Lavaee     }
2588955950cSRahman Lavaee 
2598955950cSRahman Lavaee     if (MBB.isEHPad())
2608955950cSRahman Lavaee       CallSiteRanges.back().IsLPRange = true;
2618955950cSRahman Lavaee 
2628076cab0SSaleem Abdulrasool     for (const auto &MI : MBB) {
2638076cab0SSaleem Abdulrasool       if (!MI.isEHLabel()) {
2648076cab0SSaleem Abdulrasool         if (MI.isCall())
2658076cab0SSaleem Abdulrasool           SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
2668076cab0SSaleem Abdulrasool         continue;
2678076cab0SSaleem Abdulrasool       }
2688076cab0SSaleem Abdulrasool 
2698076cab0SSaleem Abdulrasool       // End of the previous try-range?
2708076cab0SSaleem Abdulrasool       MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
2718076cab0SSaleem Abdulrasool       if (BeginLabel == LastLabel)
2728076cab0SSaleem Abdulrasool         SawPotentiallyThrowing = false;
2738076cab0SSaleem Abdulrasool 
2748076cab0SSaleem Abdulrasool       // Beginning of a new try-range?
2758076cab0SSaleem Abdulrasool       RangeMapType::const_iterator L = PadMap.find(BeginLabel);
2768076cab0SSaleem Abdulrasool       if (L == PadMap.end())
2778076cab0SSaleem Abdulrasool         // Nope, it was just some random label.
2788076cab0SSaleem Abdulrasool         continue;
2798076cab0SSaleem Abdulrasool 
2808076cab0SSaleem Abdulrasool       const PadRange &P = L->second;
2818076cab0SSaleem Abdulrasool       const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
2828076cab0SSaleem Abdulrasool       assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
2838076cab0SSaleem Abdulrasool              "Inconsistent landing pad map!");
2848076cab0SSaleem Abdulrasool 
285a65d8c5dSjasonliu       // For Dwarf and AIX exception handling (SjLj handling doesn't use this).
286a65d8c5dSjasonliu       // If some instruction between the previous try-range and this one may
287a65d8c5dSjasonliu       // throw, create a call-site entry with no landing pad for the region
288a65d8c5dSjasonliu       // between the try-ranges.
289a65d8c5dSjasonliu       if (SawPotentiallyThrowing &&
290a65d8c5dSjasonliu           (Asm->MAI->usesCFIForEH() ||
291a65d8c5dSjasonliu            Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) {
292bee68b29SFangrui Song         CallSites.push_back({LastLabel, BeginLabel, nullptr, 0});
2938076cab0SSaleem Abdulrasool         PreviousIsInvoke = false;
2948076cab0SSaleem Abdulrasool       }
2958076cab0SSaleem Abdulrasool 
2968076cab0SSaleem Abdulrasool       LastLabel = LandingPad->EndLabels[P.RangeIndex];
2978076cab0SSaleem Abdulrasool       assert(BeginLabel && LastLabel && "Invalid landing pad!");
2988076cab0SSaleem Abdulrasool 
2998076cab0SSaleem Abdulrasool       if (!LandingPad->LandingPadLabel) {
3008076cab0SSaleem Abdulrasool         // Create a gap.
3018076cab0SSaleem Abdulrasool         PreviousIsInvoke = false;
3028076cab0SSaleem Abdulrasool       } else {
3038076cab0SSaleem Abdulrasool         // This try-range is for an invoke.
3048076cab0SSaleem Abdulrasool         CallSiteEntry Site = {
3058076cab0SSaleem Abdulrasool           BeginLabel,
3068076cab0SSaleem Abdulrasool           LastLabel,
3070a57f655SReid Kleckner           LandingPad,
3088076cab0SSaleem Abdulrasool           FirstActions[P.PadIndex]
3098076cab0SSaleem Abdulrasool         };
3108076cab0SSaleem Abdulrasool 
3118076cab0SSaleem Abdulrasool         // Try to merge with the previous call-site. SJLJ doesn't do this
31293acac6cSReid Kleckner         if (PreviousIsInvoke && !IsSJLJ) {
3138076cab0SSaleem Abdulrasool           CallSiteEntry &Prev = CallSites.back();
3140a57f655SReid Kleckner           if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
3158076cab0SSaleem Abdulrasool             // Extend the range of the previous entry.
3168076cab0SSaleem Abdulrasool             Prev.EndLabel = Site.EndLabel;
3178076cab0SSaleem Abdulrasool             continue;
3188076cab0SSaleem Abdulrasool           }
3198076cab0SSaleem Abdulrasool         }
3208076cab0SSaleem Abdulrasool 
3218076cab0SSaleem Abdulrasool         // Otherwise, create a new call-site.
32293acac6cSReid Kleckner         if (!IsSJLJ)
3238076cab0SSaleem Abdulrasool           CallSites.push_back(Site);
3248076cab0SSaleem Abdulrasool         else {
3258076cab0SSaleem Abdulrasool           // SjLj EH must maintain the call sites in the order assigned
3268076cab0SSaleem Abdulrasool           // to them by the SjLjPrepare pass.
327d0ee66c2SMatthias Braun           unsigned SiteNo = Asm->MF->getCallSiteBeginLabel(BeginLabel);
3288076cab0SSaleem Abdulrasool           if (CallSites.size() < SiteNo)
3298076cab0SSaleem Abdulrasool             CallSites.resize(SiteNo);
3308076cab0SSaleem Abdulrasool           CallSites[SiteNo - 1] = Site;
3318076cab0SSaleem Abdulrasool         }
3328076cab0SSaleem Abdulrasool         PreviousIsInvoke = true;
3338076cab0SSaleem Abdulrasool       }
3348076cab0SSaleem Abdulrasool     }
3358076cab0SSaleem Abdulrasool 
3368955950cSRahman Lavaee     // We end the call-site range upon function exit and at the end of every
3378955950cSRahman Lavaee     // basic block section.
3388955950cSRahman Lavaee     if (&MBB == &Asm->MF->back() || MBB.isEndSection()) {
3398076cab0SSaleem Abdulrasool       // If some instruction between the previous try-range and the end of the
3408955950cSRahman Lavaee       // function may throw, create a call-site entry with no landing pad for
3418955950cSRahman Lavaee       // the region following the try-range.
3428955950cSRahman Lavaee       if (SawPotentiallyThrowing && !IsSJLJ) {
3438955950cSRahman Lavaee         CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel,
3448955950cSRahman Lavaee                               nullptr, 0};
3458955950cSRahman Lavaee         CallSites.push_back(Site);
3468955950cSRahman Lavaee         SawPotentiallyThrowing = false;
3478955950cSRahman Lavaee       }
3488955950cSRahman Lavaee       CallSiteRanges.back().CallSiteEndIdx = CallSites.size();
3498955950cSRahman Lavaee     }
3508955950cSRahman Lavaee   }
3518076cab0SSaleem Abdulrasool }
3528076cab0SSaleem Abdulrasool 
3538076cab0SSaleem Abdulrasool /// Emit landing pads and actions.
3548076cab0SSaleem Abdulrasool ///
3558076cab0SSaleem Abdulrasool /// The general organization of the table is complex, but the basic concepts are
3568076cab0SSaleem Abdulrasool /// easy.  First there is a header which describes the location and organization
3578076cab0SSaleem Abdulrasool /// of the three components that follow.
3588076cab0SSaleem Abdulrasool ///
3598076cab0SSaleem Abdulrasool ///  1. The landing pad site information describes the range of code covered by
3608076cab0SSaleem Abdulrasool ///     the try.  In our case it's an accumulation of the ranges covered by the
3618076cab0SSaleem Abdulrasool ///     invokes in the try.  There is also a reference to the landing pad that
3628076cab0SSaleem Abdulrasool ///     handles the exception once processed.  Finally an index into the actions
3638076cab0SSaleem Abdulrasool ///     table.
3648076cab0SSaleem Abdulrasool ///  2. The action table, in our case, is composed of pairs of type IDs and next
3658076cab0SSaleem Abdulrasool ///     action offset.  Starting with the action index from the landing pad
3668076cab0SSaleem Abdulrasool ///     site, each type ID is checked for a match to the current exception.  If
3678076cab0SSaleem Abdulrasool ///     it matches then the exception and type id are passed on to the landing
3688076cab0SSaleem Abdulrasool ///     pad.  Otherwise the next action is looked up.  This chain is terminated
3698076cab0SSaleem Abdulrasool ///     with a next action of zero.  If no type id is found then the frame is
3708076cab0SSaleem Abdulrasool ///     unwound and handling continues.
3718076cab0SSaleem Abdulrasool ///  3. Type ID table contains references to all the C++ typeinfo for all
3728076cab0SSaleem Abdulrasool ///     catches in the function.  This tables is reverse indexed base 1.
37324faf859SHeejin Ahn ///
37424faf859SHeejin Ahn /// Returns the starting symbol of an exception table.
emitExceptionTable()37524faf859SHeejin Ahn MCSymbol *EHStreamer::emitExceptionTable() {
376d0ee66c2SMatthias Braun   const MachineFunction *MF = Asm->MF;
377d0ee66c2SMatthias Braun   const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
378d0ee66c2SMatthias Braun   const std::vector<unsigned> &FilterIds = MF->getFilterIds();
379d0ee66c2SMatthias Braun   const std::vector<LandingPadInfo> &PadInfos = MF->getLandingPads();
3808076cab0SSaleem Abdulrasool 
3818076cab0SSaleem Abdulrasool   // Sort the landing pads in order of their type ids.  This is used to fold
3828076cab0SSaleem Abdulrasool   // duplicate actions.
3838076cab0SSaleem Abdulrasool   SmallVector<const LandingPadInfo *, 64> LandingPads;
3848076cab0SSaleem Abdulrasool   LandingPads.reserve(PadInfos.size());
3858076cab0SSaleem Abdulrasool 
386fd7d4064SKazu Hirata   for (const LandingPadInfo &LPI : PadInfos)
387fd7d4064SKazu Hirata     LandingPads.push_back(&LPI);
3888076cab0SSaleem Abdulrasool 
3898076cab0SSaleem Abdulrasool   // Order landing pads lexicographically by type id.
3900cac726aSFangrui Song   llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) {
3910cac726aSFangrui Song     return L->TypeIds < R->TypeIds;
3920cac726aSFangrui Song   });
3938076cab0SSaleem Abdulrasool 
3948076cab0SSaleem Abdulrasool   // Compute the actions table and gather the first action index for each
3958076cab0SSaleem Abdulrasool   // landing pad site.
3968076cab0SSaleem Abdulrasool   SmallVector<ActionEntry, 32> Actions;
3978076cab0SSaleem Abdulrasool   SmallVector<unsigned, 64> FirstActions;
3988076cab0SSaleem Abdulrasool   computeActionsTable(LandingPads, Actions, FirstActions);
3998076cab0SSaleem Abdulrasool 
4008955950cSRahman Lavaee   // Compute the call-site table and call-site ranges. Normally, there is only
4018955950cSRahman Lavaee   // one call-site-range which covers the whole funciton. With
4028955950cSRahman Lavaee   // -basic-block-sections, there is one call-site-range per basic block
4038955950cSRahman Lavaee   // section.
4048076cab0SSaleem Abdulrasool   SmallVector<CallSiteEntry, 64> CallSites;
4058955950cSRahman Lavaee   SmallVector<CallSiteRange, 4> CallSiteRanges;
4068955950cSRahman Lavaee   computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions);
4078076cab0SSaleem Abdulrasool 
4088076cab0SSaleem Abdulrasool   bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
40924faf859SHeejin Ahn   bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
4102c63e760Sjasonliu   bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();
411c052fa0bSRafael Espindola   unsigned CallSiteEncoding =
412ab009a60SAlex Bradbury       IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :
413ab009a60SAlex Bradbury                Asm->getObjFileLowering().getCallSiteEncoding();
414c052fa0bSRafael Espindola   bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty();
4158076cab0SSaleem Abdulrasool 
4168076cab0SSaleem Abdulrasool   // Type infos.
417e44a1009SFangrui Song   MCSection *LSDASection = Asm->getObjFileLowering().getSectionForLSDA(
418e44a1009SFangrui Song       MF->getFunction(), *Asm->CurrentFnSym, Asm->TM);
4198076cab0SSaleem Abdulrasool   unsigned TTypeEncoding;
4208076cab0SSaleem Abdulrasool 
4218076cab0SSaleem Abdulrasool   if (!HaveTTData) {
422c052fa0bSRafael Espindola     // If there is no TypeInfo, then we just explicitly say that we're omitting
423c052fa0bSRafael Espindola     // that bit.
4248076cab0SSaleem Abdulrasool     TTypeEncoding = dwarf::DW_EH_PE_omit;
4258076cab0SSaleem Abdulrasool   } else {
4268076cab0SSaleem Abdulrasool     // Okay, we have actual filters or typeinfos to emit.  As such, we need to
4278076cab0SSaleem Abdulrasool     // pick a type encoding for them.  We're about to emit a list of pointers to
4288076cab0SSaleem Abdulrasool     // typeinfo objects at the end of the LSDA.  However, unless we're in static
4298076cab0SSaleem Abdulrasool     // mode, this reference will require a relocation by the dynamic linker.
4308076cab0SSaleem Abdulrasool     //
4318076cab0SSaleem Abdulrasool     // Because of this, we have a couple of options:
4328076cab0SSaleem Abdulrasool     //
4338076cab0SSaleem Abdulrasool     //   1) If we are in -static mode, we can always use an absolute reference
4348076cab0SSaleem Abdulrasool     //      from the LSDA, because the static linker will resolve it.
4358076cab0SSaleem Abdulrasool     //
4368076cab0SSaleem Abdulrasool     //   2) Otherwise, if the LSDA section is writable, we can output the direct
4378076cab0SSaleem Abdulrasool     //      reference to the typeinfo and allow the dynamic linker to relocate
4388076cab0SSaleem Abdulrasool     //      it.  Since it is in a writable section, the dynamic linker won't
4398076cab0SSaleem Abdulrasool     //      have a problem.
4408076cab0SSaleem Abdulrasool     //
4418076cab0SSaleem Abdulrasool     //   3) Finally, if we're in PIC mode and the LDSA section isn't writable,
4428076cab0SSaleem Abdulrasool     //      we need to use some form of indirection.  For example, on Darwin,
4438076cab0SSaleem Abdulrasool     //      we can output a statically-relocatable reference to a dyld stub. The
4448076cab0SSaleem Abdulrasool     //      offset to the stub is constant, but the contents are in a section
4458076cab0SSaleem Abdulrasool     //      that is updated by the dynamic linker.  This is easy enough, but we
4468076cab0SSaleem Abdulrasool     //      need to tell the personality function of the unwinder to indirect
4478076cab0SSaleem Abdulrasool     //      through the dyld stub.
4488076cab0SSaleem Abdulrasool     //
4498076cab0SSaleem Abdulrasool     // FIXME: When (3) is actually implemented, we'll have to emit the stubs
4508076cab0SSaleem Abdulrasool     // somewhere.  This predicate should be moved to a shared location that is
4518076cab0SSaleem Abdulrasool     // in target-independent code.
4528076cab0SSaleem Abdulrasool     //
4538076cab0SSaleem Abdulrasool     TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding();
4548076cab0SSaleem Abdulrasool   }
4558076cab0SSaleem Abdulrasool 
4568076cab0SSaleem Abdulrasool   // Begin the exception table.
4578076cab0SSaleem Abdulrasool   // Sometimes we want not to emit the data into separate section (e.g. ARM
4588076cab0SSaleem Abdulrasool   // EHABI). In this case LSDASection will be NULL.
4598076cab0SSaleem Abdulrasool   if (LSDASection)
460*adf4142fSFangrui Song     Asm->OutStreamer->switchSection(LSDASection);
4611d49eb00SFangrui Song   Asm->emitAlignment(Align(4));
4628076cab0SSaleem Abdulrasool 
4638076cab0SSaleem Abdulrasool   // Emit the LSDA.
4648076cab0SSaleem Abdulrasool   MCSymbol *GCCETSym =
4656f482000SJim Grosbach     Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+
4668076cab0SSaleem Abdulrasool                                       Twine(Asm->getFunctionNumber()));
4676d2d589bSFangrui Song   Asm->OutStreamer->emitLabel(GCCETSym);
4688955950cSRahman Lavaee   MCSymbol *CstEndLabel = Asm->createTempSymbol(
4698955950cSRahman Lavaee       CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end");
4708076cab0SSaleem Abdulrasool 
471d09b4169SRafael Espindola   MCSymbol *TTBaseLabel = nullptr;
4728955950cSRahman Lavaee   if (HaveTTData)
4738955950cSRahman Lavaee     TTBaseLabel = Asm->createTempSymbol("ttbase");
4748955950cSRahman Lavaee 
4758955950cSRahman Lavaee   const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
4768955950cSRahman Lavaee 
4778955950cSRahman Lavaee   // Helper for emitting references (offsets) for type table and the end of the
4788955950cSRahman Lavaee   // call-site table (which marks the beginning of the action table).
4798955950cSRahman Lavaee   //  * For Itanium, these references will be emitted for every callsite range.
4808955950cSRahman Lavaee   //  * For SJLJ and Wasm, they will be emitted only once in the LSDA header.
4818955950cSRahman Lavaee   auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() {
4828955950cSRahman Lavaee     Asm->emitEncodingByte(TTypeEncoding, "@TType");
4838076cab0SSaleem Abdulrasool     if (HaveTTData) {
484d09b4169SRafael Espindola       // N.B.: There is a dependency loop between the size of the TTBase uleb128
485d09b4169SRafael Espindola       // here and the amount of padding before the aligned type table. The
4868955950cSRahman Lavaee       // assembler must sometimes pad this uleb128 or insert extra padding
4878955950cSRahman Lavaee       // before the type table. See PR35809 or GNU as bug 4029.
488d09b4169SRafael Espindola       MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref");
4890bc77a0fSFangrui Song       Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel);
4906d2d589bSFangrui Song       Asm->OutStreamer->emitLabel(TTBaseRefLabel);
4918076cab0SSaleem Abdulrasool     }
4928076cab0SSaleem Abdulrasool 
4938955950cSRahman Lavaee     // The Action table follows the call-site table. So we emit the
4948955950cSRahman Lavaee     // label difference from here (start of the call-site table for SJLJ and
4958955950cSRahman Lavaee     // Wasm, and start of a call-site range for Itanium) to the end of the
4968955950cSRahman Lavaee     // whole call-site table (end of the last call-site range for Itanium).
497d09b4169SRafael Espindola     MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin");
4981d49eb00SFangrui Song     Asm->emitEncodingByte(CallSiteEncoding, "Call site");
4990bc77a0fSFangrui Song     Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel);
5006d2d589bSFangrui Song     Asm->OutStreamer->emitLabel(CstBeginLabel);
5018955950cSRahman Lavaee   };
502d09b4169SRafael Espindola 
5032c63e760Sjasonliu   // An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.
5042c63e760Sjasonliu   // For some platforms, the system assembler does not accept the form of
5052c63e760Sjasonliu   // `.uleb128 label2 - label1`. In those situations, we would need to calculate
5062c63e760Sjasonliu   // the size between label1 and label2 manually.
5072c63e760Sjasonliu   // In this case, we would need to calculate the LSDA size and the call
5082c63e760Sjasonliu   // site table size.
5092c63e760Sjasonliu   auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {
5102c63e760Sjasonliu     assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&
5112c63e760Sjasonliu            "Targets supporting .uleb128 do not need to take this path.");
5122c63e760Sjasonliu     if (CallSiteRanges.size() > 1)
5132c63e760Sjasonliu       report_fatal_error(
5142c63e760Sjasonliu           "-fbasic-block-sections is not yet supported on "
5152c63e760Sjasonliu           "platforms that do not have general LEB128 directive support.");
5162c63e760Sjasonliu 
5172c63e760Sjasonliu     uint64_t CallSiteTableSize = 0;
5182c63e760Sjasonliu     const CallSiteRange &CSRange = CallSiteRanges.back();
5192c63e760Sjasonliu     for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
5202c63e760Sjasonliu          CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {
5212c63e760Sjasonliu       const CallSiteEntry &S = CallSites[CallSiteIdx];
5222c63e760Sjasonliu       // Each call site entry consists of 3 udata4 fields (12 bytes) and
5232c63e760Sjasonliu       // 1 ULEB128 field.
5242c63e760Sjasonliu       CallSiteTableSize += 12 + getULEB128Size(S.Action);
5252c63e760Sjasonliu       assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");
5262c63e760Sjasonliu     }
5272c63e760Sjasonliu 
5282c63e760Sjasonliu     Asm->emitEncodingByte(TTypeEncoding, "@TType");
5292c63e760Sjasonliu     if (HaveTTData) {
5302c63e760Sjasonliu       const unsigned ByteSizeOfCallSiteOffset =
5312c63e760Sjasonliu           getULEB128Size(CallSiteTableSize);
5322c63e760Sjasonliu       uint64_t ActionTableSize = 0;
5332c63e760Sjasonliu       for (const ActionEntry &Action : Actions) {
5342c63e760Sjasonliu         // Each action entry consists of two SLEB128 fields.
5352c63e760Sjasonliu         ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +
5362c63e760Sjasonliu                            getSLEB128Size(Action.NextAction);
5372c63e760Sjasonliu         assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");
5382c63e760Sjasonliu       }
5392c63e760Sjasonliu 
5402c63e760Sjasonliu       const unsigned TypeInfoSize =
5412c63e760Sjasonliu           Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();
5422c63e760Sjasonliu 
5432c63e760Sjasonliu       const uint64_t LSDASizeBeforeAlign =
5442c63e760Sjasonliu           1                          // Call site encoding byte.
5452c63e760Sjasonliu           + ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.
5462c63e760Sjasonliu           + CallSiteTableSize        // Call site table content.
5472c63e760Sjasonliu           + ActionTableSize;         // Action table content.
5482c63e760Sjasonliu 
5492c63e760Sjasonliu       const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;
5502c63e760Sjasonliu       const unsigned ByteSizeOfLSDAWithoutAlign =
5512c63e760Sjasonliu           getULEB128Size(LSDASizeWithoutAlign);
5522c63e760Sjasonliu       const uint64_t DisplacementBeforeAlign =
5532c63e760Sjasonliu           2 // LPStartEncoding and TypeTableEncoding.
5542c63e760Sjasonliu           + ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;
5552c63e760Sjasonliu 
5562c63e760Sjasonliu       // The type info area starts with 4 byte alignment.
5572c63e760Sjasonliu       const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;
5582c63e760Sjasonliu       uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;
5592c63e760Sjasonliu       const unsigned ByteSizeOfLSDAWithAlign =
5602c63e760Sjasonliu           getULEB128Size(LSDASizeWithAlign);
5612c63e760Sjasonliu 
5622c63e760Sjasonliu       // The LSDASizeWithAlign could use 1 byte less padding for alignment
5632c63e760Sjasonliu       // when the data we use to represent the LSDA Size "needs" to be 1 byte
5642c63e760Sjasonliu       // larger than the one previously calculated without alignment.
5652c63e760Sjasonliu       if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)
5662c63e760Sjasonliu         LSDASizeWithAlign -= 1;
5672c63e760Sjasonliu 
5682c63e760Sjasonliu       Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,
5692c63e760Sjasonliu                                             ByteSizeOfLSDAWithAlign);
5702c63e760Sjasonliu     }
5712c63e760Sjasonliu 
5722c63e760Sjasonliu     Asm->emitEncodingByte(CallSiteEncoding, "Call site");
5732c63e760Sjasonliu     Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);
5742c63e760Sjasonliu   };
5752c63e760Sjasonliu 
57624faf859SHeejin Ahn   // SjLj / Wasm Exception handling
57724faf859SHeejin Ahn   if (IsSJLJ || IsWasm) {
5788955950cSRahman Lavaee     Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));
5798955950cSRahman Lavaee 
5808955950cSRahman Lavaee     // emit the LSDA header.
5818955950cSRahman Lavaee     Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
5828955950cSRahman Lavaee     EmitTypeTableRefAndCallSiteTableEndRef();
5838955950cSRahman Lavaee 
5848076cab0SSaleem Abdulrasool     unsigned idx = 0;
5858076cab0SSaleem Abdulrasool     for (SmallVectorImpl<CallSiteEntry>::const_iterator
5868076cab0SSaleem Abdulrasool          I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
5878076cab0SSaleem Abdulrasool       const CallSiteEntry &S = *I;
5888076cab0SSaleem Abdulrasool 
589d09b4169SRafael Espindola       // Index of the call site entry.
5908076cab0SSaleem Abdulrasool       if (VerboseAsm) {
5919ff69c8fSLang Hames         Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<");
5929ff69c8fSLang Hames         Asm->OutStreamer->AddComment("  On exception at call site "+Twine(idx));
5938076cab0SSaleem Abdulrasool       }
5940bc77a0fSFangrui Song       Asm->emitULEB128(idx);
5958076cab0SSaleem Abdulrasool 
5968076cab0SSaleem Abdulrasool       // Offset of the first associated action record, relative to the start of
5978076cab0SSaleem Abdulrasool       // the action table. This value is biased by 1 (1 indicates the start of
5988076cab0SSaleem Abdulrasool       // the action table), and 0 indicates that there are no actions.
5998076cab0SSaleem Abdulrasool       if (VerboseAsm) {
6008076cab0SSaleem Abdulrasool         if (S.Action == 0)
6019ff69c8fSLang Hames           Asm->OutStreamer->AddComment("  Action: cleanup");
6028076cab0SSaleem Abdulrasool         else
6039ff69c8fSLang Hames           Asm->OutStreamer->AddComment("  Action: " +
6048076cab0SSaleem Abdulrasool                                        Twine((S.Action - 1) / 2 + 1));
6058076cab0SSaleem Abdulrasool       }
6060bc77a0fSFangrui Song       Asm->emitULEB128(S.Action);
6078076cab0SSaleem Abdulrasool     }
6088955950cSRahman Lavaee     Asm->OutStreamer->emitLabel(CstEndLabel);
6098076cab0SSaleem Abdulrasool   } else {
61093acac6cSReid Kleckner     // Itanium LSDA exception handling
6118076cab0SSaleem Abdulrasool 
6128076cab0SSaleem Abdulrasool     // The call-site table is a list of all call sites that may throw an
6138076cab0SSaleem Abdulrasool     // exception (including C++ 'throw' statements) in the procedure
6148076cab0SSaleem Abdulrasool     // fragment. It immediately follows the LSDA header. Each entry indicates,
6158076cab0SSaleem Abdulrasool     // for a given call, the first corresponding action record and corresponding
6168076cab0SSaleem Abdulrasool     // landing pad.
6178076cab0SSaleem Abdulrasool     //
6188076cab0SSaleem Abdulrasool     // The table begins with the number of bytes, stored as an LEB128
6198076cab0SSaleem Abdulrasool     // compressed, unsigned integer. The records immediately follow the record
6208076cab0SSaleem Abdulrasool     // count. They are sorted in increasing call-site address. Each record
6218076cab0SSaleem Abdulrasool     // indicates:
6228076cab0SSaleem Abdulrasool     //
6238076cab0SSaleem Abdulrasool     //   * The position of the call-site.
6248076cab0SSaleem Abdulrasool     //   * The position of the landing pad.
6258076cab0SSaleem Abdulrasool     //   * The first action record for that call site.
6268076cab0SSaleem Abdulrasool     //
6278076cab0SSaleem Abdulrasool     // A missing entry in the call-site table indicates that a call is not
6288076cab0SSaleem Abdulrasool     // supposed to throw.
6298076cab0SSaleem Abdulrasool 
6308955950cSRahman Lavaee     assert(CallSiteRanges.size() != 0 && "No call-site ranges!");
6318076cab0SSaleem Abdulrasool 
6328955950cSRahman Lavaee     // There should be only one call-site range which includes all the landing
6338955950cSRahman Lavaee     // pads. Find that call-site range here.
6348955950cSRahman Lavaee     const CallSiteRange *LandingPadRange = nullptr;
6358955950cSRahman Lavaee     for (const CallSiteRange &CSRange : CallSiteRanges) {
6368955950cSRahman Lavaee       if (CSRange.IsLPRange) {
6378955950cSRahman Lavaee         assert(LandingPadRange == nullptr &&
6388955950cSRahman Lavaee                "All landing pads must be in a single callsite range.");
6398955950cSRahman Lavaee         LandingPadRange = &CSRange;
6408955950cSRahman Lavaee       }
6418955950cSRahman Lavaee     }
6428955950cSRahman Lavaee 
6438955950cSRahman Lavaee     // The call-site table is split into its call-site ranges, each being
6448955950cSRahman Lavaee     // emitted as:
6458955950cSRahman Lavaee     //              [ LPStartEncoding | LPStart ]
6468955950cSRahman Lavaee     //              [ TypeTableEncoding | TypeTableOffset ]
6478955950cSRahman Lavaee     //              [ CallSiteEncoding | CallSiteTableEndOffset ]
6488955950cSRahman Lavaee     // cst_begin -> { call-site entries contained in this range }
6498955950cSRahman Lavaee     //
6508955950cSRahman Lavaee     // and is followed by the next call-site range.
6518955950cSRahman Lavaee     //
6528955950cSRahman Lavaee     // For each call-site range, CallSiteTableEndOffset is computed as the
6538955950cSRahman Lavaee     // difference between cst_begin of that range and the last call-site-table's
6548955950cSRahman Lavaee     // end label. This offset is used to find the action table.
6558955950cSRahman Lavaee 
6568955950cSRahman Lavaee     unsigned Entry = 0;
6578955950cSRahman Lavaee     for (const CallSiteRange &CSRange : CallSiteRanges) {
6588955950cSRahman Lavaee       if (CSRange.CallSiteBeginIdx != 0) {
6598955950cSRahman Lavaee         // Align the call-site range for all ranges except the first. The
6608955950cSRahman Lavaee         // first range is already aligned due to the exception table alignment.
6618955950cSRahman Lavaee         Asm->emitAlignment(Align(4));
6628955950cSRahman Lavaee       }
6638955950cSRahman Lavaee       Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel);
6648955950cSRahman Lavaee 
6658955950cSRahman Lavaee       // Emit the LSDA header.
6668955950cSRahman Lavaee       // If only one call-site range exists, LPStart is omitted as it is the
6678955950cSRahman Lavaee       // same as the function entry.
6688955950cSRahman Lavaee       if (CallSiteRanges.size() == 1) {
6698955950cSRahman Lavaee         Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
6708955950cSRahman Lavaee       } else if (!Asm->isPositionIndependent()) {
6718955950cSRahman Lavaee         // For more than one call-site ranges, LPStart must be explicitly
6728955950cSRahman Lavaee         // specified.
6738955950cSRahman Lavaee         // For non-PIC we can simply use the absolute value.
6748955950cSRahman Lavaee         Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart");
6758955950cSRahman Lavaee         Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel,
6768955950cSRahman Lavaee                                           Asm->MAI->getCodePointerSize());
6778955950cSRahman Lavaee       } else {
6788955950cSRahman Lavaee         // For PIC mode, we Emit a PC-relative address for LPStart.
6798955950cSRahman Lavaee         Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart");
6808955950cSRahman Lavaee         MCContext &Context = Asm->OutStreamer->getContext();
6818955950cSRahman Lavaee         MCSymbol *Dot = Context.createTempSymbol();
6828955950cSRahman Lavaee         Asm->OutStreamer->emitLabel(Dot);
6838955950cSRahman Lavaee         Asm->OutStreamer->emitValue(
6848955950cSRahman Lavaee             MCBinaryExpr::createSub(
6858955950cSRahman Lavaee                 MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel,
6868955950cSRahman Lavaee                                         Context),
6878955950cSRahman Lavaee                 MCSymbolRefExpr::create(Dot, Context), Context),
6888955950cSRahman Lavaee             Asm->MAI->getCodePointerSize());
6898955950cSRahman Lavaee       }
6908955950cSRahman Lavaee 
6912c63e760Sjasonliu       if (HasLEB128Directives)
6928955950cSRahman Lavaee         EmitTypeTableRefAndCallSiteTableEndRef();
6932c63e760Sjasonliu       else
6942c63e760Sjasonliu         EmitTypeTableOffsetAndCallSiteTableOffset();
6958955950cSRahman Lavaee 
6968955950cSRahman Lavaee       for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
6978955950cSRahman Lavaee            CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {
6988955950cSRahman Lavaee         const CallSiteEntry &S = CallSites[CallSiteIdx];
6998955950cSRahman Lavaee 
7008955950cSRahman Lavaee         MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel;
7018955950cSRahman Lavaee         MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel;
7028955950cSRahman Lavaee 
7038955950cSRahman Lavaee         MCSymbol *BeginLabel = S.BeginLabel;
7048955950cSRahman Lavaee         if (!BeginLabel)
7058955950cSRahman Lavaee           BeginLabel = EHFuncBeginSym;
7068955950cSRahman Lavaee         MCSymbol *EndLabel = S.EndLabel;
7078955950cSRahman Lavaee         if (!EndLabel)
7088955950cSRahman Lavaee           EndLabel = EHFuncEndSym;
7098076cab0SSaleem Abdulrasool 
710d09b4169SRafael Espindola         // Offset of the call site relative to the start of the procedure.
7118076cab0SSaleem Abdulrasool         if (VerboseAsm)
7128955950cSRahman Lavaee           Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) +
7138955950cSRahman Lavaee                                        " <<");
7148955950cSRahman Lavaee         Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding);
7158076cab0SSaleem Abdulrasool         if (VerboseAsm)
7169ff69c8fSLang Hames           Asm->OutStreamer->AddComment(Twine("  Call between ") +
7178955950cSRahman Lavaee                                        BeginLabel->getName() + " and " +
7188955950cSRahman Lavaee                                        EndLabel->getName());
7198955950cSRahman Lavaee         Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding);
7208076cab0SSaleem Abdulrasool 
7218955950cSRahman Lavaee         // Offset of the landing pad relative to the start of the landing pad
7228955950cSRahman Lavaee         // fragment.
7230a57f655SReid Kleckner         if (!S.LPad) {
7248076cab0SSaleem Abdulrasool           if (VerboseAsm)
7259ff69c8fSLang Hames             Asm->OutStreamer->AddComment("    has no landing pad");
7260bc77a0fSFangrui Song           Asm->emitCallSiteValue(0, CallSiteEncoding);
7278076cab0SSaleem Abdulrasool         } else {
7288076cab0SSaleem Abdulrasool           if (VerboseAsm)
7299ff69c8fSLang Hames             Asm->OutStreamer->AddComment(Twine("    jumps to ") +
7300a57f655SReid Kleckner                                          S.LPad->LandingPadLabel->getName());
7318955950cSRahman Lavaee           Asm->emitCallSiteOffset(S.LPad->LandingPadLabel,
7328955950cSRahman Lavaee                                   LandingPadRange->FragmentBeginLabel,
733ab009a60SAlex Bradbury                                   CallSiteEncoding);
7348076cab0SSaleem Abdulrasool         }
7358076cab0SSaleem Abdulrasool 
7368955950cSRahman Lavaee         // Offset of the first associated action record, relative to the start
7378955950cSRahman Lavaee         // of the action table. This value is biased by 1 (1 indicates the start
7388955950cSRahman Lavaee         // of the action table), and 0 indicates that there are no actions.
7398076cab0SSaleem Abdulrasool         if (VerboseAsm) {
7408076cab0SSaleem Abdulrasool           if (S.Action == 0)
7419ff69c8fSLang Hames             Asm->OutStreamer->AddComment("  On action: cleanup");
7428076cab0SSaleem Abdulrasool           else
7439ff69c8fSLang Hames             Asm->OutStreamer->AddComment("  On action: " +
7448076cab0SSaleem Abdulrasool                                          Twine((S.Action - 1) / 2 + 1));
7458076cab0SSaleem Abdulrasool         }
7460bc77a0fSFangrui Song         Asm->emitULEB128(S.Action);
7478076cab0SSaleem Abdulrasool       }
7488076cab0SSaleem Abdulrasool     }
7496d2d589bSFangrui Song     Asm->OutStreamer->emitLabel(CstEndLabel);
7508955950cSRahman Lavaee   }
7518076cab0SSaleem Abdulrasool 
7528076cab0SSaleem Abdulrasool   // Emit the Action Table.
7538076cab0SSaleem Abdulrasool   int Entry = 0;
754c5e90a88SKazu Hirata   for (const ActionEntry &Action : Actions) {
7558076cab0SSaleem Abdulrasool     if (VerboseAsm) {
7568076cab0SSaleem Abdulrasool       // Emit comments that decode the action table.
7579ff69c8fSLang Hames       Asm->OutStreamer->AddComment(">> Action Record " + Twine(++Entry) + " <<");
7588076cab0SSaleem Abdulrasool     }
7598076cab0SSaleem Abdulrasool 
7608076cab0SSaleem Abdulrasool     // Type Filter
7618076cab0SSaleem Abdulrasool     //
7628076cab0SSaleem Abdulrasool     //   Used by the runtime to match the type of the thrown exception to the
7638076cab0SSaleem Abdulrasool     //   type of the catch clauses or the types in the exception specification.
7648076cab0SSaleem Abdulrasool     if (VerboseAsm) {
7658076cab0SSaleem Abdulrasool       if (Action.ValueForTypeID > 0)
7669ff69c8fSLang Hames         Asm->OutStreamer->AddComment("  Catch TypeInfo " +
7678076cab0SSaleem Abdulrasool                                      Twine(Action.ValueForTypeID));
7688076cab0SSaleem Abdulrasool       else if (Action.ValueForTypeID < 0)
7699ff69c8fSLang Hames         Asm->OutStreamer->AddComment("  Filter TypeInfo " +
7708076cab0SSaleem Abdulrasool                                      Twine(Action.ValueForTypeID));
7718076cab0SSaleem Abdulrasool       else
7729ff69c8fSLang Hames         Asm->OutStreamer->AddComment("  Cleanup");
7738076cab0SSaleem Abdulrasool     }
7740bc77a0fSFangrui Song     Asm->emitSLEB128(Action.ValueForTypeID);
7758076cab0SSaleem Abdulrasool 
7768076cab0SSaleem Abdulrasool     // Action Record
7778076cab0SSaleem Abdulrasool     if (VerboseAsm) {
778dbc616e9SFangrui Song       if (Action.Previous == unsigned(-1)) {
7799ff69c8fSLang Hames         Asm->OutStreamer->AddComment("  No further actions");
7808076cab0SSaleem Abdulrasool       } else {
781dbc616e9SFangrui Song         Asm->OutStreamer->AddComment("  Continue to action " +
782dbc616e9SFangrui Song                                      Twine(Action.Previous + 1));
7838076cab0SSaleem Abdulrasool       }
7848076cab0SSaleem Abdulrasool     }
7850bc77a0fSFangrui Song     Asm->emitSLEB128(Action.NextAction);
7868076cab0SSaleem Abdulrasool   }
7878076cab0SSaleem Abdulrasool 
788d09b4169SRafael Espindola   if (HaveTTData) {
7891d49eb00SFangrui Song     Asm->emitAlignment(Align(4));
790d09b4169SRafael Espindola     emitTypeInfos(TTypeEncoding, TTBaseLabel);
791d09b4169SRafael Espindola   }
7928076cab0SSaleem Abdulrasool 
7931d49eb00SFangrui Song   Asm->emitAlignment(Align(4));
79424faf859SHeejin Ahn   return GCCETSym;
7958076cab0SSaleem Abdulrasool }
7968076cab0SSaleem Abdulrasool 
emitTypeInfos(unsigned TTypeEncoding,MCSymbol * TTBaseLabel)797d09b4169SRafael Espindola void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) {
798d0ee66c2SMatthias Braun   const MachineFunction *MF = Asm->MF;
799d0ee66c2SMatthias Braun   const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
800d0ee66c2SMatthias Braun   const std::vector<unsigned> &FilterIds = MF->getFilterIds();
8018076cab0SSaleem Abdulrasool 
8028955950cSRahman Lavaee   const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
8038076cab0SSaleem Abdulrasool 
8048076cab0SSaleem Abdulrasool   int Entry = 0;
8058076cab0SSaleem Abdulrasool   // Emit the Catch TypeInfos.
8068076cab0SSaleem Abdulrasool   if (VerboseAsm && !TypeInfos.empty()) {
8079ff69c8fSLang Hames     Asm->OutStreamer->AddComment(">> Catch TypeInfos <<");
80815d82c62SFangrui Song     Asm->OutStreamer->addBlankLine();
8098076cab0SSaleem Abdulrasool     Entry = TypeInfos.size();
8108076cab0SSaleem Abdulrasool   }
8118076cab0SSaleem Abdulrasool 
812843d1edaSKazu Hirata   for (const GlobalValue *GV : llvm::reverse(TypeInfos)) {
8138076cab0SSaleem Abdulrasool     if (VerboseAsm)
8149ff69c8fSLang Hames       Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--));
8151d49eb00SFangrui Song     Asm->emitTTypeReference(GV, TTypeEncoding);
8168076cab0SSaleem Abdulrasool   }
8178076cab0SSaleem Abdulrasool 
8186d2d589bSFangrui Song   Asm->OutStreamer->emitLabel(TTBaseLabel);
819d09b4169SRafael Espindola 
8208076cab0SSaleem Abdulrasool   // Emit the Exception Specifications.
8218076cab0SSaleem Abdulrasool   if (VerboseAsm && !FilterIds.empty()) {
8229ff69c8fSLang Hames     Asm->OutStreamer->AddComment(">> Filter TypeInfos <<");
82315d82c62SFangrui Song     Asm->OutStreamer->addBlankLine();
8248076cab0SSaleem Abdulrasool     Entry = 0;
8258076cab0SSaleem Abdulrasool   }
8268076cab0SSaleem Abdulrasool   for (std::vector<unsigned>::const_iterator
8278076cab0SSaleem Abdulrasool          I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
8288076cab0SSaleem Abdulrasool     unsigned TypeID = *I;
8298076cab0SSaleem Abdulrasool     if (VerboseAsm) {
8308076cab0SSaleem Abdulrasool       --Entry;
8310a57f655SReid Kleckner       if (isFilterEHSelector(TypeID))
8329ff69c8fSLang Hames         Asm->OutStreamer->AddComment("FilterInfo " + Twine(Entry));
8338076cab0SSaleem Abdulrasool     }
8348076cab0SSaleem Abdulrasool 
8350bc77a0fSFangrui Song     Asm->emitULEB128(TypeID);
8368076cab0SSaleem Abdulrasool   }
8378076cab0SSaleem Abdulrasool }
838