| //===-- 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; |
| } |