llvm.org GIT mirror llvm / 2fa550c
[WebAssembly] LSDA info generation Summary: This adds support for LSDA (exception table) generation for wasm EH. Wasm EH mostly follows the structure of Itanium-style exception tables, with one exception: a call site table entry in wasm EH corresponds to not a call site but a landing pad. In wasm EH, the VM is responsible for stack unwinding. After an exception occurs and the stack is unwound, the control flow is transferred to wasm 'catch' instruction by the VM, after which the personality function is called from the compiler-generated code. (Refer to WasmEHPrepare pass for more information on this part.) This patch: - Changes wasm.landingpad.index intrinsic to take a token argument, to make this 1:1 match with a catchpad instruction - Stores landingpad index info and catch type info MachineFunction in before instruction selection - Lowers wasm.lsda intrinsic to an MCSymbol pointing to the start of an exception table - Adds WasmException class with overridden methods for table generation - Adds support for LSDA section in Wasm object writer Reviewers: dschuff, sbc100, rnk Subscribers: mgorny, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D52748 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344575 91177308-0d34-0410-b5e6-96231b3b80d8 Heejin Ahn 1 year, 5 months ago
20 changed file(s) with 530 addition(s) and 68 deletion(s). Raw diff Collapse all Expand all
315315 /// Map a landing pad's EH symbol to the call site indexes.
316316 DenseMap> LPadToCallSiteMap;
317317
318 /// Map a landing pad to its index.
319 DenseMap WasmLPadToIndexMap;
320
318321 /// Map of invoke call site index values to associated begin EH_LABEL.
319322 DenseMap CallSiteMap;
320323
809812 LandingPadInfo &getOrCreateLandingPadInfo(MachineBasicBlock *LandingPad);
810813
811814 /// Remap landing pad labels and remove any deleted landing pads.
812 void tidyLandingPads(DenseMap*, uintptr_t> *LPMap = nullptr);
815 void tidyLandingPads(DenseMap *, uintptr_t> *LPMap = nullptr,
816 bool TidyIfNoBeginLabels = true);
813817
814818 /// Return a reference to the landing pad info for the current function.
815819 const std::vector &getLandingPads() const {
851855
852856 /// Map the landing pad's EH symbol to the call site indexes.
853857 void setCallSiteLandingPad(MCSymbol *Sym, ArrayRef Sites);
858
859 /// Map the landing pad to its index. Used for Wasm exception handling.
860 void setWasmLandingPadIndex(const MachineBasicBlock *LPad, unsigned Index) {
861 WasmLPadToIndexMap[LPad] = Index;
862 }
863
864 /// Returns true if the landing pad has an associate index in wasm EH.
865 bool hasWasmLandingPadIndex(const MachineBasicBlock *LPad) const {
866 return WasmLPadToIndexMap.count(LPad);
867 }
868
869 /// Get the index in wasm EH for a given landing pad.
870 unsigned getWasmLandingPadIndex(const MachineBasicBlock *LPad) const {
871 assert(hasWasmLandingPadIndex(LPad));
872 return WasmLPadToIndexMap.lookup(LPad);
873 }
854874
855875 /// Get the call site indexes for a landing pad EH symbol.
856876 SmallVectorImpl &getCallSiteLandingPad(MCSymbol *Sym) {
7070 // WebAssembly EH must maintain the landingpads in the order assigned to them
7171 // by WasmEHPrepare pass to generate landingpad table in EHStreamer. This is
7272 // used in order to give them the indices in WasmEHPrepare.
73 def int_wasm_landingpad_index: Intrinsic<[], [llvm_i32_ty], [IntrNoMem]>;
73 def int_wasm_landingpad_index: Intrinsic<[], [llvm_token_ty, llvm_i32_ty],
74 [IntrNoMem]>;
7475
7576 // Returns LSDA address of the current function.
7677 def int_wasm_lsda : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
1515 #include "CodeViewDebug.h"
1616 #include "DwarfDebug.h"
1717 #include "DwarfException.h"
18 #include "WasmException.h"
1819 #include "WinCFGuard.h"
1920 #include "WinException.h"
2021 #include "llvm/ADT/APFloat.h"
355356 }
356357 break;
357358 case ExceptionHandling::Wasm:
358 // TODO to prevent warning
359 ES = new WasmException(this);
359360 break;
360361 }
361362 if (ES)
2222 WinCFGuard.cpp
2323 WinException.cpp
2424 CodeViewDebug.cpp
25 WasmException.cpp
2526
2627 DEPENDS
2728 intrinsics_gen
344344 /// unwound and handling continues.
345345 /// 3. Type ID table contains references to all the C++ typeinfo for all
346346 /// catches in the function. This tables is reverse indexed base 1.
347 void EHStreamer::emitExceptionTable() {
347 ///
348 /// Returns the starting symbol of an exception table.
349 MCSymbol *EHStreamer::emitExceptionTable() {
348350 const MachineFunction *MF = Asm->MF;
349351 const std::vector &TypeInfos = MF->getTypeInfos();
350352 const std::vector &FilterIds = MF->getFilterIds();
374376 computeCallSiteTable(CallSites, LandingPads, FirstActions);
375377
376378 bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
379 bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm;
377380 unsigned CallSiteEncoding =
378381 IsSJLJ ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_uleb128;
379382 bool HaveTTData = !TypeInfos.empty() || !FilterIds.empty();
456459 Asm->EmitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel);
457460 Asm->OutStreamer->EmitLabel(CstBeginLabel);
458461
459 // SjLj Exception handling
460 if (IsSJLJ) {
462 // SjLj / Wasm Exception handling
463 if (IsSJLJ || IsWasm) {
461464 unsigned idx = 0;
462465 for (SmallVectorImpl::const_iterator
463466 I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) {
603606 }
604607
605608 Asm->EmitAlignment(2);
609 return GCCETSym;
606610 }
607611
608612 void EHStreamer::emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) {
8484 /// zero for the landing pad and the action. Calls marked 'nounwind' have
8585 /// no entry and must not be contained in the try-range of any entry - they
8686 /// form gaps in the table. Entries must be ordered by try-range address.
87 void computeCallSiteTable(SmallVectorImpl &CallSites,
88 const SmallVectorImpl &LandingPads,
89 const SmallVectorImpl &FirstActions);
87 virtual void computeCallSiteTable(
88 SmallVectorImpl &CallSites,
89 const SmallVectorImpl &LandingPads,
90 const SmallVectorImpl &FirstActions);
9091
9192 /// Emit landing pads and actions.
9293 ///
107108 /// found the frame is unwound and handling continues.
108109 /// 3. Type id table contains references to all the C++ typeinfo for all
109110 /// catches in the function. This tables is reversed indexed base 1.
110 void emitExceptionTable();
111 ///
112 /// Returns the starting symbol of an exception table.
113 MCSymbol *emitExceptionTable();
111114
112115 virtual void emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel);
113116
0 //===-- CodeGen/AsmPrinter/WasmException.cpp - Wasm Exception Impl --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains support for writing WebAssembly exception info into asm
10 // files.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "WasmException.h"
15 #include "llvm/MC/MCStreamer.h"
16 using namespace llvm;
17
18 void WasmException::markFunctionEnd() {
19 // Get rid of any dead landing pads.
20 if (!Asm->MF->getLandingPads().empty()) {
21 auto *NonConstMF = const_cast(Asm->MF);
22 // Wasm does not set BeginLabel and EndLabel information for landing pads,
23 // so we should set the second argument false.
24 NonConstMF->tidyLandingPads(nullptr, /* TidyIfNoBeginLabels */ false);
25 }
26 }
27
28 void WasmException::endFunction(const MachineFunction *MF) {
29 bool ShouldEmitExceptionTable = false;
30 for (const LandingPadInfo &Info : MF->getLandingPads()) {
31 if (MF->hasWasmLandingPadIndex(Info.LandingPadBlock)) {
32 ShouldEmitExceptionTable = true;
33 break;
34 }
35 }
36 if (!ShouldEmitExceptionTable)
37 return;
38 MCSymbol *LSDALabel = emitExceptionTable();
39 assert(LSDALabel && ".GCC_exception_table has not been emitted!");
40
41 // Wasm requires every data section symbol to have a .size set. So we emit an
42 // end marker and set the size as the difference between the start end the end
43 // marker.
44 MCSymbol *LSDAEndLabel = Asm->createTempSymbol("GCC_except_table_end");
45 Asm->OutStreamer->EmitLabel(LSDAEndLabel);
46 MCContext &OutContext = Asm->OutStreamer->getContext();
47 const MCExpr *SizeExp = MCBinaryExpr::createSub(
48 MCSymbolRefExpr::create(LSDAEndLabel, OutContext),
49 MCSymbolRefExpr::create(LSDALabel, OutContext), OutContext);
50 Asm->OutStreamer->emitELFSize(LSDALabel, SizeExp);
51 }
52
53 // Compute the call-site table for wasm EH. Even though we use the same function
54 // name to share the common routines, a call site entry in the table corresponds
55 // to not a call site for possibly-throwing functions but a landing pad. In wasm
56 // EH the VM is responsible for stack unwinding. After an exception occurs and
57 // the stack is unwound, the control flow is transferred to wasm 'catch'
58 // instruction by the VM, after which the personality function is called from
59 // the compiler-generated code. Refer to WasmEHPrepare pass for more
60 // information.
61 void WasmException::computeCallSiteTable(
62 SmallVectorImpl &CallSites,
63 const SmallVectorImpl &LandingPads,
64 const SmallVectorImpl &FirstActions) {
65 MachineFunction &MF = *Asm->MF;
66 for (unsigned I = 0, N = LandingPads.size(); I < N; ++I) {
67 const LandingPadInfo *Info = LandingPads[I];
68 MachineBasicBlock *LPad = Info->LandingPadBlock;
69 // We don't emit LSDA for single catch (...).
70 if (!MF.hasWasmLandingPadIndex(LPad))
71 continue;
72 // Wasm EH must maintain the EH pads in the order assigned to them by the
73 // WasmEHPrepare pass.
74 unsigned LPadIndex = MF.getWasmLandingPadIndex(LPad);
75 CallSiteEntry Site = {nullptr, nullptr, Info, FirstActions[I]};
76 if (CallSites.size() < LPadIndex + 1)
77 CallSites.resize(LPadIndex + 1);
78 CallSites[LPadIndex] = Site;
79 }
80 }
0 //===-- WasmException.h - Wasm Exception Framework -------------*- C++ -*--===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains support for writing WebAssembly exception info into asm
10 // files.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_WASMEXCEPTION_H
15 #define LLVM_LIB_CODEGEN_ASMPRINTER_WASMEXCEPTION_H
16
17 #include "EHStreamer.h"
18 #include "llvm/CodeGen/AsmPrinter.h"
19
20 namespace llvm {
21
22 class LLVM_LIBRARY_VISIBILITY WasmException : public EHStreamer {
23 public:
24 WasmException(AsmPrinter *A) : EHStreamer(A) {}
25
26 void endModule() override {}
27 void beginFunction(const MachineFunction *MF) override {}
28 virtual void markFunctionEnd() override;
29 void endFunction(const MachineFunction *MF) override;
30
31 protected:
32 // Compute the call site table for wasm EH.
33 void computeCallSiteTable(
34 SmallVectorImpl &CallSites,
35 const SmallVectorImpl &LandingPads,
36 const SmallVectorImpl &FirstActions) override;
37 };
38
39 } // End of namespace llvm
40
41 #endif
660660 }
661661 }
662662
663 } else if (isa(FirstI)) {
664 // TODO
663 } else if (const auto *CPI = dyn_cast(FirstI)) {
664 for (unsigned I = CPI->getNumArgOperands(); I != 0; --I) {
665 Value *TypeInfo = CPI->getArgOperand(I - 1)->stripPointerCasts();
666 addCatchTypeInfo(LandingPad, dyn_cast(TypeInfo));
667 }
665668
666669 } else {
667670 assert(isa(FirstI) && "Invalid landingpad!");
686689 LP.TypeIds.push_back(getFilterIDFor(IdsInFilter));
687690 }
688691
689 void MachineFunction::tidyLandingPads(DenseMap*, uintptr_t> *LPMap) {
692 void MachineFunction::tidyLandingPads(DenseMap *, uintptr_t> *LPMap,
693 bool TidyIfNoBeginLabels) {
690694 for (unsigned i = 0; i != LandingPads.size(); ) {
691695 LandingPadInfo &LandingPad = LandingPads[i];
692696 if (LandingPad.LandingPadLabel &&
701705 continue;
702706 }
703707
704 for (unsigned j = 0, e = LandingPads[i].BeginLabels.size(); j != e; ++j) {
705 MCSymbol *BeginLabel = LandingPad.BeginLabels[j];
706 MCSymbol *EndLabel = LandingPad.EndLabels[j];
707 if ((BeginLabel->isDefined() ||
708 (LPMap && (*LPMap)[BeginLabel] != 0)) &&
709 (EndLabel->isDefined() ||
710 (LPMap && (*LPMap)[EndLabel] != 0))) continue;
711
712 LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j);
713 LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j);
714 --j;
715 --e;
716 }
717
718 // Remove landing pads with no try-ranges.
719 if (LandingPads[i].BeginLabels.empty()) {
720 LandingPads.erase(LandingPads.begin() + i);
721 continue;
708 if (TidyIfNoBeginLabels) {
709 for (unsigned j = 0, e = LandingPads[i].BeginLabels.size(); j != e; ++j) {
710 MCSymbol *BeginLabel = LandingPad.BeginLabels[j];
711 MCSymbol *EndLabel = LandingPad.EndLabels[j];
712 if ((BeginLabel->isDefined() || (LPMap && (*LPMap)[BeginLabel] != 0)) &&
713 (EndLabel->isDefined() || (LPMap && (*LPMap)[EndLabel] != 0)))
714 continue;
715
716 LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j);
717 LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j);
718 --j;
719 --e;
720 }
721
722 // Remove landing pads with no try-ranges.
723 if (LandingPads[i].BeginLabels.empty()) {
724 LandingPads.erase(LandingPads.begin() + i);
725 continue;
726 }
722727 }
723728
724729 // If there is no landing pad, ensure that the list of typeids is empty.
62816281 return nullptr;
62826282 }
62836283
6284 case Intrinsic::wasm_landingpad_index: {
6285 // TODO store landing pad index in a map, which will be used when generating
6286 // LSDA information
6284 case Intrinsic::wasm_landingpad_index:
6285 // Information this intrinsic contained has been transferred to
6286 // MachineFunction in SelectionDAGISel::PrepareEHLandingPad. We can safely
6287 // delete it now.
62876288 return nullptr;
6288 }
62896289 }
62906290 }
62916291
64436443 WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo();
64446444 EHInfo->addIPToStateRange(cast(CLI.CS.getInstruction()),
64456445 BeginLabel, EndLabel);
6446 } else {
6446 } else if (!isScopedEHPersonality(Pers)) {
64476447 MF.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel);
64486448 }
64496449 }
2626 #include "llvm/Analysis/AliasAnalysis.h"
2727 #include "llvm/Analysis/BranchProbabilityInfo.h"
2828 #include "llvm/Analysis/CFG.h"
29 #include "llvm/Analysis/EHPersonalities.h"
2930 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
3031 #include "llvm/Analysis/TargetLibraryInfo.h"
3132 #include "llvm/Analysis/TargetTransformInfo.h"
11271128 return false;
11281129 }
11291130
1131 // wasm.landingpad.index intrinsic is for associating a landing pad index number
1132 // with a catchpad instruction. Retrieve the landing pad index in the intrinsic
1133 // and store the mapping in the function.
1134 static void mapWasmLandingPadIndex(MachineBasicBlock *MBB,
1135 const CatchPadInst *CPI) {
1136 MachineFunction *MF = MBB->getParent();
1137 // In case of single catch (...), we don't emit LSDA, so we don't need
1138 // this information.
1139 bool IsSingleCatchAllClause =
1140 CPI->getNumArgOperands() == 1 &&
1141 cast(CPI->getArgOperand(0))->isNullValue();
1142 if (!IsSingleCatchAllClause) {
1143 // Create a mapping from landing pad label to landing pad index.
1144 bool IntrFound = false;
1145 for (const User *U : CPI->users()) {
1146 if (const auto *Call = dyn_cast(U)) {
1147 Intrinsic::ID IID = Call->getIntrinsicID();
1148 if (IID == Intrinsic::wasm_landingpad_index) {
1149 Value *IndexArg = Call->getArgOperand(1);
1150 int Index = cast(IndexArg)->getZExtValue();
1151 MF->setWasmLandingPadIndex(MBB, Index);
1152 IntrFound = true;
1153 break;
1154 }
1155 }
1156 }
1157 assert(IntrFound && "wasm.landingpad.index intrinsic not found!");
1158 }
1159 }
1160
11301161 /// PrepareEHLandingPad - Emit an EH_LABEL, set up live-in registers, and
11311162 /// do other setup for EH landing-pad blocks.
11321163 bool SelectionDAGISel::PrepareEHLandingPad() {
11361167 const TargetRegisterClass *PtrRC =
11371168 TLI->getRegClassFor(TLI->getPointerTy(CurDAG->getDataLayout()));
11381169
1170 auto Pers = classifyEHPersonality(PersonalityFn);
1171
11391172 // Catchpads have one live-in register, which typically holds the exception
11401173 // pointer or code.
1141 if (const auto *CPI = dyn_cast(LLVMBB->getFirstNonPHI())) {
1142 if (hasExceptionPointerOrCodeUser(CPI)) {
1143 // Get or create the virtual register to hold the pointer or code. Mark
1144 // the live in physreg and copy into the vreg.
1145 MCPhysReg EHPhysReg = TLI->getExceptionPointerRegister(PersonalityFn);
1146 assert(EHPhysReg && "target lacks exception pointer register");
1147 MBB->addLiveIn(EHPhysReg);
1148 unsigned VReg = FuncInfo->getCatchPadExceptionPointerVReg(CPI, PtrRC);
1149 BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(),
1150 TII->get(TargetOpcode::COPY), VReg)
1151 .addReg(EHPhysReg, RegState::Kill);
1174 if (isFuncletEHPersonality(Pers)) {
1175 if (const auto *CPI = dyn_cast(LLVMBB->getFirstNonPHI())) {
1176 if (hasExceptionPointerOrCodeUser(CPI)) {
1177 // Get or create the virtual register to hold the pointer or code. Mark
1178 // the live in physreg and copy into the vreg.
1179 MCPhysReg EHPhysReg = TLI->getExceptionPointerRegister(PersonalityFn);
1180 assert(EHPhysReg && "target lacks exception pointer register");
1181 MBB->addLiveIn(EHPhysReg);
1182 unsigned VReg = FuncInfo->getCatchPadExceptionPointerVReg(CPI, PtrRC);
1183 BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(),
1184 TII->get(TargetOpcode::COPY), VReg)
1185 .addReg(EHPhysReg, RegState::Kill);
1186 }
11521187 }
11531188 return true;
11541189 }
1155
1156 if (!LLVMBB->isLandingPad())
1157 return true;
11581190
11591191 // Add a label to mark the beginning of the landing pad. Deletion of the
11601192 // landing pad can thus be detected via the MachineModuleInfo.
11611193 MCSymbol *Label = MF->addLandingPad(MBB);
11621194
1163 // Assign the call site to the landing pad's begin label.
1164 MF->setCallSiteLandingPad(Label, SDB->LPadToCallSiteMap[MBB]);
1165
11661195 const MCInstrDesc &II = TII->get(TargetOpcode::EH_LABEL);
11671196 BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II)
11681197 .addSym(Label);
11691198
1170 // Mark exception register as live in.
1171 if (unsigned Reg = TLI->getExceptionPointerRegister(PersonalityFn))
1172 FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC);
1173
1174 // Mark exception selector register as live in.
1175 if (unsigned Reg = TLI->getExceptionSelectorRegister(PersonalityFn))
1176 FuncInfo->ExceptionSelectorVirtReg = MBB->addLiveIn(Reg, PtrRC);
1199 if (Pers == EHPersonality::Wasm_CXX) {
1200 if (const auto *CPI = dyn_cast(LLVMBB->getFirstNonPHI()))
1201 mapWasmLandingPadIndex(MBB, CPI);
1202 } else {
1203 // Assign the call site to the landing pad's begin label.
1204 MF->setCallSiteLandingPad(Label, SDB->LPadToCallSiteMap[MBB]);
1205 // Mark exception register as live in.
1206 if (unsigned Reg = TLI->getExceptionPointerRegister(PersonalityFn))
1207 FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC);
1208 // Mark exception selector register as live in.
1209 if (unsigned Reg = TLI->getExceptionSelectorRegister(PersonalityFn))
1210 FuncInfo->ExceptionSelectorVirtReg = MBB->addLiveIn(Reg, PtrRC);
1211 }
11771212
11781213 return true;
11791214 }
17471747 void TargetLoweringObjectFileWasm::InitializeWasm() {
17481748 StaticCtorSection =
17491749 getContext().getWasmSection(".init_array", SectionKind::getData());
1750
1751 // We don't use PersonalityEncoding and LSDAEncoding because we don't emit
1752 // .cfi directives. We use TTypeEncoding to encode typeinfo global variables.
1753 TTypeEncoding = dwarf::DW_EH_PE_absptr;
17501754 }
17511755
17521756 MCSection *TargetLoweringObjectFileWasm::getStaticCtorSection(
299299 // This is to create a map of in
300300 // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
301301 // Pseudocode: wasm.landingpad.index(Index);
302 IRB.CreateCall(LPadIndexF, IRB.getInt32(Index));
302 IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
303303
304304 // Pseudocode: __wasm_lpad_context.lpad_index = index;
305305 IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
742742 DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata());
743743 DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata());
744744
745 // Wasm use data section for LSDA.
746 // TODO Consider putting each function's exception table in a separate
747 // section, as in -function-sections, to facilitate lld's --gc-section.
748 LSDASection = Ctx->getWasmSection(".rodata.gcc_except_table",
749 SectionKind::getReadOnlyWithRel());
750
745751 // TODO: Define more sections.
746752 }
747753
634634 llvm_unreachable("The fill should be an assembler constant");
635635 DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
636636 Fill->getValue());
637 } else if (auto *LEB = dyn_cast(&Frag)) {
638 const SmallVectorImpl &Contents = LEB->getContents();
639 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
637640 } else {
638641 const auto &DataFrag = cast(Frag);
639642 const SmallVectorImpl &Contents = DataFrag.getContents();
640
641643 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
642644 }
643645 }
2020 #include "llvm/CodeGen/CallingConvLower.h"
2121 #include "llvm/CodeGen/MachineInstrBuilder.h"
2222 #include "llvm/CodeGen/MachineJumpTableInfo.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
2324 #include "llvm/CodeGen/MachineRegisterInfo.h"
2425 #include "llvm/CodeGen/SelectionDAG.h"
2526 #include "llvm/IR/DiagnosticInfo.h"
965966 default:
966967 return {}; // Don't custom lower most intrinsics.
967968
968 case Intrinsic::wasm_lsda:
969 // TODO For now, just return 0 not to crash
970 return DAG.getConstant(0, DL, Op.getValueType());
969 case Intrinsic::wasm_lsda: {
970 MachineFunction &MF = DAG.getMachineFunction();
971 EVT VT = Op.getValueType();
972 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
973 MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
974 auto &Context = MF.getMMI().getContext();
975 MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
976 Twine(MF.getFunctionNumber()));
977 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
978 DAG.getMCSymbol(S, PtrVT));
979 }
971980 }
972981 }
973982
268268 (CONST_I32 tglobaladdr:$addr)>;
269269 def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
270270 (CONST_I32 texternalsym:$addr)>;
271 def : Pat<(i32 (WebAssemblywrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
272 def : Pat<(i64 (WebAssemblywrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
271273
272274 //===----------------------------------------------------------------------===//
273275 // Additional sets of instructions.
225225 (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
226226 (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0);
227227 break;
228 case MachineOperand::MO_MCSymbol:
229 // This is currently used only for LSDA symbols (GCC_except_table),
230 // because global addresses or other external symbols are handled above.
231 assert(MO.getTargetFlags() == 0 &&
232 "WebAssembly does not use target flags on MCSymbol");
233 MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false);
234 break;
228235 }
229236
230237 OutMI.addOperand(MCOp);
0 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
1 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
2 target triple = "wasm32-unknown-unknown"
3
4 @_ZTIi = external constant i8*
5 @_ZTIf = external constant i8*
6 @_ZTId = external constant i8*
7
8 ; Single catch (...) does not need an exception table.
9 ;
10 ; try {
11 ; may_throw();
12 ; } catch (...) {
13 ; }
14 ; CHECK-LABEL: test0:
15 ; CHECK-NOT: GCC_except_table
16 define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
17 entry:
18 invoke void @may_throw()
19 to label %try.cont unwind label %catch.dispatch
20
21 catch.dispatch: ; preds = %entry
22 %0 = catchswitch within none [label %catch.start] unwind to caller
23
24 catch.start: ; preds = %catch.dispatch
25 %1 = catchpad within %0 [i8* null]
26 %2 = call i8* @llvm.wasm.get.exception(token %1)
27 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
28 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
29 call void @__cxa_end_catch() [ "funclet"(token %1) ]
30 catchret from %1 to label %try.cont
31
32 try.cont: ; preds = %entry, %catch.start
33 ret void
34 }
35
36 ; Exception table generation + shared action test.
37 ;
38 ; try {
39 ; may_throw();
40 ; } catch (int) {
41 ; } catch (float) {
42 ; } catch (double) {
43 ; } catch (...) {
44 ; }
45 ;
46 ; try {
47 ; may_throw();
48 ; } catch (double) {
49 ; } catch (...) {
50 ; }
51 ;
52 ; try {
53 ; may_throw();
54 ; } catch (int) {
55 ; } catch (float) {
56 ; }
57 ;
58 ; There are three landing pads. The second landing pad should share action table
59 ; entries with the first landing pad because they end with the same sequence
60 ; (double -> ...). But the third landing table cannot share action table entries
61 ; with others, so it should create its own entries.
62 ; CHECK-LABEL: test1:
63 ; CHECK: .section .rodata.gcc_except_table,"",@
64 ; CHECK-NEXT: .p2align 2
65 ; CHECK-NEXT: GCC_except_table[[START:[0-9]+]]:
66 ; CHECK-NEXT: .Lexception0:
67 ; CHECK-NEXT: .int8 255 # @LPStart Encoding = omit
68 ; CHECK-NEXT: .int8 0 # @TType Encoding = absptr
69 ; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0
70 ; CHECK-NEXT: .Lttbaseref0:
71 ; CHECK-NEXT: .int8 1 # Call site Encoding = uleb128
72 ; CHECK-NEXT: .uleb128 .Lcst_end0-.Lcst_begin0
73 ; CHECK-NEXT: .Lcst_begin0:
74 ; CHECK-NEXT: .int8 0 # >> Call Site 0 <<
75 ; CHECK-NEXT: # On exception at call site 0
76 ; CHECK-NEXT: .int8 7 # Action: 4
77 ; CHECK-NEXT: .int8 1 # >> Call Site 1 <<
78 ; CHECK-NEXT: # On exception at call site 1
79 ; CHECK-NEXT: .int8 3 # Action: 2
80 ; CHECK-NEXT: .int8 2 # >> Call Site 2 <<
81 ; CHECK-NEXT: # On exception at call site 2
82 ; CHECK-NEXT: .int8 11 # Action: 6
83 ; CHECK-NEXT: .Lcst_end0:
84 ; CHECK-NEXT: .int8 1 # >> Action Record 1 <<
85 ; CHECK-NEXT: # Catch TypeInfo 1
86 ; CHECK-NEXT: .int8 0 # No further actions
87 ; CHECK-NEXT: .int8 2 # >> Action Record 2 <<
88 ; CHECK-NEXT: # Catch TypeInfo 2
89 ; CHECK-NEXT: .int8 125 # Continue to action 1
90 ; CHECK-NEXT: .int8 3 # >> Action Record 3 <<
91 ; CHECK-NEXT: # Catch TypeInfo 3
92 ; CHECK-NEXT: .int8 125 # Continue to action 2
93 ; CHECK-NEXT: .int8 4 # >> Action Record 4 <<
94 ; CHECK-NEXT: # Catch TypeInfo 4
95 ; CHECK-NEXT: .int8 125 # Continue to action 3
96 ; CHECK-NEXT: .int8 3 # >> Action Record 5 <<
97 ; CHECK-NEXT: # Catch TypeInfo 3
98 ; CHECK-NEXT: .int8 0 # No further actions
99 ; CHECK-NEXT: .int8 4 # >> Action Record 6 <<
100 ; CHECK-NEXT: # Catch TypeInfo 4
101 ; CHECK-NEXT: .int8 125 # Continue to action 5
102 ; CHECK-NEXT: .p2align 2
103 ; CHECK-NEXT: # >> Catch TypeInfos <<
104 ; CHECK-NEXT: .int32 _ZTIi # TypeInfo 4
105 ; CHECK-NEXT: .int32 _ZTIf # TypeInfo 3
106 ; CHECK-NEXT: .int32 _ZTId # TypeInfo 2
107 ; CHECK-NEXT: .int32 0 # TypeInfo 1
108 ; CHECK-NEXT: .Lttbase0:
109 ; CHECK-NEXT: .p2align 2
110 ; CHECK-NEXT: .LGCC_except_table_end[[END:[0-9]+]]:
111 ; CHECK-NEXT: .size GCC_except_table[[START]], .LGCC_except_table_end[[END]]-GCC_except_table[[START]]
112 define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
113 entry:
114 invoke void @may_throw()
115 to label %try.cont unwind label %catch.dispatch
116
117 catch.dispatch: ; preds = %entry
118 %0 = catchswitch within none [label %catch.start] unwind to caller
119
120 catch.start: ; preds = %catch.dispatch
121 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIf to i8*), i8* bitcast (i8** @_ZTId to i8*), i8* null]
122 %2 = call i8* @llvm.wasm.get.exception(token %1)
123 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
124 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
125 %matches = icmp eq i32 %3, %4
126 br i1 %matches, label %catch10, label %catch.fallthrough
127
128 catch10: ; preds = %catch.start
129 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
130 %6 = bitcast i8* %5 to i32*
131 %7 = load i32, i32* %6, align 4
132 call void @__cxa_end_catch() [ "funclet"(token %1) ]
133 catchret from %1 to label %try.cont
134
135 try.cont: ; preds = %entry, %catch, %catch4, %catch7, %catch10
136 invoke void @may_throw()
137 to label %try.cont23 unwind label %catch.dispatch14
138
139 catch.dispatch14: ; preds = %try.cont
140 %8 = catchswitch within none [label %catch.start15] unwind to caller
141
142 catch.start15: ; preds = %catch.dispatch14
143 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTId to i8*), i8* null]
144 %10 = call i8* @llvm.wasm.get.exception(token %9)
145 %11 = call i32 @llvm.wasm.get.ehselector(token %9)
146 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*))
147 %matches16 = icmp eq i32 %11, %12
148 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ]
149 br i1 %matches16, label %catch20, label %catch17
150
151 catch20: ; preds = %catch.start15
152 %14 = bitcast i8* %13 to double*
153 %15 = load double, double* %14, align 8
154 call void @__cxa_end_catch() [ "funclet"(token %9) ]
155 catchret from %9 to label %try.cont23
156
157 try.cont23: ; preds = %try.cont, %catch17, %catch20
158 invoke void @may_throw()
159 to label %try.cont36 unwind label %catch.dispatch25
160
161 catch.dispatch25: ; preds = %try.cont23
162 %16 = catchswitch within none [label %catch.start26] unwind to caller
163
164 catch.start26: ; preds = %catch.dispatch25
165 %17 = catchpad within %16 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIf to i8*)]
166 %18 = call i8* @llvm.wasm.get.exception(token %17)
167 %19 = call i32 @llvm.wasm.get.ehselector(token %17)
168 %20 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
169 %matches27 = icmp eq i32 %19, %20
170 br i1 %matches27, label %catch33, label %catch.fallthrough28
171
172 catch33: ; preds = %catch.start26
173 %21 = call i8* @__cxa_begin_catch(i8* %18) [ "funclet"(token %17) ]
174 %22 = bitcast i8* %21 to i32*
175 %23 = load i32, i32* %22, align 4
176 call void @__cxa_end_catch() [ "funclet"(token %17) ]
177 catchret from %17 to label %try.cont36
178
179 catch.fallthrough28: ; preds = %catch.start26
180 %24 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*))
181 %matches29 = icmp eq i32 %19, %24
182 br i1 %matches29, label %catch30, label %rethrow
183
184 catch30: ; preds = %catch.fallthrough28
185 %25 = call i8* @__cxa_begin_catch(i8* %18) [ "funclet"(token %17) ]
186 %26 = bitcast i8* %25 to float*
187 %27 = load float, float* %26, align 4
188 call void @__cxa_end_catch() [ "funclet"(token %17) ]
189 catchret from %17 to label %try.cont36
190
191 rethrow: ; preds = %catch.fallthrough28
192 call void @__cxa_rethrow() [ "funclet"(token %17) ]
193 unreachable
194
195 try.cont36: ; preds = %try.cont23, %catch30, %catch33
196 ret void
197
198 catch17: ; preds = %catch.start15
199 call void @__cxa_end_catch() [ "funclet"(token %9) ]
200 catchret from %9 to label %try.cont23
201
202 catch.fallthrough: ; preds = %catch.start
203 %28 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*))
204 %matches1 = icmp eq i32 %3, %28
205 br i1 %matches1, label %catch7, label %catch.fallthrough2
206
207 catch7: ; preds = %catch.fallthrough
208 %29 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
209 %30 = bitcast i8* %29 to float*
210 %31 = load float, float* %30, align 4
211 call void @__cxa_end_catch() [ "funclet"(token %1) ]
212 catchret from %1 to label %try.cont
213
214 catch.fallthrough2: ; preds = %catch.fallthrough
215 %32 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*))
216 %matches3 = icmp eq i32 %3, %32
217 %33 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
218 br i1 %matches3, label %catch4, label %catch
219
220 catch4: ; preds = %catch.fallthrough2
221 %34 = bitcast i8* %33 to double*
222 %35 = load double, double* %34, align 8
223 call void @__cxa_end_catch() [ "funclet"(token %1) ]
224 catchret from %1 to label %try.cont
225
226 catch: ; preds = %catch.fallthrough2
227 call void @__cxa_end_catch() [ "funclet"(token %1) ]
228 catchret from %1 to label %try.cont
229 }
230
231 declare void @may_throw()
232 declare i32 @llvm.eh.typeid.for(i8*)
233 declare i8* @llvm.wasm.get.exception(token)
234 declare i32 @llvm.wasm.get.ehselector(token)
235 declare void @__cxa_rethrow()
236 declare i8* @__cxa_begin_catch(i8*)
237 declare void @__cxa_end_catch()
238 declare i32 @__gxx_wasm_personality_v0(...)
2929 ; CHECK: catch.start:
3030 ; CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad
3131 ; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.catch(i32 0)
32 ; CHECK-NEXT: call void @llvm.wasm.landingpad.index(i32 0)
32 ; CHECK-NEXT: call void @llvm.wasm.landingpad.index(token %[[CATCHPAD]], i32 0)
3333 ; CHECK-NEXT: store i32 0, i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)
3434 ; CHECK-NEXT: %[[LSDA:.*]] = call i8* @llvm.wasm.lsda()
3535 ; CHECK-NEXT: store i8* %[[LSDA]], i8** getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 1)
9797 %matches = icmp eq i32 %8, %9
9898 br i1 %matches, label %catch4, label %rethrow
9999 ; CHECK: catch.start3:
100 ; CHECK: call void @llvm.wasm.landingpad.index(i32 0)
100 ; CHECK: call void @llvm.wasm.landingpad.index(token %{{.+}}, i32 0)
101101
102102 catch4: ; preds = %catch.start3
103103 %10 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
310310 declare void @__clang_call_terminate(i8*)
311311
312312 ; CHECK-DAG: declare i8* @llvm.wasm.catch(i32)
313 ; CHECK-DAG: declare void @llvm.wasm.landingpad.index(i32)
313 ; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32)
314314 ; CHECK-DAG: declare i8* @llvm.wasm.lsda()
315315 ; CHECK-DAG: declare i32 @_Unwind_CallPersonality(i8*)
316316