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