1 //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements several utility functions for WebAssembly.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "WebAssemblyUtilities.h"
15 #include "WebAssemblyMachineFunctionInfo.h"
16 #include "llvm/CodeGen/MachineInstr.h"
17 #include "llvm/CodeGen/MachineLoopInfo.h"
18 #include "llvm/MC/MCContext.h"
19 using namespace llvm;
20
21 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
22 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
23 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
24 const char *const WebAssembly::PersonalityWrapperFn =
25 "_Unwind_Wasm_CallPersonality";
26
27 /// Test whether MI is a child of some other node in an expression tree.
isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)28 bool WebAssembly::isChild(const MachineInstr &MI,
29 const WebAssemblyFunctionInfo &MFI) {
30 if (MI.getNumOperands() == 0)
31 return false;
32 const MachineOperand &MO = MI.getOperand(0);
33 if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
34 return false;
35 Register Reg = MO.getReg();
36 return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
37 }
38
mayThrow(const MachineInstr & MI)39 bool WebAssembly::mayThrow(const MachineInstr &MI) {
40 switch (MI.getOpcode()) {
41 case WebAssembly::THROW:
42 case WebAssembly::THROW_S:
43 case WebAssembly::RETHROW:
44 case WebAssembly::RETHROW_S:
45 return true;
46 }
47 if (isCallIndirect(MI.getOpcode()))
48 return true;
49 if (!MI.isCall())
50 return false;
51
52 const MachineOperand &MO = getCalleeOp(MI);
53 assert(MO.isGlobal() || MO.isSymbol());
54
55 if (MO.isSymbol()) {
56 // Some intrinsics are lowered to calls to external symbols, which are then
57 // lowered to calls to library functions. Most of libcalls don't throw, but
58 // we only list some of them here now.
59 // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
60 // instead for more accurate info.
61 const char *Name = MO.getSymbolName();
62 if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
63 strcmp(Name, "memset") == 0)
64 return false;
65 return true;
66 }
67
68 const auto *F = dyn_cast<Function>(MO.getGlobal());
69 if (!F)
70 return true;
71 if (F->doesNotThrow())
72 return false;
73 // These functions never throw
74 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
75 F->getName() == StdTerminateFn)
76 return false;
77
78 // TODO Can we exclude call instructions that are marked as 'nounwind' in the
79 // original LLVm IR? (Even when the callee may throw)
80 return true;
81 }
82
getCalleeOp(const MachineInstr & MI)83 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
84 switch (MI.getOpcode()) {
85 case WebAssembly::CALL:
86 case WebAssembly::CALL_S:
87 case WebAssembly::RET_CALL:
88 case WebAssembly::RET_CALL_S:
89 return MI.getOperand(MI.getNumExplicitDefs());
90 case WebAssembly::CALL_INDIRECT:
91 case WebAssembly::CALL_INDIRECT_S:
92 case WebAssembly::RET_CALL_INDIRECT:
93 case WebAssembly::RET_CALL_INDIRECT_S:
94 return MI.getOperand(MI.getNumOperands() - 1);
95 default:
96 llvm_unreachable("Not a call instruction");
97 }
98 }
99
getOrCreateFunctionTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)100 MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
101 MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
102 StringRef Name = "__indirect_function_table";
103 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
104 if (Sym) {
105 if (!Sym->isFunctionTable())
106 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
107 } else {
108 Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
109 Sym->setFunctionTable();
110 // The default function table is synthesized by the linker.
111 Sym->setUndefined();
112 }
113 // MVP object files can't have symtab entries for tables.
114 if (!(Subtarget && Subtarget->hasReferenceTypes()))
115 Sym->setOmitFromLinkingSection();
116 return Sym;
117 }
118
119 // Find a catch instruction from an EH pad.
findCatch(MachineBasicBlock * EHPad)120 MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
121 assert(EHPad->isEHPad());
122 auto Pos = EHPad->begin();
123 // Skip any label or debug instructions. Also skip 'end' marker instructions
124 // that may exist after marker placement in CFGStackify.
125 while (Pos != EHPad->end() &&
126 (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
127 Pos++;
128 if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
129 return &*Pos;
130 return nullptr;
131 }
132