xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric ///
9*5f757f3fSDimitry Andric /// \file
10*5f757f3fSDimitry Andric /// This file implements several utility functions for WebAssembly.
11*5f757f3fSDimitry Andric ///
12*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
13*5f757f3fSDimitry Andric 
14*5f757f3fSDimitry Andric #include "WebAssemblyUtilities.h"
15*5f757f3fSDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
16*5f757f3fSDimitry Andric #include "WebAssemblySubtarget.h"
17*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
18*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
19*5f757f3fSDimitry Andric #include "llvm/IR/Function.h"
20*5f757f3fSDimitry Andric #include "llvm/MC/MCContext.h"
21*5f757f3fSDimitry Andric using namespace llvm;
22*5f757f3fSDimitry Andric 
23*5f757f3fSDimitry Andric // Function names in libc++abi and libunwind
24*5f757f3fSDimitry Andric const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
25*5f757f3fSDimitry Andric const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
26*5f757f3fSDimitry Andric const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
27*5f757f3fSDimitry Andric const char *const WebAssembly::PersonalityWrapperFn =
28*5f757f3fSDimitry Andric     "_Unwind_Wasm_CallPersonality";
29*5f757f3fSDimitry Andric 
30*5f757f3fSDimitry Andric /// Test whether MI is a child of some other node in an expression tree.
31*5f757f3fSDimitry Andric bool WebAssembly::isChild(const MachineInstr &MI,
32*5f757f3fSDimitry Andric                           const WebAssemblyFunctionInfo &MFI) {
33*5f757f3fSDimitry Andric   if (MI.getNumOperands() == 0)
34*5f757f3fSDimitry Andric     return false;
35*5f757f3fSDimitry Andric   const MachineOperand &MO = MI.getOperand(0);
36*5f757f3fSDimitry Andric   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
37*5f757f3fSDimitry Andric     return false;
38*5f757f3fSDimitry Andric   Register Reg = MO.getReg();
39*5f757f3fSDimitry Andric   return Reg.isVirtual() && MFI.isVRegStackified(Reg);
40*5f757f3fSDimitry Andric }
41*5f757f3fSDimitry Andric 
42*5f757f3fSDimitry Andric bool WebAssembly::mayThrow(const MachineInstr &MI) {
43*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
44*5f757f3fSDimitry Andric   case WebAssembly::THROW:
45*5f757f3fSDimitry Andric   case WebAssembly::THROW_S:
46*5f757f3fSDimitry Andric   case WebAssembly::RETHROW:
47*5f757f3fSDimitry Andric   case WebAssembly::RETHROW_S:
48*5f757f3fSDimitry Andric     return true;
49*5f757f3fSDimitry Andric   }
50*5f757f3fSDimitry Andric   if (isCallIndirect(MI.getOpcode()))
51*5f757f3fSDimitry Andric     return true;
52*5f757f3fSDimitry Andric   if (!MI.isCall())
53*5f757f3fSDimitry Andric     return false;
54*5f757f3fSDimitry Andric 
55*5f757f3fSDimitry Andric   const MachineOperand &MO = getCalleeOp(MI);
56*5f757f3fSDimitry Andric   assert(MO.isGlobal() || MO.isSymbol());
57*5f757f3fSDimitry Andric 
58*5f757f3fSDimitry Andric   if (MO.isSymbol()) {
59*5f757f3fSDimitry Andric     // Some intrinsics are lowered to calls to external symbols, which are then
60*5f757f3fSDimitry Andric     // lowered to calls to library functions. Most of libcalls don't throw, but
61*5f757f3fSDimitry Andric     // we only list some of them here now.
62*5f757f3fSDimitry Andric     // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
63*5f757f3fSDimitry Andric     // instead for more accurate info.
64*5f757f3fSDimitry Andric     const char *Name = MO.getSymbolName();
65*5f757f3fSDimitry Andric     if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
66*5f757f3fSDimitry Andric         strcmp(Name, "memset") == 0)
67*5f757f3fSDimitry Andric       return false;
68*5f757f3fSDimitry Andric     return true;
69*5f757f3fSDimitry Andric   }
70*5f757f3fSDimitry Andric 
71*5f757f3fSDimitry Andric   const auto *F = dyn_cast<Function>(MO.getGlobal());
72*5f757f3fSDimitry Andric   if (!F)
73*5f757f3fSDimitry Andric     return true;
74*5f757f3fSDimitry Andric   if (F->doesNotThrow())
75*5f757f3fSDimitry Andric     return false;
76*5f757f3fSDimitry Andric   // These functions never throw
77*5f757f3fSDimitry Andric   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
78*5f757f3fSDimitry Andric       F->getName() == StdTerminateFn)
79*5f757f3fSDimitry Andric     return false;
80*5f757f3fSDimitry Andric 
81*5f757f3fSDimitry Andric   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
82*5f757f3fSDimitry Andric   // original LLVm IR? (Even when the callee may throw)
83*5f757f3fSDimitry Andric   return true;
84*5f757f3fSDimitry Andric }
85*5f757f3fSDimitry Andric 
86*5f757f3fSDimitry Andric const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
87*5f757f3fSDimitry Andric   switch (MI.getOpcode()) {
88*5f757f3fSDimitry Andric   case WebAssembly::CALL:
89*5f757f3fSDimitry Andric   case WebAssembly::CALL_S:
90*5f757f3fSDimitry Andric   case WebAssembly::RET_CALL:
91*5f757f3fSDimitry Andric   case WebAssembly::RET_CALL_S:
92*5f757f3fSDimitry Andric     return MI.getOperand(MI.getNumExplicitDefs());
93*5f757f3fSDimitry Andric   case WebAssembly::CALL_INDIRECT:
94*5f757f3fSDimitry Andric   case WebAssembly::CALL_INDIRECT_S:
95*5f757f3fSDimitry Andric   case WebAssembly::RET_CALL_INDIRECT:
96*5f757f3fSDimitry Andric   case WebAssembly::RET_CALL_INDIRECT_S:
97*5f757f3fSDimitry Andric     return MI.getOperand(MI.getNumExplicitOperands() - 1);
98*5f757f3fSDimitry Andric   default:
99*5f757f3fSDimitry Andric     llvm_unreachable("Not a call instruction");
100*5f757f3fSDimitry Andric   }
101*5f757f3fSDimitry Andric }
102*5f757f3fSDimitry Andric 
103*5f757f3fSDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
104*5f757f3fSDimitry Andric     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
105*5f757f3fSDimitry Andric   StringRef Name = "__indirect_function_table";
106*5f757f3fSDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
107*5f757f3fSDimitry Andric   if (Sym) {
108*5f757f3fSDimitry Andric     if (!Sym->isFunctionTable())
109*5f757f3fSDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
110*5f757f3fSDimitry Andric   } else {
111*5f757f3fSDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
112*5f757f3fSDimitry Andric     Sym->setFunctionTable();
113*5f757f3fSDimitry Andric     // The default function table is synthesized by the linker.
114*5f757f3fSDimitry Andric     Sym->setUndefined();
115*5f757f3fSDimitry Andric   }
116*5f757f3fSDimitry Andric   // MVP object files can't have symtab entries for tables.
117*5f757f3fSDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
118*5f757f3fSDimitry Andric     Sym->setOmitFromLinkingSection();
119*5f757f3fSDimitry Andric   return Sym;
120*5f757f3fSDimitry Andric }
121*5f757f3fSDimitry Andric 
122*5f757f3fSDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
123*5f757f3fSDimitry Andric     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
124*5f757f3fSDimitry Andric   StringRef Name = "__funcref_call_table";
125*5f757f3fSDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
126*5f757f3fSDimitry Andric   if (Sym) {
127*5f757f3fSDimitry Andric     if (!Sym->isFunctionTable())
128*5f757f3fSDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
129*5f757f3fSDimitry Andric   } else {
130*5f757f3fSDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
131*5f757f3fSDimitry Andric 
132*5f757f3fSDimitry Andric     // Setting Weak ensure only one table is left after linking when multiple
133*5f757f3fSDimitry Andric     // modules define the table.
134*5f757f3fSDimitry Andric     Sym->setWeak(true);
135*5f757f3fSDimitry Andric 
136*5f757f3fSDimitry Andric     wasm::WasmLimits Limits = {0, 1, 1};
137*5f757f3fSDimitry Andric     wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
138*5f757f3fSDimitry Andric     Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
139*5f757f3fSDimitry Andric     Sym->setTableType(TableType);
140*5f757f3fSDimitry Andric   }
141*5f757f3fSDimitry Andric   // MVP object files can't have symtab entries for tables.
142*5f757f3fSDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
143*5f757f3fSDimitry Andric     Sym->setOmitFromLinkingSection();
144*5f757f3fSDimitry Andric   return Sym;
145*5f757f3fSDimitry Andric }
146*5f757f3fSDimitry Andric 
147*5f757f3fSDimitry Andric // Find a catch instruction from an EH pad.
148*5f757f3fSDimitry Andric MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
149*5f757f3fSDimitry Andric   assert(EHPad->isEHPad());
150*5f757f3fSDimitry Andric   auto Pos = EHPad->begin();
151*5f757f3fSDimitry Andric   // Skip any label or debug instructions. Also skip 'end' marker instructions
152*5f757f3fSDimitry Andric   // that may exist after marker placement in CFGStackify.
153*5f757f3fSDimitry Andric   while (Pos != EHPad->end() &&
154*5f757f3fSDimitry Andric          (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
155*5f757f3fSDimitry Andric     Pos++;
156*5f757f3fSDimitry Andric   if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
157*5f757f3fSDimitry Andric     return &*Pos;
158*5f757f3fSDimitry Andric   return nullptr;
159*5f757f3fSDimitry Andric }
160*5f757f3fSDimitry Andric 
161*5f757f3fSDimitry Andric unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
162*5f757f3fSDimitry Andric   assert(RC != nullptr);
163*5f757f3fSDimitry Andric   switch (RC->getID()) {
164*5f757f3fSDimitry Andric   case WebAssembly::I32RegClassID:
165*5f757f3fSDimitry Andric     return WebAssembly::COPY_I32;
166*5f757f3fSDimitry Andric   case WebAssembly::I64RegClassID:
167*5f757f3fSDimitry Andric     return WebAssembly::COPY_I64;
168*5f757f3fSDimitry Andric   case WebAssembly::F32RegClassID:
169*5f757f3fSDimitry Andric     return WebAssembly::COPY_F32;
170*5f757f3fSDimitry Andric   case WebAssembly::F64RegClassID:
171*5f757f3fSDimitry Andric     return WebAssembly::COPY_F64;
172*5f757f3fSDimitry Andric   case WebAssembly::V128RegClassID:
173*5f757f3fSDimitry Andric     return WebAssembly::COPY_V128;
174*5f757f3fSDimitry Andric   case WebAssembly::FUNCREFRegClassID:
175*5f757f3fSDimitry Andric     return WebAssembly::COPY_FUNCREF;
176*5f757f3fSDimitry Andric   case WebAssembly::EXTERNREFRegClassID:
177*5f757f3fSDimitry Andric     return WebAssembly::COPY_EXTERNREF;
178*5f757f3fSDimitry Andric   default:
179*5f757f3fSDimitry Andric     llvm_unreachable("Unexpected register class");
180*5f757f3fSDimitry Andric   }
181*5f757f3fSDimitry Andric }
182