xref: /src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1b915e9e0SDimitry Andric //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2b915e9e0SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b915e9e0SDimitry Andric //
7b915e9e0SDimitry Andric //===----------------------------------------------------------------------===//
8b915e9e0SDimitry Andric ///
9b915e9e0SDimitry Andric /// \file
10eb11fae6SDimitry Andric /// This file implements several utility functions for WebAssembly.
11b915e9e0SDimitry Andric ///
12b915e9e0SDimitry Andric //===----------------------------------------------------------------------===//
13b915e9e0SDimitry Andric 
14b915e9e0SDimitry Andric #include "WebAssemblyUtilities.h"
15b915e9e0SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
16ac9a064cSDimitry Andric #include "WebAssemblyTargetMachine.h"
17b915e9e0SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
1871d5a254SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
19b1c73532SDimitry Andric #include "llvm/IR/Function.h"
20b60736ecSDimitry Andric #include "llvm/MC/MCContext.h"
21b915e9e0SDimitry Andric using namespace llvm;
22b915e9e0SDimitry Andric 
2377fc4c14SDimitry Andric // Function names in libc++abi and libunwind
24eb11fae6SDimitry Andric const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
25eb11fae6SDimitry Andric const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
26eb11fae6SDimitry Andric const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
27eb11fae6SDimitry Andric const char *const WebAssembly::PersonalityWrapperFn =
28eb11fae6SDimitry Andric     "_Unwind_Wasm_CallPersonality";
29eb11fae6SDimitry Andric 
30b915e9e0SDimitry Andric /// Test whether MI is a child of some other node in an expression tree.
isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)31b915e9e0SDimitry Andric bool WebAssembly::isChild(const MachineInstr &MI,
32b915e9e0SDimitry Andric                           const WebAssemblyFunctionInfo &MFI) {
33b915e9e0SDimitry Andric   if (MI.getNumOperands() == 0)
34b915e9e0SDimitry Andric     return false;
35b915e9e0SDimitry Andric   const MachineOperand &MO = MI.getOperand(0);
36b915e9e0SDimitry Andric   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
37b915e9e0SDimitry Andric     return false;
381d5ae102SDimitry Andric   Register Reg = MO.getReg();
39e3b55780SDimitry Andric   return Reg.isVirtual() && MFI.isVRegStackified(Reg);
40b915e9e0SDimitry Andric }
4171d5a254SDimitry Andric 
mayThrow(const MachineInstr & MI)42eb11fae6SDimitry Andric bool WebAssembly::mayThrow(const MachineInstr &MI) {
43eb11fae6SDimitry Andric   switch (MI.getOpcode()) {
44e6d15924SDimitry Andric   case WebAssembly::THROW:
45e6d15924SDimitry Andric   case WebAssembly::THROW_S:
46eb11fae6SDimitry Andric   case WebAssembly::RETHROW:
47d8e91e46SDimitry Andric   case WebAssembly::RETHROW_S:
48eb11fae6SDimitry Andric     return true;
49eb11fae6SDimitry Andric   }
50e6d15924SDimitry Andric   if (isCallIndirect(MI.getOpcode()))
51eb11fae6SDimitry Andric     return true;
52eb11fae6SDimitry Andric   if (!MI.isCall())
53eb11fae6SDimitry Andric     return false;
54eb11fae6SDimitry Andric 
55cfca06d7SDimitry Andric   const MachineOperand &MO = getCalleeOp(MI);
561d5ae102SDimitry Andric   assert(MO.isGlobal() || MO.isSymbol());
571d5ae102SDimitry Andric 
581d5ae102SDimitry Andric   if (MO.isSymbol()) {
591d5ae102SDimitry Andric     // Some intrinsics are lowered to calls to external symbols, which are then
601d5ae102SDimitry Andric     // lowered to calls to library functions. Most of libcalls don't throw, but
611d5ae102SDimitry Andric     // we only list some of them here now.
621d5ae102SDimitry Andric     // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
631d5ae102SDimitry Andric     // instead for more accurate info.
641d5ae102SDimitry Andric     const char *Name = MO.getSymbolName();
651d5ae102SDimitry Andric     if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
661d5ae102SDimitry Andric         strcmp(Name, "memset") == 0)
671d5ae102SDimitry Andric       return false;
681d5ae102SDimitry Andric     return true;
691d5ae102SDimitry Andric   }
701d5ae102SDimitry Andric 
71eb11fae6SDimitry Andric   const auto *F = dyn_cast<Function>(MO.getGlobal());
72eb11fae6SDimitry Andric   if (!F)
73eb11fae6SDimitry Andric     return true;
74eb11fae6SDimitry Andric   if (F->doesNotThrow())
75eb11fae6SDimitry Andric     return false;
76eb11fae6SDimitry Andric   // These functions never throw
77eb11fae6SDimitry Andric   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
78344a3780SDimitry Andric       F->getName() == StdTerminateFn)
79eb11fae6SDimitry Andric     return false;
80eb11fae6SDimitry Andric 
81e6d15924SDimitry Andric   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
82e6d15924SDimitry Andric   // original LLVm IR? (Even when the callee may throw)
83eb11fae6SDimitry Andric   return true;
84eb11fae6SDimitry Andric }
85cfca06d7SDimitry Andric 
getCalleeOp(const MachineInstr & MI)86cfca06d7SDimitry Andric const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
87cfca06d7SDimitry Andric   switch (MI.getOpcode()) {
88cfca06d7SDimitry Andric   case WebAssembly::CALL:
89cfca06d7SDimitry Andric   case WebAssembly::CALL_S:
90cfca06d7SDimitry Andric   case WebAssembly::RET_CALL:
91cfca06d7SDimitry Andric   case WebAssembly::RET_CALL_S:
92cfca06d7SDimitry Andric     return MI.getOperand(MI.getNumExplicitDefs());
93cfca06d7SDimitry Andric   case WebAssembly::CALL_INDIRECT:
94cfca06d7SDimitry Andric   case WebAssembly::CALL_INDIRECT_S:
95cfca06d7SDimitry Andric   case WebAssembly::RET_CALL_INDIRECT:
96cfca06d7SDimitry Andric   case WebAssembly::RET_CALL_INDIRECT_S:
97344a3780SDimitry Andric     return MI.getOperand(MI.getNumExplicitOperands() - 1);
98cfca06d7SDimitry Andric   default:
99cfca06d7SDimitry Andric     llvm_unreachable("Not a call instruction");
100cfca06d7SDimitry Andric   }
101cfca06d7SDimitry Andric }
102b60736ecSDimitry Andric 
getOrCreateFunctionTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)103344a3780SDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
104344a3780SDimitry Andric     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
105344a3780SDimitry Andric   StringRef Name = "__indirect_function_table";
106b60736ecSDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
107b60736ecSDimitry Andric   if (Sym) {
108b60736ecSDimitry Andric     if (!Sym->isFunctionTable())
109b60736ecSDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
110b60736ecSDimitry Andric   } else {
111ac9a064cSDimitry Andric     bool is64 = Subtarget && Subtarget->getTargetTriple().isArch64Bit();
112b60736ecSDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
113ac9a064cSDimitry Andric     Sym->setFunctionTable(is64);
114b60736ecSDimitry Andric     // The default function table is synthesized by the linker.
115b60736ecSDimitry Andric     Sym->setUndefined();
116b60736ecSDimitry Andric   }
117344a3780SDimitry Andric   // MVP object files can't have symtab entries for tables.
118344a3780SDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
119344a3780SDimitry Andric     Sym->setOmitFromLinkingSection();
120344a3780SDimitry Andric   return Sym;
121344a3780SDimitry Andric }
122344a3780SDimitry Andric 
getOrCreateFuncrefCallTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)123344a3780SDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
124344a3780SDimitry Andric     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
125344a3780SDimitry Andric   StringRef Name = "__funcref_call_table";
126344a3780SDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
127344a3780SDimitry Andric   if (Sym) {
128344a3780SDimitry Andric     if (!Sym->isFunctionTable())
129344a3780SDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
130344a3780SDimitry Andric   } else {
131344a3780SDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
132344a3780SDimitry Andric 
133344a3780SDimitry Andric     // Setting Weak ensure only one table is left after linking when multiple
134344a3780SDimitry Andric     // modules define the table.
135344a3780SDimitry Andric     Sym->setWeak(true);
136344a3780SDimitry Andric 
137344a3780SDimitry Andric     wasm::WasmLimits Limits = {0, 1, 1};
1384df029ccSDimitry Andric     wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits};
139344a3780SDimitry Andric     Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
140344a3780SDimitry Andric     Sym->setTableType(TableType);
141344a3780SDimitry Andric   }
142344a3780SDimitry Andric   // MVP object files can't have symtab entries for tables.
143344a3780SDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
144344a3780SDimitry Andric     Sym->setOmitFromLinkingSection();
145b60736ecSDimitry Andric   return Sym;
146b60736ecSDimitry Andric }
147b60736ecSDimitry Andric 
148b60736ecSDimitry Andric // Find a catch instruction from an EH pad.
findCatch(MachineBasicBlock * EHPad)149b60736ecSDimitry Andric MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
150b60736ecSDimitry Andric   assert(EHPad->isEHPad());
151b60736ecSDimitry Andric   auto Pos = EHPad->begin();
152b60736ecSDimitry Andric   // Skip any label or debug instructions. Also skip 'end' marker instructions
153b60736ecSDimitry Andric   // that may exist after marker placement in CFGStackify.
154b60736ecSDimitry Andric   while (Pos != EHPad->end() &&
155b60736ecSDimitry Andric          (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
156b60736ecSDimitry Andric     Pos++;
157b60736ecSDimitry Andric   if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
158b60736ecSDimitry Andric     return &*Pos;
159b60736ecSDimitry Andric   return nullptr;
160b60736ecSDimitry Andric }
1611f917f69SDimitry Andric 
getCopyOpcodeForRegClass(const TargetRegisterClass * RC)1621f917f69SDimitry Andric unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
1631f917f69SDimitry Andric   assert(RC != nullptr);
1641f917f69SDimitry Andric   switch (RC->getID()) {
1651f917f69SDimitry Andric   case WebAssembly::I32RegClassID:
1661f917f69SDimitry Andric     return WebAssembly::COPY_I32;
1671f917f69SDimitry Andric   case WebAssembly::I64RegClassID:
1681f917f69SDimitry Andric     return WebAssembly::COPY_I64;
1691f917f69SDimitry Andric   case WebAssembly::F32RegClassID:
1701f917f69SDimitry Andric     return WebAssembly::COPY_F32;
1711f917f69SDimitry Andric   case WebAssembly::F64RegClassID:
1721f917f69SDimitry Andric     return WebAssembly::COPY_F64;
1731f917f69SDimitry Andric   case WebAssembly::V128RegClassID:
1741f917f69SDimitry Andric     return WebAssembly::COPY_V128;
1751f917f69SDimitry Andric   case WebAssembly::FUNCREFRegClassID:
1761f917f69SDimitry Andric     return WebAssembly::COPY_FUNCREF;
1771f917f69SDimitry Andric   case WebAssembly::EXTERNREFRegClassID:
1781f917f69SDimitry Andric     return WebAssembly::COPY_EXTERNREF;
179ac9a064cSDimitry Andric   case WebAssembly::EXNREFRegClassID:
180ac9a064cSDimitry Andric     return WebAssembly::COPY_EXNREF;
1811f917f69SDimitry Andric   default:
1821f917f69SDimitry Andric     llvm_unreachable("Unexpected register class");
1831f917f69SDimitry Andric   }
1841f917f69SDimitry Andric }
185ac9a064cSDimitry Andric 
canLowerMultivalueReturn(const WebAssemblySubtarget * Subtarget)186ac9a064cSDimitry Andric bool WebAssembly::canLowerMultivalueReturn(
187ac9a064cSDimitry Andric     const WebAssemblySubtarget *Subtarget) {
188ac9a064cSDimitry Andric   const auto &TM = static_cast<const WebAssemblyTargetMachine &>(
189ac9a064cSDimitry Andric       Subtarget->getTargetLowering()->getTargetMachine());
190ac9a064cSDimitry Andric   return Subtarget->hasMultivalue() && TM.usesMultivalueABI();
191ac9a064cSDimitry Andric }
192ac9a064cSDimitry Andric 
canLowerReturn(size_t ResultSize,const WebAssemblySubtarget * Subtarget)193ac9a064cSDimitry Andric bool WebAssembly::canLowerReturn(size_t ResultSize,
194ac9a064cSDimitry Andric                                  const WebAssemblySubtarget *Subtarget) {
195ac9a064cSDimitry Andric   return ResultSize <= 1 || canLowerMultivalueReturn(Subtarget);
196ac9a064cSDimitry Andric }
197