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