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" 18 using namespace llvm; 19 20 const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; 21 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; 22 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; 23 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; 24 const char *const WebAssembly::PersonalityWrapperFn = 25 "_Unwind_Wasm_CallPersonality"; 26 27 /// Test whether MI is a child of some other node in an expression tree. 28 bool 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 39 bool 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 = getCalleeOp(MI); 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 83 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) { 84 switch (MI.getOpcode()) { 85 case WebAssembly::CALL_VOID: 86 case WebAssembly::CALL_VOID_S: 87 case WebAssembly::CALL_INDIRECT_VOID: 88 case WebAssembly::CALL_INDIRECT_VOID_S: 89 case WebAssembly::RET_CALL: 90 case WebAssembly::RET_CALL_S: 91 case WebAssembly::RET_CALL_INDIRECT: 92 case WebAssembly::RET_CALL_INDIRECT_S: 93 return MI.getOperand(0); 94 case WebAssembly::CALL_i32: 95 case WebAssembly::CALL_i32_S: 96 case WebAssembly::CALL_i64: 97 case WebAssembly::CALL_i64_S: 98 case WebAssembly::CALL_f32: 99 case WebAssembly::CALL_f32_S: 100 case WebAssembly::CALL_f64: 101 case WebAssembly::CALL_f64_S: 102 case WebAssembly::CALL_v16i8: 103 case WebAssembly::CALL_v16i8_S: 104 case WebAssembly::CALL_v8i16: 105 case WebAssembly::CALL_v8i16_S: 106 case WebAssembly::CALL_v4i32: 107 case WebAssembly::CALL_v4i32_S: 108 case WebAssembly::CALL_v2i64: 109 case WebAssembly::CALL_v2i64_S: 110 case WebAssembly::CALL_v4f32: 111 case WebAssembly::CALL_v4f32_S: 112 case WebAssembly::CALL_v2f64: 113 case WebAssembly::CALL_v2f64_S: 114 case WebAssembly::CALL_exnref: 115 case WebAssembly::CALL_exnref_S: 116 case WebAssembly::CALL_INDIRECT_i32: 117 case WebAssembly::CALL_INDIRECT_i32_S: 118 case WebAssembly::CALL_INDIRECT_i64: 119 case WebAssembly::CALL_INDIRECT_i64_S: 120 case WebAssembly::CALL_INDIRECT_f32: 121 case WebAssembly::CALL_INDIRECT_f32_S: 122 case WebAssembly::CALL_INDIRECT_f64: 123 case WebAssembly::CALL_INDIRECT_f64_S: 124 case WebAssembly::CALL_INDIRECT_v16i8: 125 case WebAssembly::CALL_INDIRECT_v16i8_S: 126 case WebAssembly::CALL_INDIRECT_v8i16: 127 case WebAssembly::CALL_INDIRECT_v8i16_S: 128 case WebAssembly::CALL_INDIRECT_v4i32: 129 case WebAssembly::CALL_INDIRECT_v4i32_S: 130 case WebAssembly::CALL_INDIRECT_v2i64: 131 case WebAssembly::CALL_INDIRECT_v2i64_S: 132 case WebAssembly::CALL_INDIRECT_v4f32: 133 case WebAssembly::CALL_INDIRECT_v4f32_S: 134 case WebAssembly::CALL_INDIRECT_v2f64: 135 case WebAssembly::CALL_INDIRECT_v2f64_S: 136 case WebAssembly::CALL_INDIRECT_exnref: 137 case WebAssembly::CALL_INDIRECT_exnref_S: 138 return MI.getOperand(1); 139 case WebAssembly::CALL: 140 case WebAssembly::CALL_S: 141 return MI.getOperand(MI.getNumExplicitDefs()); 142 case WebAssembly::CALL_INDIRECT: 143 case WebAssembly::CALL_INDIRECT_S: 144 return MI.getOperand(MI.getNumOperands() - 1); 145 default: 146 llvm_unreachable("Not a call instruction"); 147 } 148 } 149