10b2bc69bSHeejin Ahn //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
20b2bc69bSHeejin Ahn //
30b2bc69bSHeejin Ahn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b2bc69bSHeejin Ahn // See https://llvm.org/LICENSE.txt for license information.
50b2bc69bSHeejin Ahn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b2bc69bSHeejin Ahn //
70b2bc69bSHeejin Ahn //===----------------------------------------------------------------------===//
80b2bc69bSHeejin Ahn ///
90b2bc69bSHeejin Ahn /// \file
100b2bc69bSHeejin Ahn /// This file implements several utility functions for WebAssembly.
110b2bc69bSHeejin Ahn ///
120b2bc69bSHeejin Ahn //===----------------------------------------------------------------------===//
130b2bc69bSHeejin Ahn
140b2bc69bSHeejin Ahn #include "WebAssemblyUtilities.h"
150b2bc69bSHeejin Ahn #include "WebAssemblyMachineFunctionInfo.h"
160b2bc69bSHeejin Ahn #include "llvm/CodeGen/MachineInstr.h"
170b2bc69bSHeejin Ahn #include "llvm/CodeGen/MachineLoopInfo.h"
180b2bc69bSHeejin Ahn #include "llvm/MC/MCContext.h"
190b2bc69bSHeejin Ahn using namespace llvm;
200b2bc69bSHeejin Ahn
214625b848SHeejin Ahn // Exception handling & setjmp-longjmp handling related options. These are
224625b848SHeejin Ahn // defined here to be shared between WebAssembly and its subdirectories.
234625b848SHeejin Ahn
244625b848SHeejin Ahn // Emscripten's asm.js-style exception handling
254625b848SHeejin Ahn cl::opt<bool> WebAssembly::WasmEnableEmEH(
264625b848SHeejin Ahn "enable-emscripten-cxx-exceptions",
274625b848SHeejin Ahn cl::desc("WebAssembly Emscripten-style exception handling"),
284625b848SHeejin Ahn cl::init(false));
294625b848SHeejin Ahn // Emscripten's asm.js-style setjmp/longjmp handling
304625b848SHeejin Ahn cl::opt<bool> WebAssembly::WasmEnableEmSjLj(
314625b848SHeejin Ahn "enable-emscripten-sjlj",
324625b848SHeejin Ahn cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
334625b848SHeejin Ahn cl::init(false));
344625b848SHeejin Ahn // Exception handling using wasm EH instructions
354625b848SHeejin Ahn cl::opt<bool>
364625b848SHeejin Ahn WebAssembly::WasmEnableEH("wasm-enable-eh",
374625b848SHeejin Ahn cl::desc("WebAssembly exception handling"),
384625b848SHeejin Ahn cl::init(false));
394625b848SHeejin Ahn // setjmp/longjmp handling using wasm EH instrutions
404625b848SHeejin Ahn cl::opt<bool>
414625b848SHeejin Ahn WebAssembly::WasmEnableSjLj("wasm-enable-sjlj",
424625b848SHeejin Ahn cl::desc("WebAssembly setjmp/longjmp handling"),
434625b848SHeejin Ahn cl::init(false));
444625b848SHeejin Ahn
454625b848SHeejin Ahn // Function names in libc++abi and libunwind
460b2bc69bSHeejin Ahn const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
470b2bc69bSHeejin Ahn const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
480b2bc69bSHeejin Ahn const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
490b2bc69bSHeejin Ahn const char *const WebAssembly::PersonalityWrapperFn =
500b2bc69bSHeejin Ahn "_Unwind_Wasm_CallPersonality";
510b2bc69bSHeejin Ahn
520b2bc69bSHeejin Ahn /// Test whether MI is a child of some other node in an expression tree.
isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)530b2bc69bSHeejin Ahn bool WebAssembly::isChild(const MachineInstr &MI,
540b2bc69bSHeejin Ahn const WebAssemblyFunctionInfo &MFI) {
550b2bc69bSHeejin Ahn if (MI.getNumOperands() == 0)
560b2bc69bSHeejin Ahn return false;
570b2bc69bSHeejin Ahn const MachineOperand &MO = MI.getOperand(0);
580b2bc69bSHeejin Ahn if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
590b2bc69bSHeejin Ahn return false;
600b2bc69bSHeejin Ahn Register Reg = MO.getReg();
610b2bc69bSHeejin Ahn return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
620b2bc69bSHeejin Ahn }
630b2bc69bSHeejin Ahn
mayThrow(const MachineInstr & MI)640b2bc69bSHeejin Ahn bool WebAssembly::mayThrow(const MachineInstr &MI) {
650b2bc69bSHeejin Ahn switch (MI.getOpcode()) {
660b2bc69bSHeejin Ahn case WebAssembly::THROW:
670b2bc69bSHeejin Ahn case WebAssembly::THROW_S:
680b2bc69bSHeejin Ahn case WebAssembly::RETHROW:
690b2bc69bSHeejin Ahn case WebAssembly::RETHROW_S:
700b2bc69bSHeejin Ahn return true;
710b2bc69bSHeejin Ahn }
720b2bc69bSHeejin Ahn if (isCallIndirect(MI.getOpcode()))
730b2bc69bSHeejin Ahn return true;
740b2bc69bSHeejin Ahn if (!MI.isCall())
750b2bc69bSHeejin Ahn return false;
760b2bc69bSHeejin Ahn
770b2bc69bSHeejin Ahn const MachineOperand &MO = getCalleeOp(MI);
780b2bc69bSHeejin Ahn assert(MO.isGlobal() || MO.isSymbol());
790b2bc69bSHeejin Ahn
800b2bc69bSHeejin Ahn if (MO.isSymbol()) {
810b2bc69bSHeejin Ahn // Some intrinsics are lowered to calls to external symbols, which are then
820b2bc69bSHeejin Ahn // lowered to calls to library functions. Most of libcalls don't throw, but
830b2bc69bSHeejin Ahn // we only list some of them here now.
840b2bc69bSHeejin Ahn // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
850b2bc69bSHeejin Ahn // instead for more accurate info.
860b2bc69bSHeejin Ahn const char *Name = MO.getSymbolName();
870b2bc69bSHeejin Ahn if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
880b2bc69bSHeejin Ahn strcmp(Name, "memset") == 0)
890b2bc69bSHeejin Ahn return false;
900b2bc69bSHeejin Ahn return true;
910b2bc69bSHeejin Ahn }
920b2bc69bSHeejin Ahn
930b2bc69bSHeejin Ahn const auto *F = dyn_cast<Function>(MO.getGlobal());
940b2bc69bSHeejin Ahn if (!F)
950b2bc69bSHeejin Ahn return true;
960b2bc69bSHeejin Ahn if (F->doesNotThrow())
970b2bc69bSHeejin Ahn return false;
980b2bc69bSHeejin Ahn // These functions never throw
990b2bc69bSHeejin Ahn if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
1000b2bc69bSHeejin Ahn F->getName() == StdTerminateFn)
1010b2bc69bSHeejin Ahn return false;
1020b2bc69bSHeejin Ahn
1030b2bc69bSHeejin Ahn // TODO Can we exclude call instructions that are marked as 'nounwind' in the
1040b2bc69bSHeejin Ahn // original LLVm IR? (Even when the callee may throw)
1050b2bc69bSHeejin Ahn return true;
1060b2bc69bSHeejin Ahn }
1070b2bc69bSHeejin Ahn
getCalleeOp(const MachineInstr & MI)1080b2bc69bSHeejin Ahn const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
1090b2bc69bSHeejin Ahn switch (MI.getOpcode()) {
1100b2bc69bSHeejin Ahn case WebAssembly::CALL:
1110b2bc69bSHeejin Ahn case WebAssembly::CALL_S:
1120b2bc69bSHeejin Ahn case WebAssembly::RET_CALL:
1130b2bc69bSHeejin Ahn case WebAssembly::RET_CALL_S:
1140b2bc69bSHeejin Ahn return MI.getOperand(MI.getNumExplicitDefs());
1150b2bc69bSHeejin Ahn case WebAssembly::CALL_INDIRECT:
1160b2bc69bSHeejin Ahn case WebAssembly::CALL_INDIRECT_S:
1170b2bc69bSHeejin Ahn case WebAssembly::RET_CALL_INDIRECT:
1180b2bc69bSHeejin Ahn case WebAssembly::RET_CALL_INDIRECT_S:
1195dd86aadSHeejin Ahn return MI.getOperand(MI.getNumExplicitOperands() - 1);
1200b2bc69bSHeejin Ahn default:
1210b2bc69bSHeejin Ahn llvm_unreachable("Not a call instruction");
1220b2bc69bSHeejin Ahn }
1230b2bc69bSHeejin Ahn }
1240b2bc69bSHeejin Ahn
getOrCreateFunctionTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)1250b2bc69bSHeejin Ahn MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
1260b2bc69bSHeejin Ahn MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
1270b2bc69bSHeejin Ahn StringRef Name = "__indirect_function_table";
1280b2bc69bSHeejin Ahn MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
1290b2bc69bSHeejin Ahn if (Sym) {
1300b2bc69bSHeejin Ahn if (!Sym->isFunctionTable())
1310b2bc69bSHeejin Ahn Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
1320b2bc69bSHeejin Ahn } else {
1330b2bc69bSHeejin Ahn Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
1340b2bc69bSHeejin Ahn Sym->setFunctionTable();
1350b2bc69bSHeejin Ahn // The default function table is synthesized by the linker.
1360b2bc69bSHeejin Ahn Sym->setUndefined();
1370b2bc69bSHeejin Ahn }
1380b2bc69bSHeejin Ahn // MVP object files can't have symtab entries for tables.
1390b2bc69bSHeejin Ahn if (!(Subtarget && Subtarget->hasReferenceTypes()))
1400b2bc69bSHeejin Ahn Sym->setOmitFromLinkingSection();
1410b2bc69bSHeejin Ahn return Sym;
1420b2bc69bSHeejin Ahn }
1430b2bc69bSHeejin Ahn
getOrCreateFuncrefCallTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)14446667a10SPaulo Matos MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
14546667a10SPaulo Matos MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
14646667a10SPaulo Matos StringRef Name = "__funcref_call_table";
14746667a10SPaulo Matos MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
14846667a10SPaulo Matos if (Sym) {
14946667a10SPaulo Matos if (!Sym->isFunctionTable())
15046667a10SPaulo Matos Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
15146667a10SPaulo Matos } else {
15246667a10SPaulo Matos Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
15346667a10SPaulo Matos
15446667a10SPaulo Matos // Setting Weak ensure only one table is left after linking when multiple
15546667a10SPaulo Matos // modules define the table.
15646667a10SPaulo Matos Sym->setWeak(true);
15746667a10SPaulo Matos
15846667a10SPaulo Matos wasm::WasmLimits Limits = {0, 1, 1};
15946667a10SPaulo Matos wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
16046667a10SPaulo Matos Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
16146667a10SPaulo Matos Sym->setTableType(TableType);
16246667a10SPaulo Matos }
16346667a10SPaulo Matos // MVP object files can't have symtab entries for tables.
16446667a10SPaulo Matos if (!(Subtarget && Subtarget->hasReferenceTypes()))
16546667a10SPaulo Matos Sym->setOmitFromLinkingSection();
16646667a10SPaulo Matos return Sym;
16746667a10SPaulo Matos }
16846667a10SPaulo Matos
1690b2bc69bSHeejin Ahn // Find a catch instruction from an EH pad.
findCatch(MachineBasicBlock * EHPad)1700b2bc69bSHeejin Ahn MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
1710b2bc69bSHeejin Ahn assert(EHPad->isEHPad());
1720b2bc69bSHeejin Ahn auto Pos = EHPad->begin();
1730b2bc69bSHeejin Ahn // Skip any label or debug instructions. Also skip 'end' marker instructions
1740b2bc69bSHeejin Ahn // that may exist after marker placement in CFGStackify.
1750b2bc69bSHeejin Ahn while (Pos != EHPad->end() &&
1760b2bc69bSHeejin Ahn (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
1770b2bc69bSHeejin Ahn Pos++;
1780b2bc69bSHeejin Ahn if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
1790b2bc69bSHeejin Ahn return &*Pos;
1800b2bc69bSHeejin Ahn return nullptr;
1810b2bc69bSHeejin Ahn }
182*beec3e8cSAlex Bradbury
getCopyOpcodeForRegClass(const TargetRegisterClass * RC)183*beec3e8cSAlex Bradbury unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
184*beec3e8cSAlex Bradbury assert(RC != nullptr);
185*beec3e8cSAlex Bradbury switch (RC->getID()) {
186*beec3e8cSAlex Bradbury case WebAssembly::I32RegClassID:
187*beec3e8cSAlex Bradbury return WebAssembly::COPY_I32;
188*beec3e8cSAlex Bradbury case WebAssembly::I64RegClassID:
189*beec3e8cSAlex Bradbury return WebAssembly::COPY_I64;
190*beec3e8cSAlex Bradbury case WebAssembly::F32RegClassID:
191*beec3e8cSAlex Bradbury return WebAssembly::COPY_F32;
192*beec3e8cSAlex Bradbury case WebAssembly::F64RegClassID:
193*beec3e8cSAlex Bradbury return WebAssembly::COPY_F64;
194*beec3e8cSAlex Bradbury case WebAssembly::V128RegClassID:
195*beec3e8cSAlex Bradbury return WebAssembly::COPY_V128;
196*beec3e8cSAlex Bradbury case WebAssembly::FUNCREFRegClassID:
197*beec3e8cSAlex Bradbury return WebAssembly::COPY_FUNCREF;
198*beec3e8cSAlex Bradbury case WebAssembly::EXTERNREFRegClassID:
199*beec3e8cSAlex Bradbury return WebAssembly::COPY_EXTERNREF;
200*beec3e8cSAlex Bradbury default:
201*beec3e8cSAlex Bradbury llvm_unreachable("Unexpected register class");
202*beec3e8cSAlex Bradbury }
203*beec3e8cSAlex Bradbury }
204