| //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// This file implements several utility functions for WebAssembly. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "WebAssemblyUtilities.h" | |
| #include "WebAssemblyMachineFunctionInfo.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineLoopInfo.h" | |
| using namespace llvm; | |
| const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; | |
| const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; | |
| const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; | |
| const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; | |
| const char *const WebAssembly::PersonalityWrapperFn = | |
| "_Unwind_Wasm_CallPersonality"; | |
| /// Test whether MI is a child of some other node in an expression tree. | |
| bool WebAssembly::isChild(const MachineInstr &MI, | |
| const WebAssemblyFunctionInfo &MFI) { | |
| if (MI.getNumOperands() == 0) | |
| return false; | |
| const MachineOperand &MO = MI.getOperand(0); | |
| if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) | |
| return false; | |
| Register Reg = MO.getReg(); | |
| return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg); | |
| } | |
| bool WebAssembly::mayThrow(const MachineInstr &MI) { | |
| switch (MI.getOpcode()) { | |
| case WebAssembly::THROW: | |
| case WebAssembly::THROW_S: | |
| case WebAssembly::RETHROW: | |
| case WebAssembly::RETHROW_S: | |
| return true; | |
| } | |
| if (isCallIndirect(MI.getOpcode())) | |
| return true; | |
| if (!MI.isCall()) | |
| return false; | |
| const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI.getOpcode())); | |
| assert(MO.isGlobal() || MO.isSymbol()); | |
| if (MO.isSymbol()) { | |
| // Some intrinsics are lowered to calls to external symbols, which are then | |
| // lowered to calls to library functions. Most of libcalls don't throw, but | |
| // we only list some of them here now. | |
| // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo | |
| // instead for more accurate info. | |
| const char *Name = MO.getSymbolName(); | |
| if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 || | |
| strcmp(Name, "memset") == 0) | |
| return false; | |
| return true; | |
| } | |
| const auto *F = dyn_cast<Function>(MO.getGlobal()); | |
| if (!F) | |
| return true; | |
| if (F->doesNotThrow()) | |
| return false; | |
| // These functions never throw | |
| if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || | |
| F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) | |
| return false; | |
| // TODO Can we exclude call instructions that are marked as 'nounwind' in the | |
| // original LLVm IR? (Even when the callee may throw) | |
| return true; | |
| } |