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