123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \file
- /// This file implements several utility functions for WebAssembly.
- ///
- //===----------------------------------------------------------------------===//
- #include "WebAssemblyUtilities.h"
- #include "WebAssemblyMachineFunctionInfo.h"
- #include "llvm/CodeGen/MachineInstr.h"
- #include "llvm/CodeGen/MachineLoopInfo.h"
- #include "llvm/MC/MCContext.h"
- using namespace llvm;
- // Exception handling & setjmp-longjmp handling related options. These are
- // defined here to be shared between WebAssembly and its subdirectories.
- // Emscripten's asm.js-style exception handling
- cl::opt<bool> WebAssembly::WasmEnableEmEH(
- "enable-emscripten-cxx-exceptions",
- cl::desc("WebAssembly Emscripten-style exception handling"),
- cl::init(false));
- // Emscripten's asm.js-style setjmp/longjmp handling
- cl::opt<bool> WebAssembly::WasmEnableEmSjLj(
- "enable-emscripten-sjlj",
- cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
- cl::init(false));
- // Exception handling using wasm EH instructions
- cl::opt<bool>
- WebAssembly::WasmEnableEH("wasm-enable-eh",
- cl::desc("WebAssembly exception handling"),
- cl::init(false));
- // setjmp/longjmp handling using wasm EH instrutions
- cl::opt<bool>
- WebAssembly::WasmEnableSjLj("wasm-enable-sjlj",
- cl::desc("WebAssembly setjmp/longjmp handling"),
- cl::init(false));
- // Function names in libc++abi and libunwind
- const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
- const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
- const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
- const char *const WebAssembly::PersonalityWrapperFn =
- "_Unwind_Wasm_CallPersonality";
- /// Test whether MI is a child of some other node in an expression tree.
- bool WebAssembly::isChild(const MachineInstr &MI,
- const WebAssemblyFunctionInfo &MFI) {
- if (MI.getNumOperands() == 0)
- return false;
- const MachineOperand &MO = MI.getOperand(0);
- if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
- return false;
- Register Reg = MO.getReg();
- return Reg.isVirtual() && MFI.isVRegStackified(Reg);
- }
- bool WebAssembly::mayThrow(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- case WebAssembly::THROW:
- case WebAssembly::THROW_S:
- case WebAssembly::RETHROW:
- case WebAssembly::RETHROW_S:
- return true;
- }
- if (isCallIndirect(MI.getOpcode()))
- return true;
- if (!MI.isCall())
- return false;
- const MachineOperand &MO = getCalleeOp(MI);
- assert(MO.isGlobal() || MO.isSymbol());
- if (MO.isSymbol()) {
- // Some intrinsics are lowered to calls to external symbols, which are then
- // lowered to calls to library functions. Most of libcalls don't throw, but
- // we only list some of them here now.
- // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
- // instead for more accurate info.
- const char *Name = MO.getSymbolName();
- if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
- strcmp(Name, "memset") == 0)
- return false;
- return true;
- }
- const auto *F = dyn_cast<Function>(MO.getGlobal());
- if (!F)
- return true;
- if (F->doesNotThrow())
- return false;
- // These functions never throw
- if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
- F->getName() == StdTerminateFn)
- return false;
- // TODO Can we exclude call instructions that are marked as 'nounwind' in the
- // original LLVm IR? (Even when the callee may throw)
- return true;
- }
- const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- case WebAssembly::CALL:
- case WebAssembly::CALL_S:
- case WebAssembly::RET_CALL:
- case WebAssembly::RET_CALL_S:
- return MI.getOperand(MI.getNumExplicitDefs());
- case WebAssembly::CALL_INDIRECT:
- case WebAssembly::CALL_INDIRECT_S:
- case WebAssembly::RET_CALL_INDIRECT:
- case WebAssembly::RET_CALL_INDIRECT_S:
- return MI.getOperand(MI.getNumExplicitOperands() - 1);
- default:
- llvm_unreachable("Not a call instruction");
- }
- }
- MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
- MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
- StringRef Name = "__indirect_function_table";
- MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
- if (Sym) {
- if (!Sym->isFunctionTable())
- Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
- } else {
- Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
- Sym->setFunctionTable();
- // The default function table is synthesized by the linker.
- Sym->setUndefined();
- }
- // MVP object files can't have symtab entries for tables.
- if (!(Subtarget && Subtarget->hasReferenceTypes()))
- Sym->setOmitFromLinkingSection();
- return Sym;
- }
- MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
- MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
- StringRef Name = "__funcref_call_table";
- MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
- if (Sym) {
- if (!Sym->isFunctionTable())
- Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
- } else {
- Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
- // Setting Weak ensure only one table is left after linking when multiple
- // modules define the table.
- Sym->setWeak(true);
- wasm::WasmLimits Limits = {0, 1, 1};
- wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
- Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
- Sym->setTableType(TableType);
- }
- // MVP object files can't have symtab entries for tables.
- if (!(Subtarget && Subtarget->hasReferenceTypes()))
- Sym->setOmitFromLinkingSection();
- return Sym;
- }
- // Find a catch instruction from an EH pad.
- MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
- assert(EHPad->isEHPad());
- auto Pos = EHPad->begin();
- // Skip any label or debug instructions. Also skip 'end' marker instructions
- // that may exist after marker placement in CFGStackify.
- while (Pos != EHPad->end() &&
- (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
- Pos++;
- if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
- return &*Pos;
- return nullptr;
- }
- unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
- assert(RC != nullptr);
- switch (RC->getID()) {
- case WebAssembly::I32RegClassID:
- return WebAssembly::COPY_I32;
- case WebAssembly::I64RegClassID:
- return WebAssembly::COPY_I64;
- case WebAssembly::F32RegClassID:
- return WebAssembly::COPY_F32;
- case WebAssembly::F64RegClassID:
- return WebAssembly::COPY_F64;
- case WebAssembly::V128RegClassID:
- return WebAssembly::COPY_V128;
- case WebAssembly::FUNCREFRegClassID:
- return WebAssembly::COPY_FUNCREF;
- case WebAssembly::EXTERNREFRegClassID:
- return WebAssembly::COPY_EXTERNREF;
- default:
- llvm_unreachable("Unexpected register class");
- }
- }
|