brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · 8904867 Raw
197 lines · cpp
1//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements several utility functions for WebAssembly.11///12//===----------------------------------------------------------------------===//13 14#include "WebAssemblyUtilities.h"15#include "WebAssemblyMachineFunctionInfo.h"16#include "WebAssemblyTargetMachine.h"17#include "llvm/CodeGen/MachineInstr.h"18#include "llvm/IR/Function.h"19#include "llvm/MC/MCContext.h"20using namespace llvm;21 22// Function names in libc++abi and libunwind23const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";24const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";25const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";26const char *const WebAssembly::PersonalityWrapperFn =27    "_Unwind_Wasm_CallPersonality";28 29/// Test whether MI is a child of some other node in an expression tree.30bool WebAssembly::isChild(const MachineInstr &MI,31                          const WebAssemblyFunctionInfo &MFI) {32  if (MI.getNumOperands() == 0)33    return false;34  const MachineOperand &MO = MI.getOperand(0);35  if (!MO.isReg() || MO.isImplicit() || !MO.isDef())36    return false;37  Register Reg = MO.getReg();38  return Reg.isVirtual() && MFI.isVRegStackified(Reg);39}40 41bool WebAssembly::mayThrow(const MachineInstr &MI) {42  switch (MI.getOpcode()) {43  case WebAssembly::THROW:44  case WebAssembly::THROW_S:45  case WebAssembly::THROW_REF:46  case WebAssembly::THROW_REF_S:47  case WebAssembly::RETHROW:48  case WebAssembly::RETHROW_S:49    return true;50  }51  if (isCallIndirect(MI.getOpcode()))52    return true;53  if (!MI.isCall())54    return false;55 56  const MachineOperand &MO = getCalleeOp(MI);57  assert(MO.isGlobal() || MO.isSymbol());58 59  if (MO.isSymbol()) {60    // Some intrinsics are lowered to calls to external symbols, which are then61    // lowered to calls to library functions. Most of libcalls don't throw, but62    // we only list some of them here now.63    // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo64    // instead for more accurate info.65    const char *Name = MO.getSymbolName();66    if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||67        strcmp(Name, "memset") == 0)68      return false;69    return true;70  }71 72  const auto *F = dyn_cast<Function>(MO.getGlobal());73  if (!F)74    return true;75  if (F->doesNotThrow())76    return false;77  // These functions never throw78  if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||79      F->getName() == StdTerminateFn)80    return false;81 82  // TODO Can we exclude call instructions that are marked as 'nounwind' in the83  // original LLVm IR? (Even when the callee may throw)84  return true;85}86 87const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {88  switch (MI.getOpcode()) {89  case WebAssembly::CALL:90  case WebAssembly::CALL_S:91  case WebAssembly::RET_CALL:92  case WebAssembly::RET_CALL_S:93    return MI.getOperand(MI.getNumExplicitDefs());94  case WebAssembly::CALL_INDIRECT:95  case WebAssembly::CALL_INDIRECT_S:96  case WebAssembly::RET_CALL_INDIRECT:97  case WebAssembly::RET_CALL_INDIRECT_S:98    return MI.getOperand(MI.getNumExplicitOperands() - 1);99  default:100    llvm_unreachable("Not a call instruction");101  }102}103 104MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(105    MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {106  StringRef Name = "__indirect_function_table";107  auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));108  if (Sym) {109    if (!Sym->isFunctionTable())110      Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");111  } else {112    bool is64 = Subtarget && Subtarget->getTargetTriple().isArch64Bit();113    Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));114    Sym->setFunctionTable(is64);115    // The default function table is synthesized by the linker.116  }117  // MVP object files can't have symtab entries for tables.118  if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))119    Sym->setOmitFromLinkingSection();120  return Sym;121}122 123MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(124    MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {125  StringRef Name = "__funcref_call_table";126  auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));127  if (Sym) {128    if (!Sym->isFunctionTable())129      Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");130  } else {131    Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));132 133    // Setting Weak ensure only one table is left after linking when multiple134    // modules define the table.135    Sym->setWeak(true);136 137    wasm::WasmLimits Limits = {0, 1, 1, 0};138    wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits};139    Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);140    Sym->setTableType(TableType);141  }142  // MVP object files can't have symtab entries for tables.143  if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))144    Sym->setOmitFromLinkingSection();145  return Sym;146}147 148// Find a catch instruction from an EH pad.149MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {150  assert(EHPad->isEHPad());151  auto Pos = EHPad->begin();152  // Skip any label or debug instructions. Also skip 'end' marker instructions153  // that may exist after marker placement in CFGStackify.154  while (Pos != EHPad->end() &&155         (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))156    Pos++;157  if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))158    return &*Pos;159  return nullptr;160}161 162unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {163  assert(RC != nullptr);164  switch (RC->getID()) {165  case WebAssembly::I32RegClassID:166    return WebAssembly::COPY_I32;167  case WebAssembly::I64RegClassID:168    return WebAssembly::COPY_I64;169  case WebAssembly::F32RegClassID:170    return WebAssembly::COPY_F32;171  case WebAssembly::F64RegClassID:172    return WebAssembly::COPY_F64;173  case WebAssembly::V128RegClassID:174    return WebAssembly::COPY_V128;175  case WebAssembly::FUNCREFRegClassID:176    return WebAssembly::COPY_FUNCREF;177  case WebAssembly::EXTERNREFRegClassID:178    return WebAssembly::COPY_EXTERNREF;179  case WebAssembly::EXNREFRegClassID:180    return WebAssembly::COPY_EXNREF;181  default:182    llvm_unreachable("Unexpected register class");183  }184}185 186bool WebAssembly::canLowerMultivalueReturn(187    const WebAssemblySubtarget *Subtarget) {188  const auto &TM = static_cast<const WebAssemblyTargetMachine &>(189      Subtarget->getTargetLowering()->getTargetMachine());190  return Subtarget->hasMultivalue() && TM.usesMultivalueABI();191}192 193bool WebAssembly::canLowerReturn(size_t ResultSize,194                                 const WebAssemblySubtarget *Subtarget) {195  return ResultSize <= 1 || canLowerMultivalueReturn(Subtarget);196}197