1311116Sdim//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2311116Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311116Sdim//
7311116Sdim//===----------------------------------------------------------------------===//
8311116Sdim///
9311116Sdim/// \file
10341825Sdim/// This file implements several utility functions for WebAssembly.
11311116Sdim///
12311116Sdim//===----------------------------------------------------------------------===//
13311116Sdim
14311116Sdim#include "WebAssemblyUtilities.h"
15311116Sdim#include "WebAssemblyMachineFunctionInfo.h"
16311116Sdim#include "llvm/CodeGen/MachineInstr.h"
17321369Sdim#include "llvm/CodeGen/MachineLoopInfo.h"
18311116Sdimusing namespace llvm;
19311116Sdim
20341825Sdimconst char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
21341825Sdimconst char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
22341825Sdimconst char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
23341825Sdimconst char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
24341825Sdimconst char *const WebAssembly::PersonalityWrapperFn =
25341825Sdim    "_Unwind_Wasm_CallPersonality";
26341825Sdim
27311116Sdim/// Test whether MI is a child of some other node in an expression tree.
28311116Sdimbool WebAssembly::isChild(const MachineInstr &MI,
29311116Sdim                          const WebAssemblyFunctionInfo &MFI) {
30311116Sdim  if (MI.getNumOperands() == 0)
31311116Sdim    return false;
32311116Sdim  const MachineOperand &MO = MI.getOperand(0);
33311116Sdim  if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
34311116Sdim    return false;
35360784Sdim  Register Reg = MO.getReg();
36360784Sdim  return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
37311116Sdim}
38321369Sdim
39341825Sdimbool WebAssembly::mayThrow(const MachineInstr &MI) {
40341825Sdim  switch (MI.getOpcode()) {
41353358Sdim  case WebAssembly::THROW:
42353358Sdim  case WebAssembly::THROW_S:
43341825Sdim  case WebAssembly::RETHROW:
44344779Sdim  case WebAssembly::RETHROW_S:
45341825Sdim    return true;
46341825Sdim  }
47353358Sdim  if (isCallIndirect(MI.getOpcode()))
48341825Sdim    return true;
49341825Sdim  if (!MI.isCall())
50341825Sdim    return false;
51341825Sdim
52353358Sdim  const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI.getOpcode()));
53360784Sdim  assert(MO.isGlobal() || MO.isSymbol());
54360784Sdim
55360784Sdim  if (MO.isSymbol()) {
56360784Sdim    // Some intrinsics are lowered to calls to external symbols, which are then
57360784Sdim    // lowered to calls to library functions. Most of libcalls don't throw, but
58360784Sdim    // we only list some of them here now.
59360784Sdim    // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
60360784Sdim    // instead for more accurate info.
61360784Sdim    const char *Name = MO.getSymbolName();
62360784Sdim    if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
63360784Sdim        strcmp(Name, "memset") == 0)
64360784Sdim      return false;
65360784Sdim    return true;
66360784Sdim  }
67360784Sdim
68341825Sdim  const auto *F = dyn_cast<Function>(MO.getGlobal());
69341825Sdim  if (!F)
70341825Sdim    return true;
71341825Sdim  if (F->doesNotThrow())
72341825Sdim    return false;
73341825Sdim  // These functions never throw
74341825Sdim  if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
75341825Sdim      F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
76341825Sdim    return false;
77353358Sdim
78353358Sdim  // TODO Can we exclude call instructions that are marked as 'nounwind' in the
79353358Sdim  // original LLVm IR? (Even when the callee may throw)
80341825Sdim  return true;
81341825Sdim}
82