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"
18using namespace llvm;
19
20const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
21const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
22const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
23const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
24const char *const WebAssembly::PersonalityWrapperFn =
25    "_Unwind_Wasm_CallPersonality";
26
27/// Test whether MI is a child of some other node in an expression tree.
28bool 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
39bool 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 = MI.getOperand(getCalleeOpNo(MI.getOpcode()));
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() == ClangCallTerminateFn || 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