Home | History | Annotate | Line # | Download | only in Utils
      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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 ///
      9 /// \file
     10 /// This file implements several utility functions for WebAssembly.
     11 ///
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "WebAssemblyUtilities.h"
     15 #include "WebAssemblyMachineFunctionInfo.h"
     16 #include "llvm/CodeGen/MachineInstr.h"
     17 #include "llvm/CodeGen/MachineLoopInfo.h"
     18 #include "llvm/MC/MCContext.h"
     19 using namespace llvm;
     20 
     21 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
     22 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
     23 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
     24 const char *const WebAssembly::PersonalityWrapperFn =
     25     "_Unwind_Wasm_CallPersonality";
     26 
     27 /// Test whether MI is a child of some other node in an expression tree.
     28 bool WebAssembly::isChild(const MachineInstr &MI,
     29                           const WebAssemblyFunctionInfo &MFI) {
     30   if (MI.getNumOperands() == 0)
     31     return false;
     32   const MachineOperand &MO = MI.getOperand(0);
     33   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
     34     return false;
     35   Register Reg = MO.getReg();
     36   return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
     37 }
     38 
     39 bool WebAssembly::mayThrow(const MachineInstr &MI) {
     40   switch (MI.getOpcode()) {
     41   case WebAssembly::THROW:
     42   case WebAssembly::THROW_S:
     43   case WebAssembly::RETHROW:
     44   case WebAssembly::RETHROW_S:
     45     return true;
     46   }
     47   if (isCallIndirect(MI.getOpcode()))
     48     return true;
     49   if (!MI.isCall())
     50     return false;
     51 
     52   const MachineOperand &MO = getCalleeOp(MI);
     53   assert(MO.isGlobal() || MO.isSymbol());
     54 
     55   if (MO.isSymbol()) {
     56     // Some intrinsics are lowered to calls to external symbols, which are then
     57     // lowered to calls to library functions. Most of libcalls don't throw, but
     58     // we only list some of them here now.
     59     // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
     60     // instead for more accurate info.
     61     const char *Name = MO.getSymbolName();
     62     if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
     63         strcmp(Name, "memset") == 0)
     64       return false;
     65     return true;
     66   }
     67 
     68   const auto *F = dyn_cast<Function>(MO.getGlobal());
     69   if (!F)
     70     return true;
     71   if (F->doesNotThrow())
     72     return false;
     73   // These functions never throw
     74   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
     75       F->getName() == StdTerminateFn)
     76     return false;
     77 
     78   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
     79   // original LLVm IR? (Even when the callee may throw)
     80   return true;
     81 }
     82 
     83 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
     84   switch (MI.getOpcode()) {
     85   case WebAssembly::CALL:
     86   case WebAssembly::CALL_S:
     87   case WebAssembly::RET_CALL:
     88   case WebAssembly::RET_CALL_S:
     89     return MI.getOperand(MI.getNumExplicitDefs());
     90   case WebAssembly::CALL_INDIRECT:
     91   case WebAssembly::CALL_INDIRECT_S:
     92   case WebAssembly::RET_CALL_INDIRECT:
     93   case WebAssembly::RET_CALL_INDIRECT_S:
     94     return MI.getOperand(MI.getNumOperands() - 1);
     95   default:
     96     llvm_unreachable("Not a call instruction");
     97   }
     98 }
     99 
    100 MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
    101     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
    102   StringRef Name = "__indirect_function_table";
    103   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
    104   if (Sym) {
    105     if (!Sym->isFunctionTable())
    106       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
    107   } else {
    108     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
    109     Sym->setFunctionTable();
    110     // The default function table is synthesized by the linker.
    111     Sym->setUndefined();
    112   }
    113   // MVP object files can't have symtab entries for tables.
    114   if (!(Subtarget && Subtarget->hasReferenceTypes()))
    115     Sym->setOmitFromLinkingSection();
    116   return Sym;
    117 }
    118 
    119 // Find a catch instruction from an EH pad.
    120 MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
    121   assert(EHPad->isEHPad());
    122   auto Pos = EHPad->begin();
    123   // Skip any label or debug instructions. Also skip 'end' marker instructions
    124   // that may exist after marker placement in CFGStackify.
    125   while (Pos != EHPad->end() &&
    126          (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
    127     Pos++;
    128   if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
    129     return &*Pos;
    130   return nullptr;
    131 }
    132