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