diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-08-22 19:00:43 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-12-06 16:30:02 +0000 | 
| commit | 5f7ddb1456d5b926e85710da690bf548ef0c9fc8 (patch) | |
| tree | f8845b108c5c07836b95c8229c96cd745fc9fb2c /contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp | |
| parent | 3f82687cdf02983d8f3294df4d97b09cf211141b (diff) | |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp | 156 | 
1 files changed, 156 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp new file mode 100644 index 000000000000..3da80f4fc875 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/WebAssembly/Utils/WebAssemblyUtilities.cpp @@ -0,0 +1,156 @@ +//===-- 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; + +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 Register::isVirtualRegister(Reg) && 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; +}  | 
