xref: /openbsd-src/gnu/llvm/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===- CodeGen/AsmPrinter/EHStreamer.cpp - Exception Directive Streamer ---===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains support for writing exception info into assembly files.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "EHStreamer.h"
1409467b48Spatrick #include "llvm/ADT/SmallVector.h"
1509467b48Spatrick #include "llvm/ADT/Twine.h"
1609467b48Spatrick #include "llvm/ADT/iterator_range.h"
1709467b48Spatrick #include "llvm/BinaryFormat/Dwarf.h"
1809467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
1909467b48Spatrick #include "llvm/CodeGen/MachineFunction.h"
2009467b48Spatrick #include "llvm/CodeGen/MachineInstr.h"
2109467b48Spatrick #include "llvm/CodeGen/MachineOperand.h"
2209467b48Spatrick #include "llvm/IR/Function.h"
2309467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
2409467b48Spatrick #include "llvm/MC/MCContext.h"
2509467b48Spatrick #include "llvm/MC/MCStreamer.h"
2609467b48Spatrick #include "llvm/MC/MCSymbol.h"
2709467b48Spatrick #include "llvm/MC/MCTargetOptions.h"
2809467b48Spatrick #include "llvm/Support/Casting.h"
2909467b48Spatrick #include "llvm/Support/LEB128.h"
3009467b48Spatrick #include "llvm/Target/TargetLoweringObjectFile.h"
3109467b48Spatrick #include <algorithm>
3209467b48Spatrick #include <cassert>
3309467b48Spatrick #include <cstdint>
3409467b48Spatrick #include <vector>
3509467b48Spatrick 
3609467b48Spatrick using namespace llvm;
3709467b48Spatrick 
EHStreamer(AsmPrinter * A)3809467b48Spatrick EHStreamer::EHStreamer(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}
3909467b48Spatrick 
4009467b48Spatrick EHStreamer::~EHStreamer() = default;
4109467b48Spatrick 
4209467b48Spatrick /// How many leading type ids two landing pads have in common.
sharedTypeIDs(const LandingPadInfo * L,const LandingPadInfo * R)4309467b48Spatrick unsigned EHStreamer::sharedTypeIDs(const LandingPadInfo *L,
4409467b48Spatrick                                    const LandingPadInfo *R) {
4509467b48Spatrick   const std::vector<int> &LIds = L->TypeIds, &RIds = R->TypeIds;
4673471bf0Spatrick   return std::mismatch(LIds.begin(), LIds.end(), RIds.begin(), RIds.end())
4773471bf0Spatrick              .first -
4873471bf0Spatrick          LIds.begin();
4909467b48Spatrick }
5009467b48Spatrick 
5109467b48Spatrick /// Compute the actions table and gather the first action index for each landing
5209467b48Spatrick /// pad site.
computeActionsTable(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,SmallVectorImpl<ActionEntry> & Actions,SmallVectorImpl<unsigned> & FirstActions)5309467b48Spatrick void EHStreamer::computeActionsTable(
5409467b48Spatrick     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
5509467b48Spatrick     SmallVectorImpl<ActionEntry> &Actions,
5609467b48Spatrick     SmallVectorImpl<unsigned> &FirstActions) {
5709467b48Spatrick   // The action table follows the call-site table in the LSDA. The individual
5809467b48Spatrick   // records are of two types:
5909467b48Spatrick   //
6009467b48Spatrick   //   * Catch clause
6109467b48Spatrick   //   * Exception specification
6209467b48Spatrick   //
6309467b48Spatrick   // The two record kinds have the same format, with only small differences.
6409467b48Spatrick   // They are distinguished by the "switch value" field: Catch clauses
6509467b48Spatrick   // (TypeInfos) have strictly positive switch values, and exception
6609467b48Spatrick   // specifications (FilterIds) have strictly negative switch values. Value 0
6709467b48Spatrick   // indicates a catch-all clause.
6809467b48Spatrick   //
6909467b48Spatrick   // Negative type IDs index into FilterIds. Positive type IDs index into
7009467b48Spatrick   // TypeInfos.  The value written for a positive type ID is just the type ID
7109467b48Spatrick   // itself.  For a negative type ID, however, the value written is the
7209467b48Spatrick   // (negative) byte offset of the corresponding FilterIds entry.  The byte
7309467b48Spatrick   // offset is usually equal to the type ID (because the FilterIds entries are
7409467b48Spatrick   // written using a variable width encoding, which outputs one byte per entry
7509467b48Spatrick   // as long as the value written is not too large) but can differ.  This kind
7609467b48Spatrick   // of complication does not occur for positive type IDs because type infos are
7709467b48Spatrick   // output using a fixed width encoding.  FilterOffsets[i] holds the byte
7809467b48Spatrick   // offset corresponding to FilterIds[i].
7909467b48Spatrick 
8009467b48Spatrick   const std::vector<unsigned> &FilterIds = Asm->MF->getFilterIds();
8109467b48Spatrick   SmallVector<int, 16> FilterOffsets;
8209467b48Spatrick   FilterOffsets.reserve(FilterIds.size());
8309467b48Spatrick   int Offset = -1;
8409467b48Spatrick 
8573471bf0Spatrick   for (unsigned FilterId : FilterIds) {
8609467b48Spatrick     FilterOffsets.push_back(Offset);
8773471bf0Spatrick     Offset -= getULEB128Size(FilterId);
8809467b48Spatrick   }
8909467b48Spatrick 
9009467b48Spatrick   FirstActions.reserve(LandingPads.size());
9109467b48Spatrick 
9209467b48Spatrick   int FirstAction = 0;
9309467b48Spatrick   unsigned SizeActions = 0; // Total size of all action entries for a function
9409467b48Spatrick   const LandingPadInfo *PrevLPI = nullptr;
9509467b48Spatrick 
9673471bf0Spatrick   for (const LandingPadInfo *LPI : LandingPads) {
9709467b48Spatrick     const std::vector<int> &TypeIds = LPI->TypeIds;
9809467b48Spatrick     unsigned NumShared = PrevLPI ? sharedTypeIDs(LPI, PrevLPI) : 0;
9909467b48Spatrick     unsigned SizeSiteActions = 0; // Total size of all entries for a landingpad
10009467b48Spatrick 
10109467b48Spatrick     if (NumShared < TypeIds.size()) {
10209467b48Spatrick       // Size of one action entry (typeid + next action)
10309467b48Spatrick       unsigned SizeActionEntry = 0;
10409467b48Spatrick       unsigned PrevAction = (unsigned)-1;
10509467b48Spatrick 
10609467b48Spatrick       if (NumShared) {
10709467b48Spatrick         unsigned SizePrevIds = PrevLPI->TypeIds.size();
10809467b48Spatrick         assert(Actions.size());
10909467b48Spatrick         PrevAction = Actions.size() - 1;
11009467b48Spatrick         SizeActionEntry = getSLEB128Size(Actions[PrevAction].NextAction) +
11109467b48Spatrick                           getSLEB128Size(Actions[PrevAction].ValueForTypeID);
11209467b48Spatrick 
11309467b48Spatrick         for (unsigned j = NumShared; j != SizePrevIds; ++j) {
11409467b48Spatrick           assert(PrevAction != (unsigned)-1 && "PrevAction is invalid!");
11509467b48Spatrick           SizeActionEntry -= getSLEB128Size(Actions[PrevAction].ValueForTypeID);
11609467b48Spatrick           SizeActionEntry += -Actions[PrevAction].NextAction;
11709467b48Spatrick           PrevAction = Actions[PrevAction].Previous;
11809467b48Spatrick         }
11909467b48Spatrick       }
12009467b48Spatrick 
12109467b48Spatrick       // Compute the actions.
12209467b48Spatrick       for (unsigned J = NumShared, M = TypeIds.size(); J != M; ++J) {
12309467b48Spatrick         int TypeID = TypeIds[J];
12409467b48Spatrick         assert(-1 - TypeID < (int)FilterOffsets.size() && "Unknown filter id!");
12509467b48Spatrick         int ValueForTypeID =
12609467b48Spatrick             isFilterEHSelector(TypeID) ? FilterOffsets[-1 - TypeID] : TypeID;
12709467b48Spatrick         unsigned SizeTypeID = getSLEB128Size(ValueForTypeID);
12809467b48Spatrick 
12909467b48Spatrick         int NextAction = SizeActionEntry ? -(SizeActionEntry + SizeTypeID) : 0;
13009467b48Spatrick         SizeActionEntry = SizeTypeID + getSLEB128Size(NextAction);
13109467b48Spatrick         SizeSiteActions += SizeActionEntry;
13209467b48Spatrick 
13309467b48Spatrick         ActionEntry Action = { ValueForTypeID, NextAction, PrevAction };
13409467b48Spatrick         Actions.push_back(Action);
13509467b48Spatrick         PrevAction = Actions.size() - 1;
13609467b48Spatrick       }
13709467b48Spatrick 
13809467b48Spatrick       // Record the first action of the landing pad site.
13909467b48Spatrick       FirstAction = SizeActions + SizeSiteActions - SizeActionEntry + 1;
14009467b48Spatrick     } // else identical - re-use previous FirstAction
14109467b48Spatrick 
14209467b48Spatrick     // Information used when creating the call-site table. The action record
14309467b48Spatrick     // field of the call site record is the offset of the first associated
14409467b48Spatrick     // action record, relative to the start of the actions table. This value is
14509467b48Spatrick     // biased by 1 (1 indicating the start of the actions table), and 0
14609467b48Spatrick     // indicates that there are no actions.
14709467b48Spatrick     FirstActions.push_back(FirstAction);
14809467b48Spatrick 
14909467b48Spatrick     // Compute this sites contribution to size.
15009467b48Spatrick     SizeActions += SizeSiteActions;
15109467b48Spatrick 
15209467b48Spatrick     PrevLPI = LPI;
15309467b48Spatrick   }
15409467b48Spatrick }
15509467b48Spatrick 
15609467b48Spatrick /// Return `true' if this is a call to a function marked `nounwind'. Return
15709467b48Spatrick /// `false' otherwise.
callToNoUnwindFunction(const MachineInstr * MI)15809467b48Spatrick bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
15909467b48Spatrick   assert(MI->isCall() && "This should be a call instruction!");
16009467b48Spatrick 
16109467b48Spatrick   bool MarkedNoUnwind = false;
16209467b48Spatrick   bool SawFunc = false;
16309467b48Spatrick 
164*d415bd75Srobert   for (const MachineOperand &MO : MI->operands()) {
16509467b48Spatrick     if (!MO.isGlobal()) continue;
16609467b48Spatrick 
16709467b48Spatrick     const Function *F = dyn_cast<Function>(MO.getGlobal());
16809467b48Spatrick     if (!F) continue;
16909467b48Spatrick 
17009467b48Spatrick     if (SawFunc) {
17109467b48Spatrick       // Be conservative. If we have more than one function operand for this
17209467b48Spatrick       // call, then we can't make the assumption that it's the callee and
17309467b48Spatrick       // not a parameter to the call.
17409467b48Spatrick       //
17509467b48Spatrick       // FIXME: Determine if there's a way to say that `F' is the callee or
17609467b48Spatrick       // parameter.
17709467b48Spatrick       MarkedNoUnwind = false;
17809467b48Spatrick       break;
17909467b48Spatrick     }
18009467b48Spatrick 
18109467b48Spatrick     MarkedNoUnwind = F->doesNotThrow();
18209467b48Spatrick     SawFunc = true;
18309467b48Spatrick   }
18409467b48Spatrick 
18509467b48Spatrick   return MarkedNoUnwind;
18609467b48Spatrick }
18709467b48Spatrick 
computePadMap(const SmallVectorImpl<const LandingPadInfo * > & LandingPads,RangeMapType & PadMap)18809467b48Spatrick void EHStreamer::computePadMap(
18909467b48Spatrick     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
19009467b48Spatrick     RangeMapType &PadMap) {
19109467b48Spatrick   // Invokes and nounwind calls have entries in PadMap (due to being bracketed
19209467b48Spatrick   // by try-range labels when lowered).  Ordinary calls do not, so appropriate
19309467b48Spatrick   // try-ranges for them need be deduced so we can put them in the LSDA.
19409467b48Spatrick   for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
19509467b48Spatrick     const LandingPadInfo *LandingPad = LandingPads[i];
19609467b48Spatrick     for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
19709467b48Spatrick       MCSymbol *BeginLabel = LandingPad->BeginLabels[j];
198*d415bd75Srobert       MCSymbol *EndLabel = LandingPad->BeginLabels[j];
199*d415bd75Srobert       // If we have deleted the code for a given invoke after registering it in
200*d415bd75Srobert       // the LandingPad label list, the associated symbols will not have been
201*d415bd75Srobert       // emitted. In that case, ignore this callsite entry.
202*d415bd75Srobert       if (!BeginLabel->isDefined() || !EndLabel->isDefined())
203*d415bd75Srobert         continue;
20409467b48Spatrick       assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
20509467b48Spatrick       PadRange P = { i, j };
20609467b48Spatrick       PadMap[BeginLabel] = P;
20709467b48Spatrick     }
20809467b48Spatrick   }
20909467b48Spatrick }
21009467b48Spatrick 
21109467b48Spatrick /// Compute the call-site table.  The entry for an invoke has a try-range
21209467b48Spatrick /// containing the call, a non-zero landing pad, and an appropriate action.  The
21309467b48Spatrick /// entry for an ordinary call has a try-range containing the call and zero for
21409467b48Spatrick /// the landing pad and the action.  Calls marked 'nounwind' have no entry and
21509467b48Spatrick /// must not be contained in the try-range of any entry - they form gaps in the
21609467b48Spatrick /// table.  Entries must be ordered by try-range address.
21773471bf0Spatrick ///
21873471bf0Spatrick /// Call-sites are split into one or more call-site ranges associated with
21973471bf0Spatrick /// different sections of the function.
22073471bf0Spatrick ///
22173471bf0Spatrick ///   - Without -basic-block-sections, all call-sites are grouped into one
22273471bf0Spatrick ///     call-site-range corresponding to the function section.
22373471bf0Spatrick ///
22473471bf0Spatrick ///   - With -basic-block-sections, one call-site range is created for each
22573471bf0Spatrick ///     section, with its FragmentBeginLabel and FragmentEndLabel respectively
22673471bf0Spatrick //      set to the beginning and ending of the corresponding section and its
22773471bf0Spatrick //      ExceptionLabel set to the exception symbol dedicated for this section.
22873471bf0Spatrick //      Later, one LSDA header will be emitted for each call-site range with its
22973471bf0Spatrick //      call-sites following. The action table and type info table will be
23073471bf0Spatrick //      shared across all ranges.
computeCallSiteTable(SmallVectorImpl<CallSiteEntry> & CallSites,SmallVectorImpl<CallSiteRange> & CallSiteRanges,const SmallVectorImpl<const LandingPadInfo * > & LandingPads,const SmallVectorImpl<unsigned> & FirstActions)23173471bf0Spatrick void EHStreamer::computeCallSiteTable(
23273471bf0Spatrick     SmallVectorImpl<CallSiteEntry> &CallSites,
23373471bf0Spatrick     SmallVectorImpl<CallSiteRange> &CallSiteRanges,
23409467b48Spatrick     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
23509467b48Spatrick     const SmallVectorImpl<unsigned> &FirstActions) {
23609467b48Spatrick   RangeMapType PadMap;
23709467b48Spatrick   computePadMap(LandingPads, PadMap);
23809467b48Spatrick 
23909467b48Spatrick   // The end label of the previous invoke or nounwind try-range.
24073471bf0Spatrick   MCSymbol *LastLabel = Asm->getFunctionBegin();
24109467b48Spatrick 
24209467b48Spatrick   // Whether there is a potentially throwing instruction (currently this means
24309467b48Spatrick   // an ordinary call) between the end of the previous try-range and now.
24409467b48Spatrick   bool SawPotentiallyThrowing = false;
24509467b48Spatrick 
24609467b48Spatrick   // Whether the last CallSite entry was for an invoke.
24709467b48Spatrick   bool PreviousIsInvoke = false;
24809467b48Spatrick 
24909467b48Spatrick   bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
25009467b48Spatrick 
25109467b48Spatrick   // Visit all instructions in order of address.
25209467b48Spatrick   for (const auto &MBB : *Asm->MF) {
25373471bf0Spatrick     if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) {
25473471bf0Spatrick       // We start a call-site range upon function entry and at the beginning of
25573471bf0Spatrick       // every basic block section.
25673471bf0Spatrick       CallSiteRanges.push_back(
25773471bf0Spatrick           {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel,
25873471bf0Spatrick            Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel,
25973471bf0Spatrick            Asm->getMBBExceptionSym(MBB), CallSites.size()});
26073471bf0Spatrick       PreviousIsInvoke = false;
26173471bf0Spatrick       SawPotentiallyThrowing = false;
26273471bf0Spatrick       LastLabel = nullptr;
26373471bf0Spatrick     }
26473471bf0Spatrick 
26573471bf0Spatrick     if (MBB.isEHPad())
26673471bf0Spatrick       CallSiteRanges.back().IsLPRange = true;
26773471bf0Spatrick 
26809467b48Spatrick     for (const auto &MI : MBB) {
26909467b48Spatrick       if (!MI.isEHLabel()) {
27009467b48Spatrick         if (MI.isCall())
27109467b48Spatrick           SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
27209467b48Spatrick         continue;
27309467b48Spatrick       }
27409467b48Spatrick 
27509467b48Spatrick       // End of the previous try-range?
27609467b48Spatrick       MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
27709467b48Spatrick       if (BeginLabel == LastLabel)
27809467b48Spatrick         SawPotentiallyThrowing = false;
27909467b48Spatrick 
28009467b48Spatrick       // Beginning of a new try-range?
28109467b48Spatrick       RangeMapType::const_iterator L = PadMap.find(BeginLabel);
28209467b48Spatrick       if (L == PadMap.end())
28309467b48Spatrick         // Nope, it was just some random label.
28409467b48Spatrick         continue;
28509467b48Spatrick 
28609467b48Spatrick       const PadRange &P = L->second;
28709467b48Spatrick       const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
28809467b48Spatrick       assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
28909467b48Spatrick              "Inconsistent landing pad map!");
29009467b48Spatrick 
29173471bf0Spatrick       // For Dwarf and AIX exception handling (SjLj handling doesn't use this).
29273471bf0Spatrick       // If some instruction between the previous try-range and this one may
29373471bf0Spatrick       // throw, create a call-site entry with no landing pad for the region
29473471bf0Spatrick       // between the try-ranges.
29573471bf0Spatrick       if (SawPotentiallyThrowing &&
29673471bf0Spatrick           (Asm->MAI->usesCFIForEH() ||
29773471bf0Spatrick            Asm->MAI->getExceptionHandlingType() == ExceptionHandling::AIX)) {
29873471bf0Spatrick         CallSites.push_back({LastLabel, BeginLabel, nullptr, 0});
29909467b48Spatrick         PreviousIsInvoke = false;
30009467b48Spatrick       }
30109467b48Spatrick 
30209467b48Spatrick       LastLabel = LandingPad->EndLabels[P.RangeIndex];
30309467b48Spatrick       assert(BeginLabel && LastLabel && "Invalid landing pad!");
30409467b48Spatrick 
30509467b48Spatrick       if (!LandingPad->LandingPadLabel) {
30609467b48Spatrick         // Create a gap.
30709467b48Spatrick         PreviousIsInvoke = false;
30809467b48Spatrick       } else {
30909467b48Spatrick         // This try-range is for an invoke.
31009467b48Spatrick         CallSiteEntry Site = {
31109467b48Spatrick           BeginLabel,
31209467b48Spatrick           LastLabel,
31309467b48Spatrick           LandingPad,
31409467b48Spatrick           FirstActions[P.PadIndex]
31509467b48Spatrick         };
31609467b48Spatrick 
31709467b48Spatrick         // Try to merge with the previous call-site. SJLJ doesn't do this
31809467b48Spatrick         if (PreviousIsInvoke && !IsSJLJ) {
31909467b48Spatrick           CallSiteEntry &Prev = CallSites.back();
32009467b48Spatrick           if (Site.LPad == Prev.LPad && Site.Action == Prev.Action) {
32109467b48Spatrick             // Extend the range of the previous entry.
32209467b48Spatrick             Prev.EndLabel = Site.EndLabel;
32309467b48Spatrick             continue;
32409467b48Spatrick           }
32509467b48Spatrick         }
32609467b48Spatrick 
32709467b48Spatrick         // Otherwise, create a new call-site.
32809467b48Spatrick         if (!IsSJLJ)
32909467b48Spatrick           CallSites.push_back(Site);
33009467b48Spatrick         else {
33109467b48Spatrick           // SjLj EH must maintain the call sites in the order assigned
33209467b48Spatrick           // to them by the SjLjPrepare pass.
33309467b48Spatrick           unsigned SiteNo = Asm->MF->getCallSiteBeginLabel(BeginLabel);
33409467b48Spatrick           if (CallSites.size() < SiteNo)
33509467b48Spatrick             CallSites.resize(SiteNo);
33609467b48Spatrick           CallSites[SiteNo - 1] = Site;
33709467b48Spatrick         }
33809467b48Spatrick         PreviousIsInvoke = true;
33909467b48Spatrick       }
34009467b48Spatrick     }
34109467b48Spatrick 
34273471bf0Spatrick     // We end the call-site range upon function exit and at the end of every
34373471bf0Spatrick     // basic block section.
34473471bf0Spatrick     if (&MBB == &Asm->MF->back() || MBB.isEndSection()) {
34509467b48Spatrick       // If some instruction between the previous try-range and the end of the
34673471bf0Spatrick       // function may throw, create a call-site entry with no landing pad for
34773471bf0Spatrick       // the region following the try-range.
34809467b48Spatrick       if (SawPotentiallyThrowing && !IsSJLJ) {
34973471bf0Spatrick         CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel,
35073471bf0Spatrick                               nullptr, 0};
35109467b48Spatrick         CallSites.push_back(Site);
35273471bf0Spatrick         SawPotentiallyThrowing = false;
35373471bf0Spatrick       }
35473471bf0Spatrick       CallSiteRanges.back().CallSiteEndIdx = CallSites.size();
35573471bf0Spatrick     }
35609467b48Spatrick   }
35709467b48Spatrick }
35809467b48Spatrick 
35909467b48Spatrick /// Emit landing pads and actions.
36009467b48Spatrick ///
36109467b48Spatrick /// The general organization of the table is complex, but the basic concepts are
36209467b48Spatrick /// easy.  First there is a header which describes the location and organization
36309467b48Spatrick /// of the three components that follow.
36409467b48Spatrick ///
36509467b48Spatrick ///  1. The landing pad site information describes the range of code covered by
36609467b48Spatrick ///     the try.  In our case it's an accumulation of the ranges covered by the
36709467b48Spatrick ///     invokes in the try.  There is also a reference to the landing pad that
36809467b48Spatrick ///     handles the exception once processed.  Finally an index into the actions
36909467b48Spatrick ///     table.
37009467b48Spatrick ///  2. The action table, in our case, is composed of pairs of type IDs and next
37109467b48Spatrick ///     action offset.  Starting with the action index from the landing pad
37209467b48Spatrick ///     site, each type ID is checked for a match to the current exception.  If
37309467b48Spatrick ///     it matches then the exception and type id are passed on to the landing
37409467b48Spatrick ///     pad.  Otherwise the next action is looked up.  This chain is terminated
37509467b48Spatrick ///     with a next action of zero.  If no type id is found then the frame is
37609467b48Spatrick ///     unwound and handling continues.
37709467b48Spatrick ///  3. Type ID table contains references to all the C++ typeinfo for all
37809467b48Spatrick ///     catches in the function.  This tables is reverse indexed base 1.
37909467b48Spatrick ///
38009467b48Spatrick /// Returns the starting symbol of an exception table.
emitExceptionTable()38109467b48Spatrick MCSymbol *EHStreamer::emitExceptionTable() {
38209467b48Spatrick   const MachineFunction *MF = Asm->MF;
38309467b48Spatrick   const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
38409467b48Spatrick   const std::vector<unsigned> &FilterIds = MF->getFilterIds();
38509467b48Spatrick   const std::vector<LandingPadInfo> &PadInfos = MF->getLandingPads();
38609467b48Spatrick 
38709467b48Spatrick   // Sort the landing pads in order of their type ids.  This is used to fold
38809467b48Spatrick   // duplicate actions.
38909467b48Spatrick   SmallVector<const LandingPadInfo *, 64> LandingPads;
39009467b48Spatrick   LandingPads.reserve(PadInfos.size());
39109467b48Spatrick 
392*d415bd75Srobert   for (const LandingPadInfo &LPI : PadInfos) {
393*d415bd75Srobert     // If a landing-pad has an associated label, but the label wasn't ever
394*d415bd75Srobert     // emitted, then skip it.  (This can occur if the landingpad's MBB was
395*d415bd75Srobert     // deleted).
396*d415bd75Srobert     if (LPI.LandingPadLabel && !LPI.LandingPadLabel->isDefined())
397*d415bd75Srobert       continue;
398*d415bd75Srobert     LandingPads.push_back(&LPI);
399*d415bd75Srobert   }
40009467b48Spatrick 
40109467b48Spatrick   // Order landing pads lexicographically by type id.
40209467b48Spatrick   llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) {
40309467b48Spatrick     return L->TypeIds < R->TypeIds;
40409467b48Spatrick   });
40509467b48Spatrick 
40609467b48Spatrick   // Compute the actions table and gather the first action index for each
40709467b48Spatrick   // landing pad site.
40809467b48Spatrick   SmallVector<ActionEntry, 32> Actions;
40909467b48Spatrick   SmallVector<unsigned, 64> FirstActions;
41009467b48Spatrick   computeActionsTable(LandingPads, Actions, FirstActions);
41109467b48Spatrick 
41273471bf0Spatrick   // Compute the call-site table and call-site ranges. Normally, there is only
41373471bf0Spatrick   // one call-site-range which covers the whole funciton. With
41473471bf0Spatrick   // -basic-block-sections, there is one call-site-range per basic block
41573471bf0Spatrick   // section.
41609467b48Spatrick   SmallVector<CallSiteEntry, 64> CallSites;
41773471bf0Spatrick   SmallVector<CallSiteRange, 4> CallSiteRanges;
41873471bf0Spatrick   computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions);
41909467b48Spatrick 
42009467b48Spatrick   bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
42109467b48Spatrick   bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
42273471bf0Spatrick   bool HasLEB128Directives = Asm->MAI->hasLEB128Directives();
42309467b48Spatrick   unsigned CallSiteEncoding =
42409467b48Spatrick       IsSJLJ ? static_cast<unsigned>(dwarf::DW_EH_PE_udata4) :
42509467b48Spatrick                Asm->getObjFileLowering().getCallSiteEncoding();
42609467b48Spatrick   bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty();
42709467b48Spatrick 
42809467b48Spatrick   // Type infos.
42973471bf0Spatrick   MCSection *LSDASection = Asm->getObjFileLowering().getSectionForLSDA(
43073471bf0Spatrick       MF->getFunction(), *Asm->CurrentFnSym, Asm->TM);
43109467b48Spatrick   unsigned TTypeEncoding;
43209467b48Spatrick 
43309467b48Spatrick   if (!HaveTTData) {
43409467b48Spatrick     // If there is no TypeInfo, then we just explicitly say that we're omitting
43509467b48Spatrick     // that bit.
43609467b48Spatrick     TTypeEncoding = dwarf::DW_EH_PE_omit;
43709467b48Spatrick   } else {
43809467b48Spatrick     // Okay, we have actual filters or typeinfos to emit.  As such, we need to
43909467b48Spatrick     // pick a type encoding for them.  We're about to emit a list of pointers to
44009467b48Spatrick     // typeinfo objects at the end of the LSDA.  However, unless we're in static
44109467b48Spatrick     // mode, this reference will require a relocation by the dynamic linker.
44209467b48Spatrick     //
44309467b48Spatrick     // Because of this, we have a couple of options:
44409467b48Spatrick     //
44509467b48Spatrick     //   1) If we are in -static mode, we can always use an absolute reference
44609467b48Spatrick     //      from the LSDA, because the static linker will resolve it.
44709467b48Spatrick     //
44809467b48Spatrick     //   2) Otherwise, if the LSDA section is writable, we can output the direct
44909467b48Spatrick     //      reference to the typeinfo and allow the dynamic linker to relocate
45009467b48Spatrick     //      it.  Since it is in a writable section, the dynamic linker won't
45109467b48Spatrick     //      have a problem.
45209467b48Spatrick     //
45309467b48Spatrick     //   3) Finally, if we're in PIC mode and the LDSA section isn't writable,
45409467b48Spatrick     //      we need to use some form of indirection.  For example, on Darwin,
45509467b48Spatrick     //      we can output a statically-relocatable reference to a dyld stub. The
45609467b48Spatrick     //      offset to the stub is constant, but the contents are in a section
45709467b48Spatrick     //      that is updated by the dynamic linker.  This is easy enough, but we
45809467b48Spatrick     //      need to tell the personality function of the unwinder to indirect
45909467b48Spatrick     //      through the dyld stub.
46009467b48Spatrick     //
46109467b48Spatrick     // FIXME: When (3) is actually implemented, we'll have to emit the stubs
46209467b48Spatrick     // somewhere.  This predicate should be moved to a shared location that is
46309467b48Spatrick     // in target-independent code.
46409467b48Spatrick     //
46509467b48Spatrick     TTypeEncoding = Asm->getObjFileLowering().getTTypeEncoding();
46609467b48Spatrick   }
46709467b48Spatrick 
46809467b48Spatrick   // Begin the exception table.
46909467b48Spatrick   // Sometimes we want not to emit the data into separate section (e.g. ARM
47009467b48Spatrick   // EHABI). In this case LSDASection will be NULL.
47109467b48Spatrick   if (LSDASection)
472*d415bd75Srobert     Asm->OutStreamer->switchSection(LSDASection);
473097a140dSpatrick   Asm->emitAlignment(Align(4));
47409467b48Spatrick 
47509467b48Spatrick   // Emit the LSDA.
47609467b48Spatrick   MCSymbol *GCCETSym =
47709467b48Spatrick     Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+
47809467b48Spatrick                                       Twine(Asm->getFunctionNumber()));
479097a140dSpatrick   Asm->OutStreamer->emitLabel(GCCETSym);
48073471bf0Spatrick   MCSymbol *CstEndLabel = Asm->createTempSymbol(
48173471bf0Spatrick       CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end");
48209467b48Spatrick 
48309467b48Spatrick   MCSymbol *TTBaseLabel = nullptr;
48473471bf0Spatrick   if (HaveTTData)
48573471bf0Spatrick     TTBaseLabel = Asm->createTempSymbol("ttbase");
48673471bf0Spatrick 
48773471bf0Spatrick   const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
48873471bf0Spatrick 
48973471bf0Spatrick   // Helper for emitting references (offsets) for type table and the end of the
49073471bf0Spatrick   // call-site table (which marks the beginning of the action table).
49173471bf0Spatrick   //  * For Itanium, these references will be emitted for every callsite range.
49273471bf0Spatrick   //  * For SJLJ and Wasm, they will be emitted only once in the LSDA header.
49373471bf0Spatrick   auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() {
49473471bf0Spatrick     Asm->emitEncodingByte(TTypeEncoding, "@TType");
49509467b48Spatrick     if (HaveTTData) {
49609467b48Spatrick       // N.B.: There is a dependency loop between the size of the TTBase uleb128
49709467b48Spatrick       // here and the amount of padding before the aligned type table. The
49873471bf0Spatrick       // assembler must sometimes pad this uleb128 or insert extra padding
49973471bf0Spatrick       // before the type table. See PR35809 or GNU as bug 4029.
50009467b48Spatrick       MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref");
501097a140dSpatrick       Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel);
502097a140dSpatrick       Asm->OutStreamer->emitLabel(TTBaseRefLabel);
50309467b48Spatrick     }
50409467b48Spatrick 
50573471bf0Spatrick     // The Action table follows the call-site table. So we emit the
50673471bf0Spatrick     // label difference from here (start of the call-site table for SJLJ and
50773471bf0Spatrick     // Wasm, and start of a call-site range for Itanium) to the end of the
50873471bf0Spatrick     // whole call-site table (end of the last call-site range for Itanium).
50909467b48Spatrick     MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin");
510097a140dSpatrick     Asm->emitEncodingByte(CallSiteEncoding, "Call site");
511097a140dSpatrick     Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel);
512097a140dSpatrick     Asm->OutStreamer->emitLabel(CstBeginLabel);
51373471bf0Spatrick   };
51473471bf0Spatrick 
51573471bf0Spatrick   // An alternative path to EmitTypeTableRefAndCallSiteTableEndRef.
51673471bf0Spatrick   // For some platforms, the system assembler does not accept the form of
51773471bf0Spatrick   // `.uleb128 label2 - label1`. In those situations, we would need to calculate
51873471bf0Spatrick   // the size between label1 and label2 manually.
51973471bf0Spatrick   // In this case, we would need to calculate the LSDA size and the call
52073471bf0Spatrick   // site table size.
52173471bf0Spatrick   auto EmitTypeTableOffsetAndCallSiteTableOffset = [&]() {
52273471bf0Spatrick     assert(CallSiteEncoding == dwarf::DW_EH_PE_udata4 && !HasLEB128Directives &&
52373471bf0Spatrick            "Targets supporting .uleb128 do not need to take this path.");
52473471bf0Spatrick     if (CallSiteRanges.size() > 1)
52573471bf0Spatrick       report_fatal_error(
52673471bf0Spatrick           "-fbasic-block-sections is not yet supported on "
52773471bf0Spatrick           "platforms that do not have general LEB128 directive support.");
52873471bf0Spatrick 
52973471bf0Spatrick     uint64_t CallSiteTableSize = 0;
53073471bf0Spatrick     const CallSiteRange &CSRange = CallSiteRanges.back();
53173471bf0Spatrick     for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
53273471bf0Spatrick          CallSiteIdx < CSRange.CallSiteEndIdx; ++CallSiteIdx) {
53373471bf0Spatrick       const CallSiteEntry &S = CallSites[CallSiteIdx];
53473471bf0Spatrick       // Each call site entry consists of 3 udata4 fields (12 bytes) and
53573471bf0Spatrick       // 1 ULEB128 field.
53673471bf0Spatrick       CallSiteTableSize += 12 + getULEB128Size(S.Action);
53773471bf0Spatrick       assert(isUInt<32>(CallSiteTableSize) && "CallSiteTableSize overflows.");
53873471bf0Spatrick     }
53973471bf0Spatrick 
54073471bf0Spatrick     Asm->emitEncodingByte(TTypeEncoding, "@TType");
54173471bf0Spatrick     if (HaveTTData) {
54273471bf0Spatrick       const unsigned ByteSizeOfCallSiteOffset =
54373471bf0Spatrick           getULEB128Size(CallSiteTableSize);
54473471bf0Spatrick       uint64_t ActionTableSize = 0;
54573471bf0Spatrick       for (const ActionEntry &Action : Actions) {
54673471bf0Spatrick         // Each action entry consists of two SLEB128 fields.
54773471bf0Spatrick         ActionTableSize += getSLEB128Size(Action.ValueForTypeID) +
54873471bf0Spatrick                            getSLEB128Size(Action.NextAction);
54973471bf0Spatrick         assert(isUInt<32>(ActionTableSize) && "ActionTableSize overflows.");
55073471bf0Spatrick       }
55173471bf0Spatrick 
55273471bf0Spatrick       const unsigned TypeInfoSize =
55373471bf0Spatrick           Asm->GetSizeOfEncodedValue(TTypeEncoding) * MF->getTypeInfos().size();
55473471bf0Spatrick 
55573471bf0Spatrick       const uint64_t LSDASizeBeforeAlign =
55673471bf0Spatrick           1                          // Call site encoding byte.
55773471bf0Spatrick           + ByteSizeOfCallSiteOffset // ULEB128 encoding of CallSiteTableSize.
55873471bf0Spatrick           + CallSiteTableSize        // Call site table content.
55973471bf0Spatrick           + ActionTableSize;         // Action table content.
56073471bf0Spatrick 
56173471bf0Spatrick       const uint64_t LSDASizeWithoutAlign = LSDASizeBeforeAlign + TypeInfoSize;
56273471bf0Spatrick       const unsigned ByteSizeOfLSDAWithoutAlign =
56373471bf0Spatrick           getULEB128Size(LSDASizeWithoutAlign);
56473471bf0Spatrick       const uint64_t DisplacementBeforeAlign =
56573471bf0Spatrick           2 // LPStartEncoding and TypeTableEncoding.
56673471bf0Spatrick           + ByteSizeOfLSDAWithoutAlign + LSDASizeBeforeAlign;
56773471bf0Spatrick 
56873471bf0Spatrick       // The type info area starts with 4 byte alignment.
56973471bf0Spatrick       const unsigned NeedAlignVal = (4 - DisplacementBeforeAlign % 4) % 4;
57073471bf0Spatrick       uint64_t LSDASizeWithAlign = LSDASizeWithoutAlign + NeedAlignVal;
57173471bf0Spatrick       const unsigned ByteSizeOfLSDAWithAlign =
57273471bf0Spatrick           getULEB128Size(LSDASizeWithAlign);
57373471bf0Spatrick 
57473471bf0Spatrick       // The LSDASizeWithAlign could use 1 byte less padding for alignment
57573471bf0Spatrick       // when the data we use to represent the LSDA Size "needs" to be 1 byte
57673471bf0Spatrick       // larger than the one previously calculated without alignment.
57773471bf0Spatrick       if (ByteSizeOfLSDAWithAlign > ByteSizeOfLSDAWithoutAlign)
57873471bf0Spatrick         LSDASizeWithAlign -= 1;
57973471bf0Spatrick 
58073471bf0Spatrick       Asm->OutStreamer->emitULEB128IntValue(LSDASizeWithAlign,
58173471bf0Spatrick                                             ByteSizeOfLSDAWithAlign);
58273471bf0Spatrick     }
58373471bf0Spatrick 
58473471bf0Spatrick     Asm->emitEncodingByte(CallSiteEncoding, "Call site");
58573471bf0Spatrick     Asm->OutStreamer->emitULEB128IntValue(CallSiteTableSize);
58673471bf0Spatrick   };
58709467b48Spatrick 
58809467b48Spatrick   // SjLj / Wasm Exception handling
58909467b48Spatrick   if (IsSJLJ || IsWasm) {
59073471bf0Spatrick     Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front()));
59173471bf0Spatrick 
59273471bf0Spatrick     // emit the LSDA header.
59373471bf0Spatrick     Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
59473471bf0Spatrick     EmitTypeTableRefAndCallSiteTableEndRef();
59573471bf0Spatrick 
59609467b48Spatrick     unsigned idx = 0;
59709467b48Spatrick     for (SmallVectorImpl<CallSiteEntry>::const_iterator
59809467b48Spatrick          I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
59909467b48Spatrick       const CallSiteEntry &S = *I;
60009467b48Spatrick 
60109467b48Spatrick       // Index of the call site entry.
60209467b48Spatrick       if (VerboseAsm) {
60309467b48Spatrick         Asm->OutStreamer->AddComment(">> Call Site " + Twine(idx) + " <<");
60409467b48Spatrick         Asm->OutStreamer->AddComment("  On exception at call site "+Twine(idx));
60509467b48Spatrick       }
606097a140dSpatrick       Asm->emitULEB128(idx);
60709467b48Spatrick 
60809467b48Spatrick       // Offset of the first associated action record, relative to the start of
60909467b48Spatrick       // the action table. This value is biased by 1 (1 indicates the start of
61009467b48Spatrick       // the action table), and 0 indicates that there are no actions.
61109467b48Spatrick       if (VerboseAsm) {
61209467b48Spatrick         if (S.Action == 0)
61309467b48Spatrick           Asm->OutStreamer->AddComment("  Action: cleanup");
61409467b48Spatrick         else
61509467b48Spatrick           Asm->OutStreamer->AddComment("  Action: " +
61609467b48Spatrick                                        Twine((S.Action - 1) / 2 + 1));
61709467b48Spatrick       }
618097a140dSpatrick       Asm->emitULEB128(S.Action);
61909467b48Spatrick     }
62073471bf0Spatrick     Asm->OutStreamer->emitLabel(CstEndLabel);
62109467b48Spatrick   } else {
62209467b48Spatrick     // Itanium LSDA exception handling
62309467b48Spatrick 
62409467b48Spatrick     // The call-site table is a list of all call sites that may throw an
62509467b48Spatrick     // exception (including C++ 'throw' statements) in the procedure
62609467b48Spatrick     // fragment. It immediately follows the LSDA header. Each entry indicates,
62709467b48Spatrick     // for a given call, the first corresponding action record and corresponding
62809467b48Spatrick     // landing pad.
62909467b48Spatrick     //
63009467b48Spatrick     // The table begins with the number of bytes, stored as an LEB128
63109467b48Spatrick     // compressed, unsigned integer. The records immediately follow the record
63209467b48Spatrick     // count. They are sorted in increasing call-site address. Each record
63309467b48Spatrick     // indicates:
63409467b48Spatrick     //
63509467b48Spatrick     //   * The position of the call-site.
63609467b48Spatrick     //   * The position of the landing pad.
63709467b48Spatrick     //   * The first action record for that call site.
63809467b48Spatrick     //
63909467b48Spatrick     // A missing entry in the call-site table indicates that a call is not
64009467b48Spatrick     // supposed to throw.
64109467b48Spatrick 
64273471bf0Spatrick     assert(CallSiteRanges.size() != 0 && "No call-site ranges!");
64309467b48Spatrick 
64473471bf0Spatrick     // There should be only one call-site range which includes all the landing
64573471bf0Spatrick     // pads. Find that call-site range here.
64673471bf0Spatrick     const CallSiteRange *LandingPadRange = nullptr;
64773471bf0Spatrick     for (const CallSiteRange &CSRange : CallSiteRanges) {
64873471bf0Spatrick       if (CSRange.IsLPRange) {
64973471bf0Spatrick         assert(LandingPadRange == nullptr &&
65073471bf0Spatrick                "All landing pads must be in a single callsite range.");
65173471bf0Spatrick         LandingPadRange = &CSRange;
65273471bf0Spatrick       }
65373471bf0Spatrick     }
65473471bf0Spatrick 
65573471bf0Spatrick     // The call-site table is split into its call-site ranges, each being
65673471bf0Spatrick     // emitted as:
65773471bf0Spatrick     //              [ LPStartEncoding | LPStart ]
65873471bf0Spatrick     //              [ TypeTableEncoding | TypeTableOffset ]
65973471bf0Spatrick     //              [ CallSiteEncoding | CallSiteTableEndOffset ]
66073471bf0Spatrick     // cst_begin -> { call-site entries contained in this range }
66173471bf0Spatrick     //
66273471bf0Spatrick     // and is followed by the next call-site range.
66373471bf0Spatrick     //
66473471bf0Spatrick     // For each call-site range, CallSiteTableEndOffset is computed as the
66573471bf0Spatrick     // difference between cst_begin of that range and the last call-site-table's
66673471bf0Spatrick     // end label. This offset is used to find the action table.
66773471bf0Spatrick 
66873471bf0Spatrick     unsigned Entry = 0;
66973471bf0Spatrick     for (const CallSiteRange &CSRange : CallSiteRanges) {
67073471bf0Spatrick       if (CSRange.CallSiteBeginIdx != 0) {
67173471bf0Spatrick         // Align the call-site range for all ranges except the first. The
67273471bf0Spatrick         // first range is already aligned due to the exception table alignment.
67373471bf0Spatrick         Asm->emitAlignment(Align(4));
67473471bf0Spatrick       }
67573471bf0Spatrick       Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel);
67673471bf0Spatrick 
67773471bf0Spatrick       // Emit the LSDA header.
678*d415bd75Srobert       // LPStart is omitted if either we have a single call-site range (in which
679*d415bd75Srobert       // case the function entry is treated as @LPStart) or if this function has
680*d415bd75Srobert       // no landing pads (in which case @LPStart is undefined).
681*d415bd75Srobert       if (CallSiteRanges.size() == 1 || LandingPadRange == nullptr) {
68273471bf0Spatrick         Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart");
68373471bf0Spatrick       } else if (!Asm->isPositionIndependent()) {
68473471bf0Spatrick         // For more than one call-site ranges, LPStart must be explicitly
68573471bf0Spatrick         // specified.
68673471bf0Spatrick         // For non-PIC we can simply use the absolute value.
68773471bf0Spatrick         Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart");
68873471bf0Spatrick         Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel,
68973471bf0Spatrick                                           Asm->MAI->getCodePointerSize());
69073471bf0Spatrick       } else {
69173471bf0Spatrick         // For PIC mode, we Emit a PC-relative address for LPStart.
69273471bf0Spatrick         Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart");
69373471bf0Spatrick         MCContext &Context = Asm->OutStreamer->getContext();
69473471bf0Spatrick         MCSymbol *Dot = Context.createTempSymbol();
69573471bf0Spatrick         Asm->OutStreamer->emitLabel(Dot);
69673471bf0Spatrick         Asm->OutStreamer->emitValue(
69773471bf0Spatrick             MCBinaryExpr::createSub(
69873471bf0Spatrick                 MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel,
69973471bf0Spatrick                                         Context),
70073471bf0Spatrick                 MCSymbolRefExpr::create(Dot, Context), Context),
70173471bf0Spatrick             Asm->MAI->getCodePointerSize());
70273471bf0Spatrick       }
70373471bf0Spatrick 
70473471bf0Spatrick       if (HasLEB128Directives)
70573471bf0Spatrick         EmitTypeTableRefAndCallSiteTableEndRef();
70673471bf0Spatrick       else
70773471bf0Spatrick         EmitTypeTableOffsetAndCallSiteTableOffset();
70873471bf0Spatrick 
70973471bf0Spatrick       for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx;
71073471bf0Spatrick            CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) {
71173471bf0Spatrick         const CallSiteEntry &S = CallSites[CallSiteIdx];
71273471bf0Spatrick 
71373471bf0Spatrick         MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel;
71473471bf0Spatrick         MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel;
71509467b48Spatrick 
71609467b48Spatrick         MCSymbol *BeginLabel = S.BeginLabel;
71709467b48Spatrick         if (!BeginLabel)
71809467b48Spatrick           BeginLabel = EHFuncBeginSym;
71909467b48Spatrick         MCSymbol *EndLabel = S.EndLabel;
72009467b48Spatrick         if (!EndLabel)
72173471bf0Spatrick           EndLabel = EHFuncEndSym;
72209467b48Spatrick 
72309467b48Spatrick         // Offset of the call site relative to the start of the procedure.
72409467b48Spatrick         if (VerboseAsm)
72573471bf0Spatrick           Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) +
72673471bf0Spatrick                                        " <<");
727097a140dSpatrick         Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding);
72809467b48Spatrick         if (VerboseAsm)
72909467b48Spatrick           Asm->OutStreamer->AddComment(Twine("  Call between ") +
73009467b48Spatrick                                        BeginLabel->getName() + " and " +
73109467b48Spatrick                                        EndLabel->getName());
732097a140dSpatrick         Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding);
73309467b48Spatrick 
73473471bf0Spatrick         // Offset of the landing pad relative to the start of the landing pad
73573471bf0Spatrick         // fragment.
73609467b48Spatrick         if (!S.LPad) {
73709467b48Spatrick           if (VerboseAsm)
73809467b48Spatrick             Asm->OutStreamer->AddComment("    has no landing pad");
739097a140dSpatrick           Asm->emitCallSiteValue(0, CallSiteEncoding);
74009467b48Spatrick         } else {
74109467b48Spatrick           if (VerboseAsm)
74209467b48Spatrick             Asm->OutStreamer->AddComment(Twine("    jumps to ") +
74309467b48Spatrick                                          S.LPad->LandingPadLabel->getName());
74473471bf0Spatrick           Asm->emitCallSiteOffset(S.LPad->LandingPadLabel,
74573471bf0Spatrick                                   LandingPadRange->FragmentBeginLabel,
74609467b48Spatrick                                   CallSiteEncoding);
74709467b48Spatrick         }
74809467b48Spatrick 
74973471bf0Spatrick         // Offset of the first associated action record, relative to the start
75073471bf0Spatrick         // of the action table. This value is biased by 1 (1 indicates the start
75173471bf0Spatrick         // of the action table), and 0 indicates that there are no actions.
75209467b48Spatrick         if (VerboseAsm) {
75309467b48Spatrick           if (S.Action == 0)
75409467b48Spatrick             Asm->OutStreamer->AddComment("  On action: cleanup");
75509467b48Spatrick           else
75609467b48Spatrick             Asm->OutStreamer->AddComment("  On action: " +
75709467b48Spatrick                                          Twine((S.Action - 1) / 2 + 1));
75809467b48Spatrick         }
759097a140dSpatrick         Asm->emitULEB128(S.Action);
76009467b48Spatrick       }
76109467b48Spatrick     }
762097a140dSpatrick     Asm->OutStreamer->emitLabel(CstEndLabel);
76373471bf0Spatrick   }
76409467b48Spatrick 
76509467b48Spatrick   // Emit the Action Table.
76609467b48Spatrick   int Entry = 0;
76773471bf0Spatrick   for (const ActionEntry &Action : Actions) {
76809467b48Spatrick     if (VerboseAsm) {
76909467b48Spatrick       // Emit comments that decode the action table.
77009467b48Spatrick       Asm->OutStreamer->AddComment(">> Action Record " + Twine(++Entry) + " <<");
77109467b48Spatrick     }
77209467b48Spatrick 
77309467b48Spatrick     // Type Filter
77409467b48Spatrick     //
77509467b48Spatrick     //   Used by the runtime to match the type of the thrown exception to the
77609467b48Spatrick     //   type of the catch clauses or the types in the exception specification.
77709467b48Spatrick     if (VerboseAsm) {
77809467b48Spatrick       if (Action.ValueForTypeID > 0)
77909467b48Spatrick         Asm->OutStreamer->AddComment("  Catch TypeInfo " +
78009467b48Spatrick                                      Twine(Action.ValueForTypeID));
78109467b48Spatrick       else if (Action.ValueForTypeID < 0)
78209467b48Spatrick         Asm->OutStreamer->AddComment("  Filter TypeInfo " +
78309467b48Spatrick                                      Twine(Action.ValueForTypeID));
78409467b48Spatrick       else
78509467b48Spatrick         Asm->OutStreamer->AddComment("  Cleanup");
78609467b48Spatrick     }
787097a140dSpatrick     Asm->emitSLEB128(Action.ValueForTypeID);
78809467b48Spatrick 
78909467b48Spatrick     // Action Record
79009467b48Spatrick     if (VerboseAsm) {
79173471bf0Spatrick       if (Action.Previous == unsigned(-1)) {
79209467b48Spatrick         Asm->OutStreamer->AddComment("  No further actions");
79309467b48Spatrick       } else {
79473471bf0Spatrick         Asm->OutStreamer->AddComment("  Continue to action " +
79573471bf0Spatrick                                      Twine(Action.Previous + 1));
79609467b48Spatrick       }
79709467b48Spatrick     }
798097a140dSpatrick     Asm->emitSLEB128(Action.NextAction);
79909467b48Spatrick   }
80009467b48Spatrick 
80109467b48Spatrick   if (HaveTTData) {
802097a140dSpatrick     Asm->emitAlignment(Align(4));
80309467b48Spatrick     emitTypeInfos(TTypeEncoding, TTBaseLabel);
80409467b48Spatrick   }
80509467b48Spatrick 
806097a140dSpatrick   Asm->emitAlignment(Align(4));
80709467b48Spatrick   return GCCETSym;
80809467b48Spatrick }
80909467b48Spatrick 
emitTypeInfos(unsigned TTypeEncoding,MCSymbol * TTBaseLabel)81009467b48Spatrick void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) {
81109467b48Spatrick   const MachineFunction *MF = Asm->MF;
81209467b48Spatrick   const std::vector<const GlobalValue *> &TypeInfos = MF->getTypeInfos();
81309467b48Spatrick   const std::vector<unsigned> &FilterIds = MF->getFilterIds();
81409467b48Spatrick 
81573471bf0Spatrick   const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm();
81609467b48Spatrick 
81709467b48Spatrick   int Entry = 0;
81809467b48Spatrick   // Emit the Catch TypeInfos.
81909467b48Spatrick   if (VerboseAsm && !TypeInfos.empty()) {
82009467b48Spatrick     Asm->OutStreamer->AddComment(">> Catch TypeInfos <<");
821*d415bd75Srobert     Asm->OutStreamer->addBlankLine();
82209467b48Spatrick     Entry = TypeInfos.size();
82309467b48Spatrick   }
82409467b48Spatrick 
825*d415bd75Srobert   for (const GlobalValue *GV : llvm::reverse(TypeInfos)) {
82609467b48Spatrick     if (VerboseAsm)
82709467b48Spatrick       Asm->OutStreamer->AddComment("TypeInfo " + Twine(Entry--));
828097a140dSpatrick     Asm->emitTTypeReference(GV, TTypeEncoding);
82909467b48Spatrick   }
83009467b48Spatrick 
831097a140dSpatrick   Asm->OutStreamer->emitLabel(TTBaseLabel);
83209467b48Spatrick 
83309467b48Spatrick   // Emit the Exception Specifications.
83409467b48Spatrick   if (VerboseAsm && !FilterIds.empty()) {
83509467b48Spatrick     Asm->OutStreamer->AddComment(">> Filter TypeInfos <<");
836*d415bd75Srobert     Asm->OutStreamer->addBlankLine();
83709467b48Spatrick     Entry = 0;
83809467b48Spatrick   }
83909467b48Spatrick   for (std::vector<unsigned>::const_iterator
84009467b48Spatrick          I = FilterIds.begin(), E = FilterIds.end(); I < E; ++I) {
84109467b48Spatrick     unsigned TypeID = *I;
84209467b48Spatrick     if (VerboseAsm) {
84309467b48Spatrick       --Entry;
84409467b48Spatrick       if (isFilterEHSelector(TypeID))
84509467b48Spatrick         Asm->OutStreamer->AddComment("FilterInfo " + Twine(Entry));
84609467b48Spatrick     }
84709467b48Spatrick 
848097a140dSpatrick     Asm->emitULEB128(TypeID);
84909467b48Spatrick   }
85009467b48Spatrick }
851