| //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \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"; |
| |
| bool WebAssembly::isArgument(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::ARGUMENT_I32: |
| case WebAssembly::ARGUMENT_I64: |
| case WebAssembly::ARGUMENT_F32: |
| case WebAssembly::ARGUMENT_F64: |
| case WebAssembly::ARGUMENT_v16i8: |
| case WebAssembly::ARGUMENT_v8i16: |
| case WebAssembly::ARGUMENT_v4i32: |
| case WebAssembly::ARGUMENT_v4f32: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isCopy(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::COPY_I32: |
| case WebAssembly::COPY_I64: |
| case WebAssembly::COPY_F32: |
| case WebAssembly::COPY_F64: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isTee(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::TEE_I32: |
| case WebAssembly::TEE_I64: |
| case WebAssembly::TEE_F32: |
| case WebAssembly::TEE_F64: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /// 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; |
| unsigned Reg = MO.getReg(); |
| return TargetRegisterInfo::isVirtualRegister(Reg) && |
| MFI.isVRegStackified(Reg); |
| } |
| |
| bool WebAssembly::isCallDirect(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::CALL_VOID: |
| case WebAssembly::CALL_I32: |
| case WebAssembly::CALL_I64: |
| case WebAssembly::CALL_F32: |
| case WebAssembly::CALL_F64: |
| case WebAssembly::CALL_v16i8: |
| case WebAssembly::CALL_v8i16: |
| case WebAssembly::CALL_v4i32: |
| case WebAssembly::CALL_v4f32: |
| case WebAssembly::CALL_EXCEPT_REF: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isCallIndirect(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::CALL_INDIRECT_VOID: |
| case WebAssembly::CALL_INDIRECT_I32: |
| case WebAssembly::CALL_INDIRECT_I64: |
| case WebAssembly::CALL_INDIRECT_F32: |
| case WebAssembly::CALL_INDIRECT_F64: |
| case WebAssembly::CALL_INDIRECT_v16i8: |
| case WebAssembly::CALL_INDIRECT_v8i16: |
| case WebAssembly::CALL_INDIRECT_v4i32: |
| case WebAssembly::CALL_INDIRECT_v4f32: |
| case WebAssembly::CALL_INDIRECT_EXCEPT_REF: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::CALL_VOID: |
| case WebAssembly::CALL_INDIRECT_VOID: |
| return 0; |
| case WebAssembly::CALL_I32: |
| case WebAssembly::CALL_I64: |
| case WebAssembly::CALL_F32: |
| case WebAssembly::CALL_F64: |
| case WebAssembly::CALL_EXCEPT_REF: |
| case WebAssembly::CALL_INDIRECT_I32: |
| case WebAssembly::CALL_INDIRECT_I64: |
| case WebAssembly::CALL_INDIRECT_F32: |
| case WebAssembly::CALL_INDIRECT_F64: |
| case WebAssembly::CALL_INDIRECT_EXCEPT_REF: |
| return 1; |
| default: |
| llvm_unreachable("Not a call instruction"); |
| } |
| } |
| |
| bool WebAssembly::isMarker(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::BLOCK: |
| case WebAssembly::END_BLOCK: |
| case WebAssembly::LOOP: |
| case WebAssembly::END_LOOP: |
| case WebAssembly::TRY: |
| case WebAssembly::END_TRY: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isThrow(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::THROW_I32: |
| case WebAssembly::THROW_I64: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isRethrow(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::RETHROW: |
| case WebAssembly::RETHROW_TO_CALLER: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::isCatch(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::CATCH_I32: |
| case WebAssembly::CATCH_I64: |
| case WebAssembly::CATCH_ALL: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool WebAssembly::mayThrow(const MachineInstr &MI) { |
| switch (MI.getOpcode()) { |
| case WebAssembly::THROW_I32: |
| case WebAssembly::THROW_I64: |
| case WebAssembly::RETHROW: |
| return true; |
| } |
| if (isCallIndirect(MI)) |
| return true; |
| if (!MI.isCall()) |
| return false; |
| |
| const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); |
| assert(MO.isGlobal()); |
| 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; |
| return true; |
| } |
| |
| bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) { |
| if (!MBB.isEHPad()) |
| return false; |
| bool SeenCatch = false; |
| for (auto &MI : MBB) { |
| if (MI.getOpcode() == WebAssembly::CATCH_I32 || |
| MI.getOpcode() == WebAssembly::CATCH_I64) |
| SeenCatch = true; |
| if (SeenCatch && MI.isCall()) { |
| const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); |
| if (CalleeOp.isGlobal() && |
| CalleeOp.getGlobal()->getName() == ClangCallTerminateFn) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) { |
| if (!MBB.isEHPad()) |
| return false; |
| bool SeenCatchAll = false; |
| for (auto &MI : MBB) { |
| if (MI.getOpcode() == WebAssembly::CATCH_ALL) |
| SeenCatchAll = true; |
| if (SeenCatchAll && MI.isCall()) { |
| const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); |
| if (CalleeOp.isGlobal() && |
| CalleeOp.getGlobal()->getName() == StdTerminateFn) |
| return true; |
| } |
| } |
| return false; |
| } |