160b640bbSReid Kleckner //===-- CodeGen/AsmPrinter/WinException.cpp - Dwarf Exception Impl ------===//
260b640bbSReid Kleckner //
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
660b640bbSReid Kleckner //
760b640bbSReid Kleckner //===----------------------------------------------------------------------===//
860b640bbSReid Kleckner //
960b640bbSReid Kleckner // This file contains support for writing Win64 exception info into asm files.
1060b640bbSReid Kleckner //
1160b640bbSReid Kleckner //===----------------------------------------------------------------------===//
1260b640bbSReid Kleckner 
1360b640bbSReid Kleckner #include "WinException.h"
1460b640bbSReid Kleckner #include "llvm/ADT/Twine.h"
15264b5d9eSZachary Turner #include "llvm/BinaryFormat/COFF.h"
16264b5d9eSZachary Turner #include "llvm/BinaryFormat/Dwarf.h"
1760b640bbSReid Kleckner #include "llvm/CodeGen/AsmPrinter.h"
1860b640bbSReid Kleckner #include "llvm/CodeGen/MachineFrameInfo.h"
1960b640bbSReid Kleckner #include "llvm/CodeGen/MachineFunction.h"
2060b640bbSReid Kleckner #include "llvm/CodeGen/MachineModuleInfo.h"
21b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetFrameLowering.h"
22b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetLowering.h"
23b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h"
2460b640bbSReid Kleckner #include "llvm/CodeGen/WinEHFuncInfo.h"
2560b640bbSReid Kleckner #include "llvm/IR/DataLayout.h"
2660b640bbSReid Kleckner #include "llvm/IR/Module.h"
2760b640bbSReid Kleckner #include "llvm/MC/MCAsmInfo.h"
2860b640bbSReid Kleckner #include "llvm/MC/MCContext.h"
2960b640bbSReid Kleckner #include "llvm/MC/MCExpr.h"
3060b640bbSReid Kleckner #include "llvm/MC/MCStreamer.h"
316054e650SDavid Blaikie #include "llvm/Target/TargetLoweringObjectFile.h"
32fe0006c8SSimon Pilgrim #include "llvm/Target/TargetMachine.h"
3360b640bbSReid Kleckner using namespace llvm;
3460b640bbSReid Kleckner 
WinException(AsmPrinter * A)351d3d4adbSReid Kleckner WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
361d3d4adbSReid Kleckner   // MSVC's EH tables are always composed of 32-bit words.  All known 64-bit
371d3d4adbSReid Kleckner   // platforms use an imagerel32 relocation to refer to symbols.
381d3d4adbSReid Kleckner   useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
3996f2ea3dSSanjin Sijaric   isAArch64 = Asm->TM.getTargetTriple().isAArch64();
408ecce695SDaniel Paoliello   isThumb = Asm->TM.getTargetTriple().isThumb();
411d3d4adbSReid Kleckner }
4260b640bbSReid Kleckner 
433a8c5148SKazu Hirata WinException::~WinException() = default;
4460b640bbSReid Kleckner 
4560b640bbSReid Kleckner /// endModule - Emit all exception information that should come after the
4660b640bbSReid Kleckner /// content.
endModule()4760b640bbSReid Kleckner void WinException::endModule() {
482bc93ca8SReid Kleckner   auto &OS = *Asm->OutStreamer;
492bc93ca8SReid Kleckner   const Module *M = MMI->getModule();
50ca6ef66eSReid Kleckner   for (const Function &F : *M)
51ca6ef66eSReid Kleckner     if (F.hasFnAttribute("safeseh"))
529ee15bbaSFangrui Song       OS.emitCOFFSafeSEH(Asm->getSymbol(&F));
5308086647SArlo Siemsen 
5408086647SArlo Siemsen   if (M->getModuleFlag("ehcontguard") && !EHContTargets.empty()) {
5508086647SArlo Siemsen     // Emit the symbol index of each ehcont target.
56*adf4142fSFangrui Song     OS.switchSection(Asm->OutContext.getObjectFileInfo()->getGEHContSection());
5708086647SArlo Siemsen     for (const MCSymbol *S : EHContTargets) {
589ee15bbaSFangrui Song       OS.emitCOFFSymbolIndex(S);
5908086647SArlo Siemsen     }
6008086647SArlo Siemsen   }
612bc93ca8SReid Kleckner }
6260b640bbSReid Kleckner 
beginFunction(const MachineFunction * MF)6360b640bbSReid Kleckner void WinException::beginFunction(const MachineFunction *MF) {
6460b640bbSReid Kleckner   shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;
6560b640bbSReid Kleckner 
6660b640bbSReid Kleckner   // If any landing pads survive, we need an EH table.
67d0ee66c2SMatthias Braun   bool hasLandingPads = !MF->getLandingPads().empty();
68d0ee66c2SMatthias Braun   bool hasEHFunclets = MF->hasEHFunclets();
6960b640bbSReid Kleckner 
70f1caa283SMatthias Braun   const Function &F = MF->getFunction();
711d3d4adbSReid Kleckner 
728819c738SReid Kleckner   shouldEmitMoves = Asm->needsSEHMoves() && MF->hasWinCFI();
7360b640bbSReid Kleckner 
7460b640bbSReid Kleckner   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
7560b640bbSReid Kleckner   unsigned PerEncoding = TLOF.getPersonalityEncoding();
7660b640bbSReid Kleckner 
779cb915b7SReid Kleckner   EHPersonality Per = EHPersonality::Unknown;
789cb915b7SReid Kleckner   const Function *PerFn = nullptr;
79f1caa283SMatthias Braun   if (F.hasPersonalityFn()) {
80f1caa283SMatthias Braun     PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
819cb915b7SReid Kleckner     Per = classifyEHPersonality(PerFn);
829cb915b7SReid Kleckner   }
839cb915b7SReid Kleckner 
84f1caa283SMatthias Braun   bool forceEmitPersonality = F.hasPersonalityFn() &&
859cb915b7SReid Kleckner                               !isNoOpWithoutInvoke(Per) &&
86f1caa283SMatthias Braun                               F.needsUnwindTableEntry();
87aff703a2SKeno Fischer 
880e288234SReid Kleckner   shouldEmitPersonality =
890e288234SReid Kleckner       forceEmitPersonality || ((hasLandingPads || hasEHFunclets) &&
909cb915b7SReid Kleckner                                PerEncoding != dwarf::DW_EH_PE_omit && PerFn);
9160b640bbSReid Kleckner 
9260b640bbSReid Kleckner   unsigned LSDAEncoding = TLOF.getLSDAEncoding();
9360b640bbSReid Kleckner   shouldEmitLSDA = shouldEmitPersonality &&
9460b640bbSReid Kleckner     LSDAEncoding != dwarf::DW_EH_PE_omit;
9560b640bbSReid Kleckner 
960e288234SReid Kleckner   // If we're not using CFI, we don't want the CFI or the personality, but we
970e288234SReid Kleckner   // might want EH tables if we had EH pads.
988819c738SReid Kleckner   if (!Asm->MAI->usesWindowsCFI()) {
999cb915b7SReid Kleckner     if (Per == EHPersonality::MSVC_X86SEH && !hasEHFunclets) {
1009cb915b7SReid Kleckner       // If this is 32-bit SEH and we don't have any funclets (really invokes),
1019cb915b7SReid Kleckner       // make sure we emit the parent offset label. Some unreferenced filter
1029cb915b7SReid Kleckner       // functions may still refer to it.
1039cb915b7SReid Kleckner       const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
1049cb915b7SReid Kleckner       StringRef FLinkageName =
105f1caa283SMatthias Braun           GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
1069cb915b7SReid Kleckner       emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
1079cb915b7SReid Kleckner     }
108bfa5b982SDavid Majnemer     shouldEmitLSDA = hasEHFunclets;
1091d3d4adbSReid Kleckner     shouldEmitPersonality = false;
1101d3d4adbSReid Kleckner     return;
1111d3d4adbSReid Kleckner   }
11260b640bbSReid Kleckner 
113a80c1512SDavid Majnemer   beginFunclet(MF->front(), Asm->CurrentFnSym);
1141d3d4adbSReid Kleckner }
11560b640bbSReid Kleckner 
markFunctionEnd()1160b61d220SEli Friedman void WinException::markFunctionEnd() {
1170b61d220SEli Friedman   if (isAArch64 && CurrentFuncletEntry &&
1180b61d220SEli Friedman       (shouldEmitMoves || shouldEmitPersonality))
1199ee15bbaSFangrui Song     Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();
1200b61d220SEli Friedman }
1210b61d220SEli Friedman 
12260b640bbSReid Kleckner /// endFunction - Gather and emit post-function exception information.
12360b640bbSReid Kleckner ///
endFunction(const MachineFunction * MF)12460b640bbSReid Kleckner void WinException::endFunction(const MachineFunction *MF) {
1251d3d4adbSReid Kleckner   if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)
12660b640bbSReid Kleckner     return;
12760b640bbSReid Kleckner 
128f1caa283SMatthias Braun   const Function &F = MF->getFunction();
1299a1a9194SReid Kleckner   EHPersonality Per = EHPersonality::Unknown;
130f1caa283SMatthias Braun   if (F.hasPersonalityFn())
131f1caa283SMatthias Braun     Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());
13260b640bbSReid Kleckner 
1332afea543SJoseph Tremoulet   // Get rid of any dead landing pads if we're not using funclets. In funclet
1342afea543SJoseph Tremoulet   // schemes, the landing pad is not actually reachable. It only exists so
1352afea543SJoseph Tremoulet   // that we can emit the right table data.
136d0ee66c2SMatthias Braun   if (!isFuncletEHPersonality(Per)) {
137d0ee66c2SMatthias Braun     MachineFunction *NonConstMF = const_cast<MachineFunction*>(MF);
138d0ee66c2SMatthias Braun     NonConstMF->tidyLandingPads();
139d0ee66c2SMatthias Braun   }
14060b640bbSReid Kleckner 
1410b61d220SEli Friedman   endFuncletImpl();
142a80c1512SDavid Majnemer 
1434c0a0169SLuqman Aden   // endFunclet will emit the necessary .xdata tables for table-based SEH.
1444c0a0169SLuqman Aden   if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets())
145fc64fae6SReid Kleckner     return;
146fc64fae6SReid Kleckner 
1471d3d4adbSReid Kleckner   if (shouldEmitPersonality || shouldEmitLSDA) {
14815d82c62SFangrui Song     Asm->OutStreamer->pushSection();
14960b640bbSReid Kleckner 
15097837b7bSReid Kleckner     // Just switch sections to the right xdata section.
15197837b7bSReid Kleckner     MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection(
15297837b7bSReid Kleckner         Asm->OutStreamer->getCurrentSectionOnly());
153*adf4142fSFangrui Song     Asm->OutStreamer->switchSection(XData);
15460b640bbSReid Kleckner 
15560b640bbSReid Kleckner     // Emit the tables appropriate to the personality function in use. If we
15660b640bbSReid Kleckner     // don't recognize the personality, assume it uses an Itanium-style LSDA.
1574c0a0169SLuqman Aden     if (Per == EHPersonality::MSVC_TableSEH)
15894b704c4SReid Kleckner       emitCSpecificHandlerTable(MF);
1591d3d4adbSReid Kleckner     else if (Per == EHPersonality::MSVC_X86SEH)
160f12c030fSReid Kleckner       emitExceptHandlerTable(MF);
16160b640bbSReid Kleckner     else if (Per == EHPersonality::MSVC_CXX)
16260b640bbSReid Kleckner       emitCXXFrameHandler3Table(MF);
16328c89bbbSJoseph Tremoulet     else if (Per == EHPersonality::CoreCLR)
16428c89bbbSJoseph Tremoulet       emitCLRExceptionTable(MF);
16560b640bbSReid Kleckner     else
16660b640bbSReid Kleckner       emitExceptionTable();
16760b640bbSReid Kleckner 
16815d82c62SFangrui Song     Asm->OutStreamer->popSection();
16960b640bbSReid Kleckner   }
17008086647SArlo Siemsen 
17108086647SArlo Siemsen   if (!MF->getCatchretTargets().empty()) {
17208086647SArlo Siemsen     // Copy the function's catchret targets to a module-level list.
17308086647SArlo Siemsen     EHContTargets.insert(EHContTargets.end(), MF->getCatchretTargets().begin(),
17408086647SArlo Siemsen                          MF->getCatchretTargets().end());
17508086647SArlo Siemsen   }
176a80c1512SDavid Majnemer }
1771d3d4adbSReid Kleckner 
178f2fbf437SSimon Pilgrim /// Retrieve the MCSymbol for a GlobalValue or MachineBasicBlock.
getMCSymbolForMBB(AsmPrinter * Asm,const MachineBasicBlock * MBB)179bfa5b982SDavid Majnemer static MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm,
180bfa5b982SDavid Majnemer                                    const MachineBasicBlock *MBB) {
181bfa5b982SDavid Majnemer   if (!MBB)
182a80c1512SDavid Majnemer     return nullptr;
183bfa5b982SDavid Majnemer 
184a80c1512SDavid Majnemer   assert(MBB->isEHFuncletEntry());
185a80c1512SDavid Majnemer 
186a80c1512SDavid Majnemer   // Give catches and cleanups a name based off of their parent function and
187a80c1512SDavid Majnemer   // their funclet entry block's number.
188a80c1512SDavid Majnemer   const MachineFunction *MF = MBB->getParent();
189f1caa283SMatthias Braun   const Function &F = MF->getFunction();
190f1caa283SMatthias Braun   StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
191a80c1512SDavid Majnemer   MCContext &Ctx = MF->getContext();
192a80c1512SDavid Majnemer   StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";
193a80c1512SDavid Majnemer   return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +
194a80c1512SDavid Majnemer                                Twine(MBB->getNumber()) + "@?0?" +
195a80c1512SDavid Majnemer                                FuncLinkageName + "@4HA");
196a80c1512SDavid Majnemer }
197a80c1512SDavid Majnemer 
beginFunclet(const MachineBasicBlock & MBB,MCSymbol * Sym)198a80c1512SDavid Majnemer void WinException::beginFunclet(const MachineBasicBlock &MBB,
199a80c1512SDavid Majnemer                                 MCSymbol *Sym) {
200a80c1512SDavid Majnemer   CurrentFuncletEntry = &MBB;
201a80c1512SDavid Majnemer 
202f1caa283SMatthias Braun   const Function &F = Asm->MF->getFunction();
203a80c1512SDavid Majnemer   // If a symbol was not provided for the funclet, invent one.
204a80c1512SDavid Majnemer   if (!Sym) {
205bfa5b982SDavid Majnemer     Sym = getMCSymbolForMBB(Asm, &MBB);
206a80c1512SDavid Majnemer 
207a80c1512SDavid Majnemer     // Describe our funclet symbol as a function with internal linkage.
20815d82c62SFangrui Song     Asm->OutStreamer->beginCOFFSymbolDef(Sym);
2099ee15bbaSFangrui Song     Asm->OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
2109ee15bbaSFangrui Song     Asm->OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
211a80c1512SDavid Majnemer                                          << COFF::SCT_COMPLEX_TYPE_SHIFT);
21215d82c62SFangrui Song     Asm->OutStreamer->endCOFFSymbolDef();
213a80c1512SDavid Majnemer 
214a80c1512SDavid Majnemer     // We want our funclet's entry point to be aligned such that no nops will be
215a80c1512SDavid Majnemer     // present after the label.
2161d49eb00SFangrui Song     Asm->emitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),
21797264366SGuillaume Chatelet                        &F);
218a80c1512SDavid Majnemer 
219a80c1512SDavid Majnemer     // Now that we've emitted the alignment directive, point at our funclet.
2206d2d589bSFangrui Song     Asm->OutStreamer->emitLabel(Sym);
221a80c1512SDavid Majnemer   }
222a80c1512SDavid Majnemer 
223a80c1512SDavid Majnemer   // Mark 'Sym' as starting our funclet.
22492647369SReid Kleckner   if (shouldEmitMoves || shouldEmitPersonality) {
22592647369SReid Kleckner     CurrentFuncletTextSection = Asm->OutStreamer->getCurrentSectionOnly();
2269ee15bbaSFangrui Song     Asm->OutStreamer->emitWinCFIStartProc(Sym);
22792647369SReid Kleckner   }
228a80c1512SDavid Majnemer 
229a80c1512SDavid Majnemer   if (shouldEmitPersonality) {
230a80c1512SDavid Majnemer     const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
231a80c1512SDavid Majnemer     const Function *PerFn = nullptr;
232a80c1512SDavid Majnemer 
233a80c1512SDavid Majnemer     // Determine which personality routine we are using for this funclet.
234f1caa283SMatthias Braun     if (F.hasPersonalityFn())
235f1caa283SMatthias Braun       PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
236a80c1512SDavid Majnemer     const MCSymbol *PersHandlerSym =
2374367c7fbSEric Christopher         TLOF.getCFIPersonalitySymbol(PerFn, Asm->TM, MMI);
238a80c1512SDavid Majnemer 
239785e7d28SReid Kleckner     // Do not emit a .seh_handler directives for cleanup funclets.
240785e7d28SReid Kleckner     // FIXME: This means cleanup funclets cannot handle exceptions. Given that
241785e7d28SReid Kleckner     // Clang doesn't produce EH constructs inside cleanup funclets and LLVM's
242785e7d28SReid Kleckner     // inliner doesn't allow inlining them, this isn't a major problem in
243785e7d28SReid Kleckner     // practice.
244785e7d28SReid Kleckner     if (!CurrentFuncletEntry->isCleanupFuncletEntry())
2459ee15bbaSFangrui Song       Asm->OutStreamer->emitWinEHHandler(PersHandlerSym, true, true);
246a80c1512SDavid Majnemer   }
247a80c1512SDavid Majnemer }
248a80c1512SDavid Majnemer 
endFunclet()249a80c1512SDavid Majnemer void WinException::endFunclet() {
2500b61d220SEli Friedman   if (isAArch64 && CurrentFuncletEntry &&
2510b61d220SEli Friedman       (shouldEmitMoves || shouldEmitPersonality)) {
252*adf4142fSFangrui Song     Asm->OutStreamer->switchSection(CurrentFuncletTextSection);
2539ee15bbaSFangrui Song     Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();
2540b61d220SEli Friedman   }
2550b61d220SEli Friedman   endFuncletImpl();
2560b61d220SEli Friedman }
2570b61d220SEli Friedman 
endFuncletImpl()2580b61d220SEli Friedman void WinException::endFuncletImpl() {
259a80c1512SDavid Majnemer   // No funclet to process?  Great, we have nothing to do.
260a80c1512SDavid Majnemer   if (!CurrentFuncletEntry)
261a80c1512SDavid Majnemer     return;
262a80c1512SDavid Majnemer 
263d0ee66c2SMatthias Braun   const MachineFunction *MF = Asm->MF;
264a80c1512SDavid Majnemer   if (shouldEmitMoves || shouldEmitPersonality) {
265f1caa283SMatthias Braun     const Function &F = MF->getFunction();
266a80c1512SDavid Majnemer     EHPersonality Per = EHPersonality::Unknown;
267f1caa283SMatthias Braun     if (F.hasPersonalityFn())
268f1caa283SMatthias Braun       Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());
269a80c1512SDavid Majnemer 
2706f792041SMartin Storsjö     if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&
2716f792041SMartin Storsjö         !CurrentFuncletEntry->isCleanupFuncletEntry()) {
272a80c1512SDavid Majnemer       // Emit an UNWIND_INFO struct describing the prologue.
2739ee15bbaSFangrui Song       Asm->OutStreamer->emitWinEHHandlerData();
274a80c1512SDavid Majnemer 
275fc64fae6SReid Kleckner       // If this is a C++ catch funclet (or the parent function),
276fc64fae6SReid Kleckner       // emit a reference to the LSDA for the parent function.
277f1caa283SMatthias Braun       StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
278a80c1512SDavid Majnemer       MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
279a80c1512SDavid Majnemer           Twine("$cppxdata$", FuncLinkageName));
28077497103SFangrui Song       Asm->OutStreamer->emitValue(create32bitRef(FuncInfoXData), 4);
2814c0a0169SLuqman Aden     } else if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets() &&
282fc64fae6SReid Kleckner                !CurrentFuncletEntry->isEHFuncletEntry()) {
2836f792041SMartin Storsjö       // Emit an UNWIND_INFO struct describing the prologue.
2849ee15bbaSFangrui Song       Asm->OutStreamer->emitWinEHHandlerData();
2856f792041SMartin Storsjö 
286fc64fae6SReid Kleckner       // If this is the parent function in Win64 SEH, emit the LSDA immediately
287fc64fae6SReid Kleckner       // following .seh_handlerdata.
288d0ee66c2SMatthias Braun       emitCSpecificHandlerTable(MF);
2896f792041SMartin Storsjö     } else if (shouldEmitPersonality || shouldEmitLSDA) {
2906f792041SMartin Storsjö       // Emit an UNWIND_INFO struct describing the prologue.
2919ee15bbaSFangrui Song       Asm->OutStreamer->emitWinEHHandlerData();
2926f792041SMartin Storsjö       // In these cases, no further info is written to the .xdata section
2936f792041SMartin Storsjö       // right here, but is written by e.g. emitExceptionTable in endFunction()
2946f792041SMartin Storsjö       // above.
2956f792041SMartin Storsjö     } else {
2966f792041SMartin Storsjö       // No need to emit the EH handler data right here if nothing needs
2976f792041SMartin Storsjö       // writing to the .xdata section; it will be emitted for all
2986f792041SMartin Storsjö       // functions that need it in the end anyway.
299a80c1512SDavid Majnemer     }
300a80c1512SDavid Majnemer 
30192647369SReid Kleckner     // Switch back to the funclet start .text section now that we are done
30292647369SReid Kleckner     // writing to .xdata, and emit an .seh_endproc directive to mark the end of
30392647369SReid Kleckner     // the function.
304*adf4142fSFangrui Song     Asm->OutStreamer->switchSection(CurrentFuncletTextSection);
3059ee15bbaSFangrui Song     Asm->OutStreamer->emitWinCFIEndProc();
30660b640bbSReid Kleckner   }
30760b640bbSReid Kleckner 
308a80c1512SDavid Majnemer   // Let's make sure we don't try to end the same funclet twice.
309a80c1512SDavid Majnemer   CurrentFuncletEntry = nullptr;
310a80c1512SDavid Majnemer }
311a80c1512SDavid Majnemer 
create32bitRef(const MCSymbol * Value)3121d3d4adbSReid Kleckner const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
31360b640bbSReid Kleckner   if (!Value)
31413760bd1SJim Grosbach     return MCConstantExpr::create(0, Asm->OutContext);
31513760bd1SJim Grosbach   return MCSymbolRefExpr::create(Value, useImageRel32
3161d3d4adbSReid Kleckner                                             ? MCSymbolRefExpr::VK_COFF_IMGREL32
3171d3d4adbSReid Kleckner                                             : MCSymbolRefExpr::VK_None,
31860b640bbSReid Kleckner                                  Asm->OutContext);
31960b640bbSReid Kleckner }
32060b640bbSReid Kleckner 
create32bitRef(const GlobalValue * GV)3213d0fbf1dSJoseph Tremoulet const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
3223d0fbf1dSJoseph Tremoulet   if (!GV)
32313760bd1SJim Grosbach     return MCConstantExpr::create(0, Asm->OutContext);
3240e288234SReid Kleckner   return create32bitRef(Asm->getSymbol(GV));
32560b640bbSReid Kleckner }
32660b640bbSReid Kleckner 
getLabel(const MCSymbol * Label)32796f2ea3dSSanjin Sijaric const MCExpr *WinException::getLabel(const MCSymbol *Label) {
32896f2ea3dSSanjin Sijaric   return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32,
32996f2ea3dSSanjin Sijaric                                  Asm->OutContext);
3308ecce695SDaniel Paoliello }
3318ecce695SDaniel Paoliello 
getLabelPlusOne(const MCSymbol * Label)3328ecce695SDaniel Paoliello const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) {
3338ecce695SDaniel Paoliello   return MCBinaryExpr::createAdd(getLabel(Label),
334c71d6275SReid Kleckner                                  MCConstantExpr::create(1, Asm->OutContext),
335c71d6275SReid Kleckner                                  Asm->OutContext);
336c71d6275SReid Kleckner }
337c71d6275SReid Kleckner 
getOffset(const MCSymbol * OffsetOf,const MCSymbol * OffsetFrom)33828c89bbbSJoseph Tremoulet const MCExpr *WinException::getOffset(const MCSymbol *OffsetOf,
33928c89bbbSJoseph Tremoulet                                       const MCSymbol *OffsetFrom) {
34028c89bbbSJoseph Tremoulet   return MCBinaryExpr::createSub(
34128c89bbbSJoseph Tremoulet       MCSymbolRefExpr::create(OffsetOf, Asm->OutContext),
34228c89bbbSJoseph Tremoulet       MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext);
34328c89bbbSJoseph Tremoulet }
34428c89bbbSJoseph Tremoulet 
getOffsetPlusOne(const MCSymbol * OffsetOf,const MCSymbol * OffsetFrom)34528c89bbbSJoseph Tremoulet const MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf,
34628c89bbbSJoseph Tremoulet                                              const MCSymbol *OffsetFrom) {
34728c89bbbSJoseph Tremoulet   return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom),
34828c89bbbSJoseph Tremoulet                                  MCConstantExpr::create(1, Asm->OutContext),
34928c89bbbSJoseph Tremoulet                                  Asm->OutContext);
35028c89bbbSJoseph Tremoulet }
35128c89bbbSJoseph Tremoulet 
getFrameIndexOffset(int FrameIndex,const WinEHFuncInfo & FuncInfo)352c20276d0SReid Kleckner int WinException::getFrameIndexOffset(int FrameIndex,
353c20276d0SReid Kleckner                                       const WinEHFuncInfo &FuncInfo) {
35470bf6bb5SReid Kleckner   const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();
3552481f26aSMatt Arsenault   Register UnusedReg;
3560ebc9616SSanjoy Das   if (Asm->MAI->usesWindowsCFI()) {
357d57bba7cSSander de Smalen     StackOffset Offset =
3580ebc9616SSanjoy Das         TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg,
3590ebc9616SSanjoy Das                                            /*IgnoreSPUpdates*/ true);
3600ebc9616SSanjoy Das     assert(UnusedReg ==
3610ebc9616SSanjoy Das            Asm->MF->getSubtarget()
3620ebc9616SSanjoy Das                .getTargetLowering()
3630ebc9616SSanjoy Das                ->getStackPointerRegisterToSaveRestore());
364d57bba7cSSander de Smalen     return Offset.getFixed();
3650ebc9616SSanjoy Das   }
3660ebc9616SSanjoy Das 
3676ddae310SReid Kleckner   // For 32-bit, offsets should be relative to the end of the EH registration
3686ddae310SReid Kleckner   // node. For 64-bit, it's relative to SP at the end of the prologue.
3696ddae310SReid Kleckner   assert(FuncInfo.EHRegNodeEndOffset != INT_MAX);
370d57bba7cSSander de Smalen   StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);
371d57bba7cSSander de Smalen   Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset);
372d57bba7cSSander de Smalen   assert(!Offset.getScalable() &&
373d57bba7cSSander de Smalen          "Frame offsets with a scalable component are not supported");
374d57bba7cSSander de Smalen   return Offset.getFixed();
37570bf6bb5SReid Kleckner }
37670bf6bb5SReid Kleckner 
377808d2a07SBenjamin Kramer namespace {
378fc64fae6SReid Kleckner 
3791e2f062eSJoseph Tremoulet /// Top-level state used to represent unwind to caller
3801e2f062eSJoseph Tremoulet const int NullState = -1;
3811e2f062eSJoseph Tremoulet 
3821e2f062eSJoseph Tremoulet struct InvokeStateChange {
3831e2f062eSJoseph Tremoulet   /// EH Label immediately after the last invoke in the previous state, or
3841e2f062eSJoseph Tremoulet   /// nullptr if the previous state was the null state.
3851e2f062eSJoseph Tremoulet   const MCSymbol *PreviousEndLabel;
3861e2f062eSJoseph Tremoulet 
3871e2f062eSJoseph Tremoulet   /// EH label immediately before the first invoke in the new state, or nullptr
3881e2f062eSJoseph Tremoulet   /// if the new state is the null state.
3891e2f062eSJoseph Tremoulet   const MCSymbol *NewStartLabel;
3901e2f062eSJoseph Tremoulet 
3911e2f062eSJoseph Tremoulet   /// State of the invoke following NewStartLabel, or NullState to indicate
3921e2f062eSJoseph Tremoulet   /// the presence of calls which may unwind to caller.
3931e2f062eSJoseph Tremoulet   int NewState;
394fc64fae6SReid Kleckner };
395fc64fae6SReid Kleckner 
3961e2f062eSJoseph Tremoulet /// Iterator that reports all the invoke state changes in a range of machine
3971e2f062eSJoseph Tremoulet /// basic blocks.  Changes to the null state are reported whenever a call that
3981e2f062eSJoseph Tremoulet /// may unwind to caller is encountered.  The MBB range is expected to be an
3991e2f062eSJoseph Tremoulet /// entire function or funclet, and the start and end of the range are treated
4001e2f062eSJoseph Tremoulet /// as being in the NullState even if there's not an unwind-to-caller call
4011e2f062eSJoseph Tremoulet /// before the first invoke or after the last one (i.e., the first state change
4021e2f062eSJoseph Tremoulet /// reported is the first change to something other than NullState, and a
4031e2f062eSJoseph Tremoulet /// change back to NullState is always reported at the end of iteration).
4041e2f062eSJoseph Tremoulet class InvokeStateChangeIterator {
InvokeStateChangeIterator(const WinEHFuncInfo & EHInfo,MachineFunction::const_iterator MFI,MachineFunction::const_iterator MFE,MachineBasicBlock::const_iterator MBBI,int BaseState)405c20276d0SReid Kleckner   InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo,
4061e2f062eSJoseph Tremoulet                             MachineFunction::const_iterator MFI,
4071e2f062eSJoseph Tremoulet                             MachineFunction::const_iterator MFE,
4088a1c45d6SDavid Majnemer                             MachineBasicBlock::const_iterator MBBI,
4098a1c45d6SDavid Majnemer                             int BaseState)
4108a1c45d6SDavid Majnemer       : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) {
4111e2f062eSJoseph Tremoulet     LastStateChange.PreviousEndLabel = nullptr;
4121e2f062eSJoseph Tremoulet     LastStateChange.NewStartLabel = nullptr;
4138a1c45d6SDavid Majnemer     LastStateChange.NewState = BaseState;
414fc64fae6SReid Kleckner     scan();
415fc64fae6SReid Kleckner   }
416fc64fae6SReid Kleckner 
4171e2f062eSJoseph Tremoulet public:
4181e2f062eSJoseph Tremoulet   static iterator_range<InvokeStateChangeIterator>
range(const WinEHFuncInfo & EHInfo,MachineFunction::const_iterator Begin,MachineFunction::const_iterator End,int BaseState=NullState)419c20276d0SReid Kleckner   range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin,
4208a1c45d6SDavid Majnemer         MachineFunction::const_iterator End, int BaseState = NullState) {
4211e2f062eSJoseph Tremoulet     // Reject empty ranges to simplify bookkeeping by ensuring that we can get
4221e2f062eSJoseph Tremoulet     // the end of the last block.
4231e2f062eSJoseph Tremoulet     assert(Begin != End);
4241e2f062eSJoseph Tremoulet     auto BlockBegin = Begin->begin();
4251e2f062eSJoseph Tremoulet     auto BlockEnd = std::prev(End)->end();
4268a1c45d6SDavid Majnemer     return make_range(
4278a1c45d6SDavid Majnemer         InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState),
4288a1c45d6SDavid Majnemer         InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState));
4291e2f062eSJoseph Tremoulet   }
4301e2f062eSJoseph Tremoulet 
431fc64fae6SReid Kleckner   // Iterator methods.
operator ==(const InvokeStateChangeIterator & O) const4321e2f062eSJoseph Tremoulet   bool operator==(const InvokeStateChangeIterator &O) const {
4338a1c45d6SDavid Majnemer     assert(BaseState == O.BaseState);
4341e2f062eSJoseph Tremoulet     // Must be visiting same block.
4351e2f062eSJoseph Tremoulet     if (MFI != O.MFI)
4361e2f062eSJoseph Tremoulet       return false;
4371e2f062eSJoseph Tremoulet     // Must be visiting same isntr.
4381e2f062eSJoseph Tremoulet     if (MBBI != O.MBBI)
4391e2f062eSJoseph Tremoulet       return false;
4401e2f062eSJoseph Tremoulet     // At end of block/instr iteration, we can still have two distinct states:
4411e2f062eSJoseph Tremoulet     // one to report the final EndLabel, and another indicating the end of the
4421e2f062eSJoseph Tremoulet     // state change iteration.  Check for CurrentEndLabel equality to
4431e2f062eSJoseph Tremoulet     // distinguish these.
4441e2f062eSJoseph Tremoulet     return CurrentEndLabel == O.CurrentEndLabel;
4451e2f062eSJoseph Tremoulet   }
4461e2f062eSJoseph Tremoulet 
operator !=(const InvokeStateChangeIterator & O) const4471e2f062eSJoseph Tremoulet   bool operator!=(const InvokeStateChangeIterator &O) const {
4481e2f062eSJoseph Tremoulet     return !operator==(O);
4491e2f062eSJoseph Tremoulet   }
operator *()4501e2f062eSJoseph Tremoulet   InvokeStateChange &operator*() { return LastStateChange; }
operator ->()4511e2f062eSJoseph Tremoulet   InvokeStateChange *operator->() { return &LastStateChange; }
operator ++()4521e2f062eSJoseph Tremoulet   InvokeStateChangeIterator &operator++() { return scan(); }
453fc64fae6SReid Kleckner 
454fc64fae6SReid Kleckner private:
4551e2f062eSJoseph Tremoulet   InvokeStateChangeIterator &scan();
456fc64fae6SReid Kleckner 
457c20276d0SReid Kleckner   const WinEHFuncInfo &EHInfo;
4581e2f062eSJoseph Tremoulet   const MCSymbol *CurrentEndLabel = nullptr;
4591e2f062eSJoseph Tremoulet   MachineFunction::const_iterator MFI;
4601e2f062eSJoseph Tremoulet   MachineFunction::const_iterator MFE;
461fc64fae6SReid Kleckner   MachineBasicBlock::const_iterator MBBI;
4621e2f062eSJoseph Tremoulet   InvokeStateChange LastStateChange;
4631e2f062eSJoseph Tremoulet   bool VisitingInvoke = false;
4648a1c45d6SDavid Majnemer   int BaseState;
465fc64fae6SReid Kleckner };
4661e2f062eSJoseph Tremoulet 
467808d2a07SBenjamin Kramer } // end anonymous namespace
468fc64fae6SReid Kleckner 
scan()4691e2f062eSJoseph Tremoulet InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
4701e2f062eSJoseph Tremoulet   bool IsNewBlock = false;
4711e2f062eSJoseph Tremoulet   for (; MFI != MFE; ++MFI, IsNewBlock = true) {
4721e2f062eSJoseph Tremoulet     if (IsNewBlock)
4731e2f062eSJoseph Tremoulet       MBBI = MFI->begin();
4741e2f062eSJoseph Tremoulet     for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) {
4751e2f062eSJoseph Tremoulet       const MachineInstr &MI = *MBBI;
4768a1c45d6SDavid Majnemer       if (!VisitingInvoke && LastStateChange.NewState != BaseState &&
4771e2f062eSJoseph Tremoulet           MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) {
4781e2f062eSJoseph Tremoulet         // Indicate a change of state to the null state.  We don't have
4791e2f062eSJoseph Tremoulet         // start/end EH labels handy but the caller won't expect them for
4801e2f062eSJoseph Tremoulet         // null state regions.
4811e2f062eSJoseph Tremoulet         LastStateChange.PreviousEndLabel = CurrentEndLabel;
4821e2f062eSJoseph Tremoulet         LastStateChange.NewStartLabel = nullptr;
4838a1c45d6SDavid Majnemer         LastStateChange.NewState = BaseState;
4841e2f062eSJoseph Tremoulet         CurrentEndLabel = nullptr;
4851e2f062eSJoseph Tremoulet         // Don't re-visit this instr on the next scan
4861e2f062eSJoseph Tremoulet         ++MBBI;
4871e2f062eSJoseph Tremoulet         return *this;
488fc64fae6SReid Kleckner       }
4891e2f062eSJoseph Tremoulet 
4901e2f062eSJoseph Tremoulet       // All other state changes are at EH labels before/after invokes.
491fc64fae6SReid Kleckner       if (!MI.isEHLabel())
492fc64fae6SReid Kleckner         continue;
493fc64fae6SReid Kleckner       MCSymbol *Label = MI.getOperand(0).getMCSymbol();
4941e2f062eSJoseph Tremoulet       if (Label == CurrentEndLabel) {
4951e2f062eSJoseph Tremoulet         VisitingInvoke = false;
496fc64fae6SReid Kleckner         continue;
497fc64fae6SReid Kleckner       }
4988a1c45d6SDavid Majnemer       auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label);
4991e2f062eSJoseph Tremoulet       // Ignore EH labels that aren't the ones inserted before an invoke
5008a1c45d6SDavid Majnemer       if (InvokeMapIter == EHInfo.LabelToStateMap.end())
5011e2f062eSJoseph Tremoulet         continue;
5021e2f062eSJoseph Tremoulet       auto &StateAndEnd = InvokeMapIter->second;
5031e2f062eSJoseph Tremoulet       int NewState = StateAndEnd.first;
5041e2f062eSJoseph Tremoulet       // Keep track of the fact that we're between EH start/end labels so
5051e2f062eSJoseph Tremoulet       // we know not to treat the inoke we'll see as unwinding to caller.
5061e2f062eSJoseph Tremoulet       VisitingInvoke = true;
5071e2f062eSJoseph Tremoulet       if (NewState == LastStateChange.NewState) {
5081e2f062eSJoseph Tremoulet         // The state isn't actually changing here.  Record the new end and
5091e2f062eSJoseph Tremoulet         // keep going.
5101e2f062eSJoseph Tremoulet         CurrentEndLabel = StateAndEnd.second;
5111e2f062eSJoseph Tremoulet         continue;
5121e2f062eSJoseph Tremoulet       }
5131e2f062eSJoseph Tremoulet       // Found a state change to report
5141e2f062eSJoseph Tremoulet       LastStateChange.PreviousEndLabel = CurrentEndLabel;
5151e2f062eSJoseph Tremoulet       LastStateChange.NewStartLabel = Label;
5161e2f062eSJoseph Tremoulet       LastStateChange.NewState = NewState;
5171e2f062eSJoseph Tremoulet       // Start keeping track of the new current end
5181e2f062eSJoseph Tremoulet       CurrentEndLabel = StateAndEnd.second;
5191e2f062eSJoseph Tremoulet       // Don't re-visit this instr on the next scan
5201e2f062eSJoseph Tremoulet       ++MBBI;
521fc64fae6SReid Kleckner       return *this;
522fc64fae6SReid Kleckner     }
5231e2f062eSJoseph Tremoulet   }
5241e2f062eSJoseph Tremoulet   // Iteration hit the end of the block range.
5258a1c45d6SDavid Majnemer   if (LastStateChange.NewState != BaseState) {
5261e2f062eSJoseph Tremoulet     // Report the end of the last new state
5271e2f062eSJoseph Tremoulet     LastStateChange.PreviousEndLabel = CurrentEndLabel;
5281e2f062eSJoseph Tremoulet     LastStateChange.NewStartLabel = nullptr;
5298a1c45d6SDavid Majnemer     LastStateChange.NewState = BaseState;
5301e2f062eSJoseph Tremoulet     // Leave CurrentEndLabel non-null to distinguish this state from end.
5311e2f062eSJoseph Tremoulet     assert(CurrentEndLabel != nullptr);
532fc64fae6SReid Kleckner     return *this;
533fc64fae6SReid Kleckner   }
5341e2f062eSJoseph Tremoulet   // We've reported all state changes and hit the end state.
5351e2f062eSJoseph Tremoulet   CurrentEndLabel = nullptr;
5361e2f062eSJoseph Tremoulet   return *this;
537fc64fae6SReid Kleckner }
538fc64fae6SReid Kleckner 
53960b640bbSReid Kleckner /// Emit the language-specific data that __C_specific_handler expects.  This
54060b640bbSReid Kleckner /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
54160b640bbSReid Kleckner /// up after faults with __try, __except, and __finally.  The typeinfo values
54260b640bbSReid Kleckner /// are not really RTTI data, but pointers to filter functions that return an
54360b640bbSReid Kleckner /// integer (1, 0, or -1) indicating how to handle the exception. For __finally
54460b640bbSReid Kleckner /// blocks and other cleanups, the landing pad label is zero, and the filter
54560b640bbSReid Kleckner /// function is actually a cleanup handler with the same prototype.  A catch-all
54660b640bbSReid Kleckner /// entry is modeled with a null filter function field and a non-zero landing
54760b640bbSReid Kleckner /// pad label.
54860b640bbSReid Kleckner ///
54960b640bbSReid Kleckner /// Possible filter function return values:
55060b640bbSReid Kleckner ///   EXCEPTION_EXECUTE_HANDLER (1):
55160b640bbSReid Kleckner ///     Jump to the landing pad label after cleanups.
55260b640bbSReid Kleckner ///   EXCEPTION_CONTINUE_SEARCH (0):
55360b640bbSReid Kleckner ///     Continue searching this table or continue unwinding.
55460b640bbSReid Kleckner ///   EXCEPTION_CONTINUE_EXECUTION (-1):
55560b640bbSReid Kleckner ///     Resume execution at the trapping PC.
55660b640bbSReid Kleckner ///
55760b640bbSReid Kleckner /// Inferred table structure:
55860b640bbSReid Kleckner ///   struct Table {
55960b640bbSReid Kleckner ///     int NumEntries;
56060b640bbSReid Kleckner ///     struct Entry {
5618ecce695SDaniel Paoliello ///       imagerel32 LabelStart;       // Inclusive
5628ecce695SDaniel Paoliello ///       imagerel32 LabelEnd;         // Exclusive
56360b640bbSReid Kleckner ///       imagerel32 FilterOrFinally;  // One means catch-all.
56414e77350SReid Kleckner ///       imagerel32 LabelLPad;        // Zero means __finally.
56560b640bbSReid Kleckner ///     } Entries[NumEntries];
56660b640bbSReid Kleckner ///   };
emitCSpecificHandlerTable(const MachineFunction * MF)56794b704c4SReid Kleckner void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
568fc64fae6SReid Kleckner   auto &OS = *Asm->OutStreamer;
569fc64fae6SReid Kleckner   MCContext &Ctx = Asm->OutContext;
570c20276d0SReid Kleckner   const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
5717850c9f5SReid Kleckner 
572081e8fe4SDavid Majnemer   bool VerboseAsm = OS.isVerboseAsm();
573081e8fe4SDavid Majnemer   auto AddComment = [&](const Twine &Comment) {
574081e8fe4SDavid Majnemer     if (VerboseAsm)
575081e8fe4SDavid Majnemer       OS.AddComment(Comment);
576081e8fe4SDavid Majnemer   };
577081e8fe4SDavid Majnemer 
57833c49c0cSMandeep Singh Grang   if (!isAArch64) {
5797850c9f5SReid Kleckner     // Emit a label assignment with the SEH frame offset so we can use it for
580436735c3SMandeep Singh Grang     // llvm.eh.recoverfp.
5817850c9f5SReid Kleckner     StringRef FLinkageName =
582f1caa283SMatthias Braun         GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
5837850c9f5SReid Kleckner     MCSymbol *ParentFrameOffset =
5847850c9f5SReid Kleckner         Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
5857850c9f5SReid Kleckner     const MCExpr *MCOffset =
5867850c9f5SReid Kleckner         MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);
587a55daa14SFangrui Song     Asm->OutStreamer->emitAssignment(ParentFrameOffset, MCOffset);
58833c49c0cSMandeep Singh Grang   }
5897850c9f5SReid Kleckner 
590fc64fae6SReid Kleckner   // Use the assembler to compute the number of table entries through label
591fc64fae6SReid Kleckner   // difference and division.
592e0129e47SRichard Trieu   MCSymbol *TableBegin =
593e0129e47SRichard Trieu       Ctx.createTempSymbol("lsda_begin", /*AlwaysAddSuffix=*/true);
594e0129e47SRichard Trieu   MCSymbol *TableEnd =
595e0129e47SRichard Trieu       Ctx.createTempSymbol("lsda_end", /*AlwaysAddSuffix=*/true);
59628c89bbbSJoseph Tremoulet   const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin);
597fc64fae6SReid Kleckner   const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);
59814e77350SReid Kleckner   const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);
599081e8fe4SDavid Majnemer   AddComment("Number of call sites");
60077497103SFangrui Song   OS.emitValue(EntryCount, 4);
601fc64fae6SReid Kleckner 
6026d2d589bSFangrui Song   OS.emitLabel(TableBegin);
603fc64fae6SReid Kleckner 
604fc64fae6SReid Kleckner   // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only
605fc64fae6SReid Kleckner   // models exceptions from invokes. LLVM also allows arbitrary reordering of
606fc64fae6SReid Kleckner   // the code, so our tables end up looking a bit different. Rather than
607fc64fae6SReid Kleckner   // trying to match MSVC's tables exactly, we emit a denormalized table.  For
608fc64fae6SReid Kleckner   // each range of invokes in the same state, we emit table entries for all
609fc64fae6SReid Kleckner   // the actions that would be taken in that state. This means our tables are
610fc64fae6SReid Kleckner   // slightly bigger, which is OK.
6111e2f062eSJoseph Tremoulet   const MCSymbol *LastStartLabel = nullptr;
6121e2f062eSJoseph Tremoulet   int LastEHState = -1;
613eb7cd6c8SReid Kleckner   // Break out before we enter into a finally funclet.
614eb7cd6c8SReid Kleckner   // FIXME: We need to emit separate EH tables for cleanups.
6151e2f062eSJoseph Tremoulet   MachineFunction::const_iterator End = MF->end();
6161e2f062eSJoseph Tremoulet   MachineFunction::const_iterator Stop = std::next(MF->begin());
6171e2f062eSJoseph Tremoulet   while (Stop != End && !Stop->isEHFuncletEntry())
6181e2f062eSJoseph Tremoulet     ++Stop;
6191e2f062eSJoseph Tremoulet   for (const auto &StateChange :
6201e2f062eSJoseph Tremoulet        InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) {
6211e2f062eSJoseph Tremoulet     // Emit all the actions for the state we just transitioned out of
6221e2f062eSJoseph Tremoulet     // if it was not the null state
623d880dc75SReid Kleckner     if (LastEHState != -1)
6241e2f062eSJoseph Tremoulet       emitSEHActionsForRange(FuncInfo, LastStartLabel,
6251e2f062eSJoseph Tremoulet                              StateChange.PreviousEndLabel, LastEHState);
6261e2f062eSJoseph Tremoulet     LastStartLabel = StateChange.NewStartLabel;
6271e2f062eSJoseph Tremoulet     LastEHState = StateChange.NewState;
628fc64fae6SReid Kleckner   }
629d880dc75SReid Kleckner 
6306d2d589bSFangrui Song   OS.emitLabel(TableEnd);
63160b640bbSReid Kleckner }
63260b640bbSReid Kleckner 
emitSEHActionsForRange(const WinEHFuncInfo & FuncInfo,const MCSymbol * BeginLabel,const MCSymbol * EndLabel,int State)633c20276d0SReid Kleckner void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,
6341e2f062eSJoseph Tremoulet                                           const MCSymbol *BeginLabel,
6351e2f062eSJoseph Tremoulet                                           const MCSymbol *EndLabel, int State) {
636d880dc75SReid Kleckner   auto &OS = *Asm->OutStreamer;
637d880dc75SReid Kleckner   MCContext &Ctx = Asm->OutContext;
638081e8fe4SDavid Majnemer   bool VerboseAsm = OS.isVerboseAsm();
639081e8fe4SDavid Majnemer   auto AddComment = [&](const Twine &Comment) {
640081e8fe4SDavid Majnemer     if (VerboseAsm)
641081e8fe4SDavid Majnemer       OS.AddComment(Comment);
642081e8fe4SDavid Majnemer   };
643081e8fe4SDavid Majnemer 
644d880dc75SReid Kleckner   assert(BeginLabel && EndLabel);
645d880dc75SReid Kleckner   while (State != -1) {
646c20276d0SReid Kleckner     const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
647d880dc75SReid Kleckner     const MCExpr *FilterOrFinally;
648d880dc75SReid Kleckner     const MCExpr *ExceptOrNull;
649d880dc75SReid Kleckner     auto *Handler = UME.Handler.get<MachineBasicBlock *>();
650d880dc75SReid Kleckner     if (UME.IsFinally) {
651bfa5b982SDavid Majnemer       FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler));
652d880dc75SReid Kleckner       ExceptOrNull = MCConstantExpr::create(0, Ctx);
653d880dc75SReid Kleckner     } else {
654d880dc75SReid Kleckner       // For an except, the filter can be 1 (catch-all) or a function
655d880dc75SReid Kleckner       // label.
656d880dc75SReid Kleckner       FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
657d880dc75SReid Kleckner                                    : MCConstantExpr::create(1, Ctx);
658d880dc75SReid Kleckner       ExceptOrNull = create32bitRef(Handler->getSymbol());
659d880dc75SReid Kleckner     }
660d880dc75SReid Kleckner 
661081e8fe4SDavid Majnemer     AddComment("LabelStart");
66277497103SFangrui Song     OS.emitValue(getLabel(BeginLabel), 4);
663081e8fe4SDavid Majnemer     AddComment("LabelEnd");
6648ecce695SDaniel Paoliello     OS.emitValue(getLabelPlusOne(EndLabel), 4);
665081e8fe4SDavid Majnemer     AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction"
666081e8fe4SDavid Majnemer                                                              : "CatchAll");
66777497103SFangrui Song     OS.emitValue(FilterOrFinally, 4);
668081e8fe4SDavid Majnemer     AddComment(UME.IsFinally ? "Null" : "ExceptionHandler");
66977497103SFangrui Song     OS.emitValue(ExceptOrNull, 4);
670d880dc75SReid Kleckner 
671d880dc75SReid Kleckner     assert(UME.ToState < State && "states should decrease");
672d880dc75SReid Kleckner     State = UME.ToState;
673d880dc75SReid Kleckner   }
674d880dc75SReid Kleckner }
675d880dc75SReid Kleckner 
emitCXXFrameHandler3Table(const MachineFunction * MF)67660b640bbSReid Kleckner void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
677f1caa283SMatthias Braun   const Function &F = MF->getFunction();
67860b640bbSReid Kleckner   auto &OS = *Asm->OutStreamer;
679c20276d0SReid Kleckner   const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
68060b640bbSReid Kleckner 
681f1caa283SMatthias Braun   StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
68260b640bbSReid Kleckner 
683c71d6275SReid Kleckner   SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable;
6841d3d4adbSReid Kleckner   MCSymbol *FuncInfoXData = nullptr;
6851d3d4adbSReid Kleckner   if (shouldEmitPersonality) {
686c71d6275SReid Kleckner     // If we're 64-bit, emit a pointer to the C++ EH data, and build a map from
687c71d6275SReid Kleckner     // IPs to state numbers.
688813f1b65SReid Kleckner     FuncInfoXData =
689813f1b65SReid Kleckner         Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));
690c71d6275SReid Kleckner     computeIP2StateTable(MF, FuncInfo, IPToStateTable);
6911d3d4adbSReid Kleckner   } else {
692813f1b65SReid Kleckner     FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);
6931d3d4adbSReid Kleckner   }
6941d3d4adbSReid Kleckner 
69570bf6bb5SReid Kleckner   int UnwindHelpOffset = 0;
6966b75a352SMartin Storsjö   // TODO: The check for UnwindHelpFrameIdx against max() below (and the
6976b75a352SMartin Storsjö   // second check further below) can be removed if MS C++ unwinding is
6986b75a352SMartin Storsjö   // implemented for ARM, when test/CodeGen/ARM/Windows/wineh-basic.ll
6996b75a352SMartin Storsjö   // passes without the check.
7006b75a352SMartin Storsjö   if (Asm->MAI->usesWindowsCFI() &&
7016b75a352SMartin Storsjö       FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max())
7026ddae310SReid Kleckner     UnwindHelpOffset =
7036ddae310SReid Kleckner         getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo);
70470bf6bb5SReid Kleckner 
7051d3d4adbSReid Kleckner   MCSymbol *UnwindMapXData = nullptr;
7061d3d4adbSReid Kleckner   MCSymbol *TryBlockMapXData = nullptr;
7071d3d4adbSReid Kleckner   MCSymbol *IPToStateXData = nullptr;
70814e77350SReid Kleckner   if (!FuncInfo.CxxUnwindMap.empty())
7091d3d4adbSReid Kleckner     UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
710813f1b65SReid Kleckner         Twine("$stateUnwindMap$", FuncLinkageName));
7111d3d4adbSReid Kleckner   if (!FuncInfo.TryBlockMap.empty())
712813f1b65SReid Kleckner     TryBlockMapXData =
713813f1b65SReid Kleckner         Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName));
714c71d6275SReid Kleckner   if (!IPToStateTable.empty())
715813f1b65SReid Kleckner     IPToStateXData =
716813f1b65SReid Kleckner         Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName));
7171d3d4adbSReid Kleckner 
718081e8fe4SDavid Majnemer   bool VerboseAsm = OS.isVerboseAsm();
719081e8fe4SDavid Majnemer   auto AddComment = [&](const Twine &Comment) {
720081e8fe4SDavid Majnemer     if (VerboseAsm)
721081e8fe4SDavid Majnemer       OS.AddComment(Comment);
722081e8fe4SDavid Majnemer   };
723081e8fe4SDavid Majnemer 
7241d3d4adbSReid Kleckner   // FuncInfo {
7251d3d4adbSReid Kleckner   //   uint32_t           MagicNumber
7261d3d4adbSReid Kleckner   //   int32_t            MaxState;
7271d3d4adbSReid Kleckner   //   UnwindMapEntry    *UnwindMap;
7281d3d4adbSReid Kleckner   //   uint32_t           NumTryBlocks;
7291d3d4adbSReid Kleckner   //   TryBlockMapEntry  *TryBlockMap;
7301d3d4adbSReid Kleckner   //   uint32_t           IPMapEntries; // always 0 for x86
7311d3d4adbSReid Kleckner   //   IPToStateMapEntry *IPToStateMap; // always 0 for x86
7321d3d4adbSReid Kleckner   //   uint32_t           UnwindHelp;   // non-x86 only
7331d3d4adbSReid Kleckner   //   ESTypeList        *ESTypeList;
7341d3d4adbSReid Kleckner   //   int32_t            EHFlags;
7351d3d4adbSReid Kleckner   // }
7361d3d4adbSReid Kleckner   // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
7371d3d4adbSReid Kleckner   // EHFlags & 2 -> ???
7381d3d4adbSReid Kleckner   // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
7396d2d589bSFangrui Song   OS.emitValueToAlignment(4);
7406d2d589bSFangrui Song   OS.emitLabel(FuncInfoXData);
741081e8fe4SDavid Majnemer 
742081e8fe4SDavid Majnemer   AddComment("MagicNumber");
743692e0c96SFangrui Song   OS.emitInt32(0x19930522);
744081e8fe4SDavid Majnemer 
745081e8fe4SDavid Majnemer   AddComment("MaxState");
746692e0c96SFangrui Song   OS.emitInt32(FuncInfo.CxxUnwindMap.size());
747081e8fe4SDavid Majnemer 
748081e8fe4SDavid Majnemer   AddComment("UnwindMap");
74977497103SFangrui Song   OS.emitValue(create32bitRef(UnwindMapXData), 4);
750081e8fe4SDavid Majnemer 
751081e8fe4SDavid Majnemer   AddComment("NumTryBlocks");
752692e0c96SFangrui Song   OS.emitInt32(FuncInfo.TryBlockMap.size());
753081e8fe4SDavid Majnemer 
754081e8fe4SDavid Majnemer   AddComment("TryBlockMap");
75577497103SFangrui Song   OS.emitValue(create32bitRef(TryBlockMapXData), 4);
756081e8fe4SDavid Majnemer 
757081e8fe4SDavid Majnemer   AddComment("IPMapEntries");
758692e0c96SFangrui Song   OS.emitInt32(IPToStateTable.size());
759081e8fe4SDavid Majnemer 
760081e8fe4SDavid Majnemer   AddComment("IPToStateXData");
76177497103SFangrui Song   OS.emitValue(create32bitRef(IPToStateXData), 4);
762081e8fe4SDavid Majnemer 
7636b75a352SMartin Storsjö   if (Asm->MAI->usesWindowsCFI() &&
7646b75a352SMartin Storsjö       FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max()) {
765081e8fe4SDavid Majnemer     AddComment("UnwindHelp");
766692e0c96SFangrui Song     OS.emitInt32(UnwindHelpOffset);
767081e8fe4SDavid Majnemer   }
768081e8fe4SDavid Majnemer 
769081e8fe4SDavid Majnemer   AddComment("ESTypeList");
770692e0c96SFangrui Song   OS.emitInt32(0);
771081e8fe4SDavid Majnemer 
772081e8fe4SDavid Majnemer   AddComment("EHFlags");
773692e0c96SFangrui Song   OS.emitInt32(1);
7741d3d4adbSReid Kleckner 
7751d3d4adbSReid Kleckner   // UnwindMapEntry {
7761d3d4adbSReid Kleckner   //   int32_t ToState;
7771d3d4adbSReid Kleckner   //   void  (*Action)();
7781d3d4adbSReid Kleckner   // };
7791d3d4adbSReid Kleckner   if (UnwindMapXData) {
7806d2d589bSFangrui Song     OS.emitLabel(UnwindMapXData);
78114e77350SReid Kleckner     for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) {
782bfa5b982SDavid Majnemer       MCSymbol *CleanupSym =
783bfa5b982SDavid Majnemer           getMCSymbolForMBB(Asm, UME.Cleanup.dyn_cast<MachineBasicBlock *>());
784081e8fe4SDavid Majnemer       AddComment("ToState");
785692e0c96SFangrui Song       OS.emitInt32(UME.ToState);
786081e8fe4SDavid Majnemer 
787081e8fe4SDavid Majnemer       AddComment("Action");
78877497103SFangrui Song       OS.emitValue(create32bitRef(CleanupSym), 4);
7891d3d4adbSReid Kleckner     }
7901d3d4adbSReid Kleckner   }
7911d3d4adbSReid Kleckner 
7921d3d4adbSReid Kleckner   // TryBlockMap {
7931d3d4adbSReid Kleckner   //   int32_t      TryLow;
7941d3d4adbSReid Kleckner   //   int32_t      TryHigh;
7951d3d4adbSReid Kleckner   //   int32_t      CatchHigh;
7961d3d4adbSReid Kleckner   //   int32_t      NumCatches;
7971d3d4adbSReid Kleckner   //   HandlerType *HandlerArray;
7981d3d4adbSReid Kleckner   // };
7991d3d4adbSReid Kleckner   if (TryBlockMapXData) {
8006d2d589bSFangrui Song     OS.emitLabel(TryBlockMapXData);
8011d3d4adbSReid Kleckner     SmallVector<MCSymbol *, 1> HandlerMaps;
8021d3d4adbSReid Kleckner     for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
803c20276d0SReid Kleckner       const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
8041d3d4adbSReid Kleckner 
805813f1b65SReid Kleckner       MCSymbol *HandlerMapXData = nullptr;
8061d3d4adbSReid Kleckner       if (!TBME.HandlerArray.empty())
8071d3d4adbSReid Kleckner         HandlerMapXData =
8081d3d4adbSReid Kleckner             Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
8091d3d4adbSReid Kleckner                                                   .concat(Twine(I))
8101d3d4adbSReid Kleckner                                                   .concat("$")
811813f1b65SReid Kleckner                                                   .concat(FuncLinkageName));
8121d3d4adbSReid Kleckner       HandlerMaps.push_back(HandlerMapXData);
8131d3d4adbSReid Kleckner 
814813f1b65SReid Kleckner       // TBMEs should form intervals.
815813f1b65SReid Kleckner       assert(0 <= TBME.TryLow && "bad trymap interval");
816813f1b65SReid Kleckner       assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");
817813f1b65SReid Kleckner       assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");
81814e77350SReid Kleckner       assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) &&
819813f1b65SReid Kleckner              "bad trymap interval");
8201d3d4adbSReid Kleckner 
821081e8fe4SDavid Majnemer       AddComment("TryLow");
822692e0c96SFangrui Song       OS.emitInt32(TBME.TryLow);
823081e8fe4SDavid Majnemer 
824081e8fe4SDavid Majnemer       AddComment("TryHigh");
825692e0c96SFangrui Song       OS.emitInt32(TBME.TryHigh);
826081e8fe4SDavid Majnemer 
827081e8fe4SDavid Majnemer       AddComment("CatchHigh");
828692e0c96SFangrui Song       OS.emitInt32(TBME.CatchHigh);
829081e8fe4SDavid Majnemer 
830081e8fe4SDavid Majnemer       AddComment("NumCatches");
831692e0c96SFangrui Song       OS.emitInt32(TBME.HandlerArray.size());
832081e8fe4SDavid Majnemer 
833081e8fe4SDavid Majnemer       AddComment("HandlerArray");
83477497103SFangrui Song       OS.emitValue(create32bitRef(HandlerMapXData), 4);
8351d3d4adbSReid Kleckner     }
8361d3d4adbSReid Kleckner 
83728e49034SReid Kleckner     // All funclets use the same parent frame offset currently.
83828e49034SReid Kleckner     unsigned ParentFrameOffset = 0;
83928e49034SReid Kleckner     if (shouldEmitPersonality) {
84028e49034SReid Kleckner       const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
84128e49034SReid Kleckner       ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF);
84228e49034SReid Kleckner     }
84328e49034SReid Kleckner 
8441d3d4adbSReid Kleckner     for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
845c20276d0SReid Kleckner       const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
8461d3d4adbSReid Kleckner       MCSymbol *HandlerMapXData = HandlerMaps[I];
8471d3d4adbSReid Kleckner       if (!HandlerMapXData)
8481d3d4adbSReid Kleckner         continue;
8491d3d4adbSReid Kleckner       // HandlerType {
8501d3d4adbSReid Kleckner       //   int32_t         Adjectives;
8511d3d4adbSReid Kleckner       //   TypeDescriptor *Type;
8521d3d4adbSReid Kleckner       //   int32_t         CatchObjOffset;
8531d3d4adbSReid Kleckner       //   void          (*Handler)();
85496f2ea3dSSanjin Sijaric       //   int32_t         ParentFrameOffset; // x64 and AArch64 only
8551d3d4adbSReid Kleckner       // };
8566d2d589bSFangrui Song       OS.emitLabel(HandlerMapXData);
8571d3d4adbSReid Kleckner       for (const WinEHHandlerType &HT : TBME.HandlerArray) {
8581d3d4adbSReid Kleckner         // Get the frame escape label with the offset of the catch object. If
85999c1d13eSDavid Majnemer         // the index is INT_MAX, then there is no catch object, and we should
86099c1d13eSDavid Majnemer         // emit an offset of zero, indicating that no copy will occur.
8611d3d4adbSReid Kleckner         const MCExpr *FrameAllocOffsetRef = nullptr;
86299c1d13eSDavid Majnemer         if (HT.CatchObj.FrameIndex != INT_MAX) {
8636ddae310SReid Kleckner           int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo);
864cb305deaSDavid Majnemer           assert(Offset != 0 && "Illegal offset for catch object!");
865b005d281SReid Kleckner           FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext);
8661d3d4adbSReid Kleckner         } else {
86713760bd1SJim Grosbach           FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
8681d3d4adbSReid Kleckner         }
8691d3d4adbSReid Kleckner 
870bfa5b982SDavid Majnemer         MCSymbol *HandlerSym =
871bfa5b982SDavid Majnemer             getMCSymbolForMBB(Asm, HT.Handler.dyn_cast<MachineBasicBlock *>());
87294b704c4SReid Kleckner 
873081e8fe4SDavid Majnemer         AddComment("Adjectives");
874692e0c96SFangrui Song         OS.emitInt32(HT.Adjectives);
875081e8fe4SDavid Majnemer 
876081e8fe4SDavid Majnemer         AddComment("Type");
87777497103SFangrui Song         OS.emitValue(create32bitRef(HT.TypeDescriptor), 4);
878081e8fe4SDavid Majnemer 
879081e8fe4SDavid Majnemer         AddComment("CatchObjOffset");
88077497103SFangrui Song         OS.emitValue(FrameAllocOffsetRef, 4);
881081e8fe4SDavid Majnemer 
882081e8fe4SDavid Majnemer         AddComment("Handler");
88377497103SFangrui Song         OS.emitValue(create32bitRef(HandlerSym), 4);
884081e8fe4SDavid Majnemer 
885081e8fe4SDavid Majnemer         if (shouldEmitPersonality) {
886081e8fe4SDavid Majnemer           AddComment("ParentFrameOffset");
887692e0c96SFangrui Song           OS.emitInt32(ParentFrameOffset);
888081e8fe4SDavid Majnemer         }
8891d3d4adbSReid Kleckner       }
8901d3d4adbSReid Kleckner     }
8911d3d4adbSReid Kleckner   }
8921d3d4adbSReid Kleckner 
8931d3d4adbSReid Kleckner   // IPToStateMapEntry {
8941d3d4adbSReid Kleckner   //   void   *IP;
8951d3d4adbSReid Kleckner   //   int32_t State;
8961d3d4adbSReid Kleckner   // };
8971d3d4adbSReid Kleckner   if (IPToStateXData) {
8986d2d589bSFangrui Song     OS.emitLabel(IPToStateXData);
899c71d6275SReid Kleckner     for (auto &IPStatePair : IPToStateTable) {
900081e8fe4SDavid Majnemer       AddComment("IP");
90177497103SFangrui Song       OS.emitValue(IPStatePair.first, 4);
902081e8fe4SDavid Majnemer       AddComment("ToState");
903692e0c96SFangrui Song       OS.emitInt32(IPStatePair.second);
9041d3d4adbSReid Kleckner     }
9051d3d4adbSReid Kleckner   }
9061d3d4adbSReid Kleckner }
9071d3d4adbSReid Kleckner 
computeIP2StateTable(const MachineFunction * MF,const WinEHFuncInfo & FuncInfo,SmallVectorImpl<std::pair<const MCExpr *,int>> & IPToStateTable)908c71d6275SReid Kleckner void WinException::computeIP2StateTable(
909c20276d0SReid Kleckner     const MachineFunction *MF, const WinEHFuncInfo &FuncInfo,
910c71d6275SReid Kleckner     SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {
91160b640bbSReid Kleckner 
9128a1c45d6SDavid Majnemer   for (MachineFunction::const_iterator FuncletStart = MF->begin(),
9138a1c45d6SDavid Majnemer                                        FuncletEnd = MF->begin(),
9148a1c45d6SDavid Majnemer                                        End = MF->end();
9158a1c45d6SDavid Majnemer        FuncletStart != End; FuncletStart = FuncletEnd) {
9168a1c45d6SDavid Majnemer     // Find the end of the funclet
9178a1c45d6SDavid Majnemer     while (++FuncletEnd != End) {
9188a1c45d6SDavid Majnemer       if (FuncletEnd->isEHFuncletEntry()) {
9198a1c45d6SDavid Majnemer         break;
9208a1c45d6SDavid Majnemer       }
9218a1c45d6SDavid Majnemer     }
9228a1c45d6SDavid Majnemer 
9238a1c45d6SDavid Majnemer     // Don't emit ip2state entries for cleanup funclets. Any interesting
9248a1c45d6SDavid Majnemer     // exceptional actions in cleanups must be handled in a separate IR
9258a1c45d6SDavid Majnemer     // function.
9268a1c45d6SDavid Majnemer     if (FuncletStart->isCleanupFuncletEntry())
9278a1c45d6SDavid Majnemer       continue;
9288a1c45d6SDavid Majnemer 
9298a1c45d6SDavid Majnemer     MCSymbol *StartLabel;
9308a1c45d6SDavid Majnemer     int BaseState;
9318a1c45d6SDavid Majnemer     if (FuncletStart == MF->begin()) {
9328a1c45d6SDavid Majnemer       BaseState = NullState;
9338a1c45d6SDavid Majnemer       StartLabel = Asm->getFunctionBegin();
9348a1c45d6SDavid Majnemer     } else {
9358a1c45d6SDavid Majnemer       auto *FuncletPad =
9368a1c45d6SDavid Majnemer           cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI());
9378a1c45d6SDavid Majnemer       assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0);
9388a1c45d6SDavid Majnemer       BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second;
9398a1c45d6SDavid Majnemer       StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart);
9408a1c45d6SDavid Majnemer     }
9418a1c45d6SDavid Majnemer     assert(StartLabel && "need local function start label");
9428a1c45d6SDavid Majnemer     IPToStateTable.push_back(
9438a1c45d6SDavid Majnemer         std::make_pair(create32bitRef(StartLabel), BaseState));
9448a1c45d6SDavid Majnemer 
9458a1c45d6SDavid Majnemer     for (const auto &StateChange : InvokeStateChangeIterator::range(
9468a1c45d6SDavid Majnemer              FuncInfo, FuncletStart, FuncletEnd, BaseState)) {
9478a1c45d6SDavid Majnemer       // Compute the label to report as the start of this entry; use the EH
9488a1c45d6SDavid Majnemer       // start label for the invoke if we have one, otherwise (this is a call
9498a1c45d6SDavid Majnemer       // which may unwind to our caller and does not have an EH start label, so)
9508a1c45d6SDavid Majnemer       // use the previous end label.
9511e2f062eSJoseph Tremoulet       const MCSymbol *ChangeLabel = StateChange.NewStartLabel;
9521e2f062eSJoseph Tremoulet       if (!ChangeLabel)
9531e2f062eSJoseph Tremoulet         ChangeLabel = StateChange.PreviousEndLabel;
954c71d6275SReid Kleckner       // Emit an entry indicating that PCs after 'Label' have this EH state.
9558ecce695SDaniel Paoliello       // NOTE: On ARM architectures, the StateFromIp automatically takes into
9568ecce695SDaniel Paoliello       // account that the return address is after the call instruction (whose EH
9578ecce695SDaniel Paoliello       // state we should be using), but on other platforms we need to +1 to the
9588ecce695SDaniel Paoliello       // label so that we are using the correct EH state.
9598ecce695SDaniel Paoliello       const MCExpr *LabelExpression = (isAArch64 || isThumb)
9608ecce695SDaniel Paoliello                                           ? getLabel(ChangeLabel)
9618ecce695SDaniel Paoliello                                           : getLabelPlusOne(ChangeLabel);
962fc64fae6SReid Kleckner       IPToStateTable.push_back(
9638ecce695SDaniel Paoliello           std::make_pair(LabelExpression, StateChange.NewState));
9648a1c45d6SDavid Majnemer       // FIXME: assert that NewState is between CatchLow and CatchHigh.
9658a1c45d6SDavid Majnemer     }
966c71d6275SReid Kleckner   }
96760b640bbSReid Kleckner }
968f12c030fSReid Kleckner 
emitEHRegistrationOffsetLabel(const WinEHFuncInfo & FuncInfo,StringRef FLinkageName)969399a2fe4SReid Kleckner void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
970399a2fe4SReid Kleckner                                                  StringRef FLinkageName) {
971399a2fe4SReid Kleckner   // Outlined helpers called by the EH runtime need to know the offset of the EH
972399a2fe4SReid Kleckner   // registration in order to recover the parent frame pointer. Now that we know
973399a2fe4SReid Kleckner   // we've code generated the parent, we can emit the label assignment that
974399a2fe4SReid Kleckner   // those helpers use to get the offset of the registration node.
9759cb915b7SReid Kleckner 
9769cb915b7SReid Kleckner   // Compute the parent frame offset. The EHRegNodeFrameIndex will be invalid if
9779cb915b7SReid Kleckner   // after optimization all the invokes were eliminated. We still need to emit
9789cb915b7SReid Kleckner   // the parent frame offset label, but it should be garbage and should never be
9799cb915b7SReid Kleckner   // used.
9809cb915b7SReid Kleckner   int64_t Offset = 0;
9819cb915b7SReid Kleckner   int FI = FuncInfo.EHRegNodeFrameIndex;
9829cb915b7SReid Kleckner   if (FI != INT_MAX) {
9839cb915b7SReid Kleckner     const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
984d57bba7cSSander de Smalen     Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed();
9859cb915b7SReid Kleckner   }
9869cb915b7SReid Kleckner 
987c20276d0SReid Kleckner   MCContext &Ctx = Asm->OutContext;
988399a2fe4SReid Kleckner   MCSymbol *ParentFrameOffset =
989c20276d0SReid Kleckner       Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
990a55daa14SFangrui Song   Asm->OutStreamer->emitAssignment(ParentFrameOffset,
9919cb915b7SReid Kleckner                                    MCConstantExpr::create(Offset, Ctx));
992399a2fe4SReid Kleckner }
993399a2fe4SReid Kleckner 
994f12c030fSReid Kleckner /// Emit the language-specific data that _except_handler3 and 4 expect. This is
995f12c030fSReid Kleckner /// functionally equivalent to the __C_specific_handler table, except it is
996f12c030fSReid Kleckner /// indexed by state number instead of IP.
emitExceptHandlerTable(const MachineFunction * MF)997f12c030fSReid Kleckner void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
998a9d62535SReid Kleckner   MCStreamer &OS = *Asm->OutStreamer;
999f1caa283SMatthias Braun   const Function &F = MF->getFunction();
1000f1caa283SMatthias Braun   StringRef FLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
1001399a2fe4SReid Kleckner 
1002081e8fe4SDavid Majnemer   bool VerboseAsm = OS.isVerboseAsm();
1003081e8fe4SDavid Majnemer   auto AddComment = [&](const Twine &Comment) {
1004081e8fe4SDavid Majnemer     if (VerboseAsm)
1005081e8fe4SDavid Majnemer       OS.AddComment(Comment);
1006081e8fe4SDavid Majnemer   };
1007081e8fe4SDavid Majnemer 
1008c20276d0SReid Kleckner   const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
1009399a2fe4SReid Kleckner   emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
1010f12c030fSReid Kleckner 
1011f12c030fSReid Kleckner   // Emit the __ehtable label that we use for llvm.x86.seh.lsda.
1012f12c030fSReid Kleckner   MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
10136d2d589bSFangrui Song   OS.emitValueToAlignment(4);
10146d2d589bSFangrui Song   OS.emitLabel(LSDALabel);
1015f12c030fSReid Kleckner 
1016c9129ceaSSimon Pilgrim   const auto *Per = cast<Function>(F.getPersonalityFn()->stripPointerCasts());
1017f12c030fSReid Kleckner   StringRef PerName = Per->getName();
1018f12c030fSReid Kleckner   int BaseState = -1;
1019f12c030fSReid Kleckner   if (PerName == "_except_handler4") {
1020f12c030fSReid Kleckner     // The LSDA for _except_handler4 starts with this struct, followed by the
1021f12c030fSReid Kleckner     // scope table:
1022f12c030fSReid Kleckner     //
1023f12c030fSReid Kleckner     // struct EH4ScopeTable {
1024f12c030fSReid Kleckner     //   int32_t GSCookieOffset;
1025f12c030fSReid Kleckner     //   int32_t GSCookieXOROffset;
1026f12c030fSReid Kleckner     //   int32_t EHCookieOffset;
1027f12c030fSReid Kleckner     //   int32_t EHCookieXOROffset;
1028f12c030fSReid Kleckner     //   ScopeTableEntry ScopeRecord[];
1029f12c030fSReid Kleckner     // };
1030f12c030fSReid Kleckner     //
1031f6be62f2SEtienne Bergeron     // Offsets are %ebp relative.
1032f6be62f2SEtienne Bergeron     //
1033f6be62f2SEtienne Bergeron     // The GS cookie is present only if the function needs stack protection.
1034f6be62f2SEtienne Bergeron     // GSCookieOffset = -2 means that GS cookie is not used.
1035f6be62f2SEtienne Bergeron     //
1036f6be62f2SEtienne Bergeron     // The EH cookie is always present.
1037f6be62f2SEtienne Bergeron     //
1038f6be62f2SEtienne Bergeron     // Check is done the following way:
1039f6be62f2SEtienne Bergeron     //    (ebp+CookieXOROffset) ^ [ebp+CookieOffset] == _security_cookie
1040f6be62f2SEtienne Bergeron 
1041f6be62f2SEtienne Bergeron     // Retrieve the Guard Stack slot.
1042f6be62f2SEtienne Bergeron     int GSCookieOffset = -2;
1043941a705bSMatthias Braun     const MachineFrameInfo &MFI = MF->getFrameInfo();
1044941a705bSMatthias Braun     if (MFI.hasStackProtectorIndex()) {
10452481f26aSMatt Arsenault       Register UnusedReg;
1046f6be62f2SEtienne Bergeron       const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
1047941a705bSMatthias Braun       int SSPIdx = MFI.getStackProtectorIndex();
1048d57bba7cSSander de Smalen       GSCookieOffset =
1049d57bba7cSSander de Smalen           TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed();
1050f6be62f2SEtienne Bergeron     }
1051f6be62f2SEtienne Bergeron 
1052f6be62f2SEtienne Bergeron     // Retrieve the EH Guard slot.
1053f6be62f2SEtienne Bergeron     // TODO(etienneb): Get rid of this value and change it for and assertion.
1054f6be62f2SEtienne Bergeron     int EHCookieOffset = 9999;
1055f6be62f2SEtienne Bergeron     if (FuncInfo.EHGuardFrameIndex != INT_MAX) {
10562481f26aSMatt Arsenault       Register UnusedReg;
1057f6be62f2SEtienne Bergeron       const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
1058f6be62f2SEtienne Bergeron       int EHGuardIdx = FuncInfo.EHGuardFrameIndex;
1059d57bba7cSSander de Smalen       EHCookieOffset =
1060d57bba7cSSander de Smalen           TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed();
1061f6be62f2SEtienne Bergeron     }
1062f6be62f2SEtienne Bergeron 
1063081e8fe4SDavid Majnemer     AddComment("GSCookieOffset");
1064692e0c96SFangrui Song     OS.emitInt32(GSCookieOffset);
1065081e8fe4SDavid Majnemer     AddComment("GSCookieXOROffset");
1066692e0c96SFangrui Song     OS.emitInt32(0);
1067081e8fe4SDavid Majnemer     AddComment("EHCookieOffset");
1068692e0c96SFangrui Song     OS.emitInt32(EHCookieOffset);
1069081e8fe4SDavid Majnemer     AddComment("EHCookieXOROffset");
1070692e0c96SFangrui Song     OS.emitInt32(0);
1071f12c030fSReid Kleckner     BaseState = -2;
1072f12c030fSReid Kleckner   }
1073f12c030fSReid Kleckner 
107414e77350SReid Kleckner   assert(!FuncInfo.SEHUnwindMap.empty());
1075c20276d0SReid Kleckner   for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
1076081e8fe4SDavid Majnemer     auto *Handler = UME.Handler.get<MachineBasicBlock *>();
1077081e8fe4SDavid Majnemer     const MCSymbol *ExceptOrFinally =
1078081e8fe4SDavid Majnemer         UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol();
1079e1c8a7f9SReid Kleckner     // -1 is usually the base state for "unwind to caller", but for
1080e1c8a7f9SReid Kleckner     // _except_handler4 it's -2. Do that replacement here if necessary.
1081e1c8a7f9SReid Kleckner     int ToState = UME.ToState == -1 ? BaseState : UME.ToState;
1082081e8fe4SDavid Majnemer     AddComment("ToState");
1083692e0c96SFangrui Song     OS.emitInt32(ToState);
1084081e8fe4SDavid Majnemer     AddComment(UME.IsFinally ? "Null" : "FilterFunction");
108577497103SFangrui Song     OS.emitValue(create32bitRef(UME.Filter), 4);
1086081e8fe4SDavid Majnemer     AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler");
108777497103SFangrui Song     OS.emitValue(create32bitRef(ExceptOrFinally), 4);
108894b704c4SReid Kleckner   }
1089f12c030fSReid Kleckner }
109028c89bbbSJoseph Tremoulet 
getTryRank(const WinEHFuncInfo & FuncInfo,int State)109152f729a6SJoseph Tremoulet static int getTryRank(const WinEHFuncInfo &FuncInfo, int State) {
109228c89bbbSJoseph Tremoulet   int Rank = 0;
109328c89bbbSJoseph Tremoulet   while (State != -1) {
109428c89bbbSJoseph Tremoulet     ++Rank;
109552f729a6SJoseph Tremoulet     State = FuncInfo.ClrEHUnwindMap[State].TryParentState;
109628c89bbbSJoseph Tremoulet   }
109728c89bbbSJoseph Tremoulet   return Rank;
109828c89bbbSJoseph Tremoulet }
109928c89bbbSJoseph Tremoulet 
getTryAncestor(const WinEHFuncInfo & FuncInfo,int Left,int Right)110052f729a6SJoseph Tremoulet static int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) {
110152f729a6SJoseph Tremoulet   int LeftRank = getTryRank(FuncInfo, Left);
110252f729a6SJoseph Tremoulet   int RightRank = getTryRank(FuncInfo, Right);
110328c89bbbSJoseph Tremoulet 
110428c89bbbSJoseph Tremoulet   while (LeftRank < RightRank) {
110552f729a6SJoseph Tremoulet     Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;
110628c89bbbSJoseph Tremoulet     --RightRank;
110728c89bbbSJoseph Tremoulet   }
110828c89bbbSJoseph Tremoulet 
110928c89bbbSJoseph Tremoulet   while (RightRank < LeftRank) {
111052f729a6SJoseph Tremoulet     Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;
111128c89bbbSJoseph Tremoulet     --LeftRank;
111228c89bbbSJoseph Tremoulet   }
111328c89bbbSJoseph Tremoulet 
111428c89bbbSJoseph Tremoulet   while (Left != Right) {
111552f729a6SJoseph Tremoulet     Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;
111652f729a6SJoseph Tremoulet     Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;
111728c89bbbSJoseph Tremoulet   }
111828c89bbbSJoseph Tremoulet 
111928c89bbbSJoseph Tremoulet   return Left;
112028c89bbbSJoseph Tremoulet }
112128c89bbbSJoseph Tremoulet 
emitCLRExceptionTable(const MachineFunction * MF)112228c89bbbSJoseph Tremoulet void WinException::emitCLRExceptionTable(const MachineFunction *MF) {
112328c89bbbSJoseph Tremoulet   // CLR EH "states" are really just IDs that identify handlers/funclets;
112428c89bbbSJoseph Tremoulet   // states, handlers, and funclets all have 1:1 mappings between them, and a
112528c89bbbSJoseph Tremoulet   // handler/funclet's "state" is its index in the ClrEHUnwindMap.
112628c89bbbSJoseph Tremoulet   MCStreamer &OS = *Asm->OutStreamer;
1127c20276d0SReid Kleckner   const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
112828c89bbbSJoseph Tremoulet   MCSymbol *FuncBeginSym = Asm->getFunctionBegin();
112928c89bbbSJoseph Tremoulet   MCSymbol *FuncEndSym = Asm->getFunctionEnd();
113028c89bbbSJoseph Tremoulet 
113128c89bbbSJoseph Tremoulet   // A ClrClause describes a protected region.
113228c89bbbSJoseph Tremoulet   struct ClrClause {
113328c89bbbSJoseph Tremoulet     const MCSymbol *StartLabel; // Start of protected region
113428c89bbbSJoseph Tremoulet     const MCSymbol *EndLabel;   // End of protected region
113528c89bbbSJoseph Tremoulet     int State;          // Index of handler protecting the protected region
113628c89bbbSJoseph Tremoulet     int EnclosingState; // Index of funclet enclosing the protected region
113728c89bbbSJoseph Tremoulet   };
113828c89bbbSJoseph Tremoulet   SmallVector<ClrClause, 8> Clauses;
113928c89bbbSJoseph Tremoulet 
114028c89bbbSJoseph Tremoulet   // Build a map from handler MBBs to their corresponding states (i.e. their
114128c89bbbSJoseph Tremoulet   // indices in the ClrEHUnwindMap).
114228c89bbbSJoseph Tremoulet   int NumStates = FuncInfo.ClrEHUnwindMap.size();
114328c89bbbSJoseph Tremoulet   assert(NumStates > 0 && "Don't need exception table!");
114428c89bbbSJoseph Tremoulet   DenseMap<const MachineBasicBlock *, int> HandlerStates;
114528c89bbbSJoseph Tremoulet   for (int State = 0; State < NumStates; ++State) {
114628c89bbbSJoseph Tremoulet     MachineBasicBlock *HandlerBlock =
114728c89bbbSJoseph Tremoulet         FuncInfo.ClrEHUnwindMap[State].Handler.get<MachineBasicBlock *>();
114828c89bbbSJoseph Tremoulet     HandlerStates[HandlerBlock] = State;
114928c89bbbSJoseph Tremoulet     // Use this loop through all handlers to verify our assumption (used in
115052f729a6SJoseph Tremoulet     // the MinEnclosingState computation) that enclosing funclets have lower
115152f729a6SJoseph Tremoulet     // state numbers than their enclosed funclets.
115252f729a6SJoseph Tremoulet     assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State &&
115328c89bbbSJoseph Tremoulet            "ill-formed state numbering");
115428c89bbbSJoseph Tremoulet   }
115528c89bbbSJoseph Tremoulet   // Map the main function to the NullState.
1156a25ad068SDuncan P. N. Exon Smith   HandlerStates[&MF->front()] = NullState;
115728c89bbbSJoseph Tremoulet 
115828c89bbbSJoseph Tremoulet   // Write out a sentinel indicating the end of the standard (Windows) xdata
115928c89bbbSJoseph Tremoulet   // and the start of the additional (CLR) info.
1160692e0c96SFangrui Song   OS.emitInt32(0xffffffff);
116128c89bbbSJoseph Tremoulet   // Write out the number of funclets
1162692e0c96SFangrui Song   OS.emitInt32(NumStates);
116328c89bbbSJoseph Tremoulet 
116428c89bbbSJoseph Tremoulet   // Walk the machine blocks/instrs, computing and emitting a few things:
116528c89bbbSJoseph Tremoulet   // 1. Emit a list of the offsets to each handler entry, in lexical order.
116628c89bbbSJoseph Tremoulet   // 2. Compute a map (EndSymbolMap) from each funclet to the symbol at its end.
116728c89bbbSJoseph Tremoulet   // 3. Compute the list of ClrClauses, in the required order (inner before
116828c89bbbSJoseph Tremoulet   //    outer, earlier before later; the order by which a forward scan with
116928c89bbbSJoseph Tremoulet   //    early termination will find the innermost enclosing clause covering
117028c89bbbSJoseph Tremoulet   //    a given address).
117128c89bbbSJoseph Tremoulet   // 4. A map (MinClauseMap) from each handler index to the index of the
117228c89bbbSJoseph Tremoulet   //    outermost funclet/function which contains a try clause targeting the
117328c89bbbSJoseph Tremoulet   //    key handler.  This will be used to determine IsDuplicate-ness when
117428c89bbbSJoseph Tremoulet   //    emitting ClrClauses.  The NullState value is used to indicate that the
117528c89bbbSJoseph Tremoulet   //    top-level function contains a try clause targeting the key handler.
117628c89bbbSJoseph Tremoulet   // HandlerStack is a stack of (PendingStartLabel, PendingState) pairs for
117728c89bbbSJoseph Tremoulet   // try regions we entered before entering the PendingState try but which
117828c89bbbSJoseph Tremoulet   // we haven't yet exited.
117928c89bbbSJoseph Tremoulet   SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack;
118028c89bbbSJoseph Tremoulet   // EndSymbolMap and MinClauseMap are maps described above.
118128c89bbbSJoseph Tremoulet   std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]);
118228c89bbbSJoseph Tremoulet   SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates);
118328c89bbbSJoseph Tremoulet 
118428c89bbbSJoseph Tremoulet   // Visit the root function and each funclet.
118528c89bbbSJoseph Tremoulet   for (MachineFunction::const_iterator FuncletStart = MF->begin(),
118628c89bbbSJoseph Tremoulet                                        FuncletEnd = MF->begin(),
118728c89bbbSJoseph Tremoulet                                        End = MF->end();
118828c89bbbSJoseph Tremoulet        FuncletStart != End; FuncletStart = FuncletEnd) {
1189a25ad068SDuncan P. N. Exon Smith     int FuncletState = HandlerStates[&*FuncletStart];
119028c89bbbSJoseph Tremoulet     // Find the end of the funclet
119128c89bbbSJoseph Tremoulet     MCSymbol *EndSymbol = FuncEndSym;
119228c89bbbSJoseph Tremoulet     while (++FuncletEnd != End) {
119328c89bbbSJoseph Tremoulet       if (FuncletEnd->isEHFuncletEntry()) {
1194a25ad068SDuncan P. N. Exon Smith         EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd);
119528c89bbbSJoseph Tremoulet         break;
119628c89bbbSJoseph Tremoulet       }
119728c89bbbSJoseph Tremoulet     }
119828c89bbbSJoseph Tremoulet     // Emit the function/funclet end and, if this is a funclet (and not the
119928c89bbbSJoseph Tremoulet     // root function), record it in the EndSymbolMap.
120077497103SFangrui Song     OS.emitValue(getOffset(EndSymbol, FuncBeginSym), 4);
120128c89bbbSJoseph Tremoulet     if (FuncletState != NullState) {
120228c89bbbSJoseph Tremoulet       // Record the end of the handler.
120328c89bbbSJoseph Tremoulet       EndSymbolMap[FuncletState] = EndSymbol;
120428c89bbbSJoseph Tremoulet     }
120528c89bbbSJoseph Tremoulet 
120628c89bbbSJoseph Tremoulet     // Walk the state changes in this function/funclet and compute its clauses.
120728c89bbbSJoseph Tremoulet     // Funclets always start in the null state.
120828c89bbbSJoseph Tremoulet     const MCSymbol *CurrentStartLabel = nullptr;
120928c89bbbSJoseph Tremoulet     int CurrentState = NullState;
121028c89bbbSJoseph Tremoulet     assert(HandlerStack.empty());
121128c89bbbSJoseph Tremoulet     for (const auto &StateChange :
121228c89bbbSJoseph Tremoulet          InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) {
121328c89bbbSJoseph Tremoulet       // Close any try regions we're not still under
121452f729a6SJoseph Tremoulet       int StillPendingState =
121552f729a6SJoseph Tremoulet           getTryAncestor(FuncInfo, CurrentState, StateChange.NewState);
121652f729a6SJoseph Tremoulet       while (CurrentState != StillPendingState) {
121752f729a6SJoseph Tremoulet         assert(CurrentState != NullState &&
121852f729a6SJoseph Tremoulet                "Failed to find still-pending state!");
121928c89bbbSJoseph Tremoulet         // Close the pending clause
122028c89bbbSJoseph Tremoulet         Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel,
122128c89bbbSJoseph Tremoulet                            CurrentState, FuncletState});
122252f729a6SJoseph Tremoulet         // Now the next-outer try region is current
122352f729a6SJoseph Tremoulet         CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState;
122428c89bbbSJoseph Tremoulet         // Pop the new start label from the handler stack if we've exited all
122552f729a6SJoseph Tremoulet         // inner try regions of the corresponding try region.
122628c89bbbSJoseph Tremoulet         if (HandlerStack.back().second == CurrentState)
122728c89bbbSJoseph Tremoulet           CurrentStartLabel = HandlerStack.pop_back_val().first;
122828c89bbbSJoseph Tremoulet       }
122928c89bbbSJoseph Tremoulet 
123028c89bbbSJoseph Tremoulet       if (StateChange.NewState != CurrentState) {
123128c89bbbSJoseph Tremoulet         // For each clause we're starting, update the MinClauseMap so we can
123228c89bbbSJoseph Tremoulet         // know which is the topmost funclet containing a clause targeting
123328c89bbbSJoseph Tremoulet         // it.
123428c89bbbSJoseph Tremoulet         for (int EnteredState = StateChange.NewState;
123528c89bbbSJoseph Tremoulet              EnteredState != CurrentState;
123652f729a6SJoseph Tremoulet              EnteredState =
123752f729a6SJoseph Tremoulet                  FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) {
123828c89bbbSJoseph Tremoulet           int &MinEnclosingState = MinClauseMap[EnteredState];
123928c89bbbSJoseph Tremoulet           if (FuncletState < MinEnclosingState)
124028c89bbbSJoseph Tremoulet             MinEnclosingState = FuncletState;
124128c89bbbSJoseph Tremoulet         }
124228c89bbbSJoseph Tremoulet         // Save the previous current start/label on the stack and update to
124328c89bbbSJoseph Tremoulet         // the newly-current start/state.
124428c89bbbSJoseph Tremoulet         HandlerStack.emplace_back(CurrentStartLabel, CurrentState);
124528c89bbbSJoseph Tremoulet         CurrentStartLabel = StateChange.NewStartLabel;
124628c89bbbSJoseph Tremoulet         CurrentState = StateChange.NewState;
124728c89bbbSJoseph Tremoulet       }
124828c89bbbSJoseph Tremoulet     }
124928c89bbbSJoseph Tremoulet     assert(HandlerStack.empty());
125028c89bbbSJoseph Tremoulet   }
125128c89bbbSJoseph Tremoulet 
125228c89bbbSJoseph Tremoulet   // Now emit the clause info, starting with the number of clauses.
1253692e0c96SFangrui Song   OS.emitInt32(Clauses.size());
125428c89bbbSJoseph Tremoulet   for (ClrClause &Clause : Clauses) {
125528c89bbbSJoseph Tremoulet     // Emit a CORINFO_EH_CLAUSE :
125628c89bbbSJoseph Tremoulet     /*
125728c89bbbSJoseph Tremoulet       struct CORINFO_EH_CLAUSE
125828c89bbbSJoseph Tremoulet       {
125928c89bbbSJoseph Tremoulet           CORINFO_EH_CLAUSE_FLAGS Flags;         // actually a CorExceptionFlag
126028c89bbbSJoseph Tremoulet           DWORD                   TryOffset;
126128c89bbbSJoseph Tremoulet           DWORD                   TryLength;     // actually TryEndOffset
126228c89bbbSJoseph Tremoulet           DWORD                   HandlerOffset;
126328c89bbbSJoseph Tremoulet           DWORD                   HandlerLength; // actually HandlerEndOffset
126428c89bbbSJoseph Tremoulet           union
126528c89bbbSJoseph Tremoulet           {
126628c89bbbSJoseph Tremoulet               DWORD               ClassToken;   // use for catch clauses
126728c89bbbSJoseph Tremoulet               DWORD               FilterOffset; // use for filter clauses
126828c89bbbSJoseph Tremoulet           };
126928c89bbbSJoseph Tremoulet       };
127028c89bbbSJoseph Tremoulet 
127128c89bbbSJoseph Tremoulet       enum CORINFO_EH_CLAUSE_FLAGS
127228c89bbbSJoseph Tremoulet       {
127328c89bbbSJoseph Tremoulet           CORINFO_EH_CLAUSE_NONE    = 0,
127428c89bbbSJoseph Tremoulet           CORINFO_EH_CLAUSE_FILTER  = 0x0001, // This clause is for a filter
127528c89bbbSJoseph Tremoulet           CORINFO_EH_CLAUSE_FINALLY = 0x0002, // This clause is a finally clause
127628c89bbbSJoseph Tremoulet           CORINFO_EH_CLAUSE_FAULT   = 0x0004, // This clause is a fault clause
127728c89bbbSJoseph Tremoulet       };
127828c89bbbSJoseph Tremoulet       typedef enum CorExceptionFlag
127928c89bbbSJoseph Tremoulet       {
128028c89bbbSJoseph Tremoulet           COR_ILEXCEPTION_CLAUSE_NONE,
128128c89bbbSJoseph Tremoulet           COR_ILEXCEPTION_CLAUSE_FILTER  = 0x0001, // This is a filter clause
128228c89bbbSJoseph Tremoulet           COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002, // This is a finally clause
128328c89bbbSJoseph Tremoulet           COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004,   // This is a fault clause
128428c89bbbSJoseph Tremoulet           COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008, // duplicated clause. This
128528c89bbbSJoseph Tremoulet                                                       // clause was duplicated
128628c89bbbSJoseph Tremoulet                                                       // to a funclet which was
128728c89bbbSJoseph Tremoulet                                                       // pulled out of line
128828c89bbbSJoseph Tremoulet       } CorExceptionFlag;
128928c89bbbSJoseph Tremoulet     */
129028c89bbbSJoseph Tremoulet     // Add 1 to the start/end of the EH clause; the IP associated with a
129128c89bbbSJoseph Tremoulet     // call when the runtime does its scan is the IP of the next instruction
129228c89bbbSJoseph Tremoulet     // (the one to which control will return after the call), so we need
129328c89bbbSJoseph Tremoulet     // to add 1 to the end of the clause to cover that offset.  We also add
129428c89bbbSJoseph Tremoulet     // 1 to the start of the clause to make sure that the ranges reported
129528c89bbbSJoseph Tremoulet     // for all clauses are disjoint.  Note that we'll need some additional
129628c89bbbSJoseph Tremoulet     // logic when machine traps are supported, since in that case the IP
129728c89bbbSJoseph Tremoulet     // that the runtime uses is the offset of the faulting instruction
129828c89bbbSJoseph Tremoulet     // itself; if such an instruction immediately follows a call but the
129928c89bbbSJoseph Tremoulet     // two belong to different clauses, we'll need to insert a nop between
130028c89bbbSJoseph Tremoulet     // them so the runtime can distinguish the point to which the call will
130128c89bbbSJoseph Tremoulet     // return from the point at which the fault occurs.
130228c89bbbSJoseph Tremoulet 
130328c89bbbSJoseph Tremoulet     const MCExpr *ClauseBegin =
130428c89bbbSJoseph Tremoulet         getOffsetPlusOne(Clause.StartLabel, FuncBeginSym);
130528c89bbbSJoseph Tremoulet     const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym);
130628c89bbbSJoseph Tremoulet 
1307c20276d0SReid Kleckner     const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State];
130828c89bbbSJoseph Tremoulet     MachineBasicBlock *HandlerBlock = Entry.Handler.get<MachineBasicBlock *>();
130928c89bbbSJoseph Tremoulet     MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock);
131028c89bbbSJoseph Tremoulet     const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym);
131128c89bbbSJoseph Tremoulet     MCSymbol *EndSym = EndSymbolMap[Clause.State];
131228c89bbbSJoseph Tremoulet     const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym);
131328c89bbbSJoseph Tremoulet 
131428c89bbbSJoseph Tremoulet     uint32_t Flags = 0;
131528c89bbbSJoseph Tremoulet     switch (Entry.HandlerType) {
131628c89bbbSJoseph Tremoulet     case ClrHandlerType::Catch:
131728c89bbbSJoseph Tremoulet       // Leaving bits 0-2 clear indicates catch.
131828c89bbbSJoseph Tremoulet       break;
131928c89bbbSJoseph Tremoulet     case ClrHandlerType::Filter:
132028c89bbbSJoseph Tremoulet       Flags |= 1;
132128c89bbbSJoseph Tremoulet       break;
132228c89bbbSJoseph Tremoulet     case ClrHandlerType::Finally:
132328c89bbbSJoseph Tremoulet       Flags |= 2;
132428c89bbbSJoseph Tremoulet       break;
132528c89bbbSJoseph Tremoulet     case ClrHandlerType::Fault:
132628c89bbbSJoseph Tremoulet       Flags |= 4;
132728c89bbbSJoseph Tremoulet       break;
132828c89bbbSJoseph Tremoulet     }
132928c89bbbSJoseph Tremoulet     if (Clause.EnclosingState != MinClauseMap[Clause.State]) {
133028c89bbbSJoseph Tremoulet       // This is a "duplicate" clause; the handler needs to be entered from a
133128c89bbbSJoseph Tremoulet       // frame above the one holding the invoke.
133228c89bbbSJoseph Tremoulet       assert(Clause.EnclosingState > MinClauseMap[Clause.State]);
133328c89bbbSJoseph Tremoulet       Flags |= 8;
133428c89bbbSJoseph Tremoulet     }
1335692e0c96SFangrui Song     OS.emitInt32(Flags);
133628c89bbbSJoseph Tremoulet 
133728c89bbbSJoseph Tremoulet     // Write the clause start/end
133877497103SFangrui Song     OS.emitValue(ClauseBegin, 4);
133977497103SFangrui Song     OS.emitValue(ClauseEnd, 4);
134028c89bbbSJoseph Tremoulet 
134128c89bbbSJoseph Tremoulet     // Write out the handler start/end
134277497103SFangrui Song     OS.emitValue(HandlerBegin, 4);
134377497103SFangrui Song     OS.emitValue(HandlerEnd, 4);
134428c89bbbSJoseph Tremoulet 
134528c89bbbSJoseph Tremoulet     // Write out the type token or filter offset
134628c89bbbSJoseph Tremoulet     assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters");
1347692e0c96SFangrui Song     OS.emitInt32(Entry.TypeToken);
134828c89bbbSJoseph Tremoulet   }
134928c89bbbSJoseph Tremoulet }
1350