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 bool WebAssembly::isArgument(const MachineInstr &MI) { 28 switch (MI.getOpcode()) { 29 case WebAssembly::ARGUMENT_i32: 30 case WebAssembly::ARGUMENT_i32_S: 31 case WebAssembly::ARGUMENT_i64: 32 case WebAssembly::ARGUMENT_i64_S: 33 case WebAssembly::ARGUMENT_f32: 34 case WebAssembly::ARGUMENT_f32_S: 35 case WebAssembly::ARGUMENT_f64: 36 case WebAssembly::ARGUMENT_f64_S: 37 case WebAssembly::ARGUMENT_v16i8: 38 case WebAssembly::ARGUMENT_v16i8_S: 39 case WebAssembly::ARGUMENT_v8i16: 40 case WebAssembly::ARGUMENT_v8i16_S: 41 case WebAssembly::ARGUMENT_v4i32: 42 case WebAssembly::ARGUMENT_v4i32_S: 43 case WebAssembly::ARGUMENT_v2i64: 44 case WebAssembly::ARGUMENT_v2i64_S: 45 case WebAssembly::ARGUMENT_v4f32: 46 case WebAssembly::ARGUMENT_v4f32_S: 47 case WebAssembly::ARGUMENT_v2f64: 48 case WebAssembly::ARGUMENT_v2f64_S: 49 return true; 50 default: 51 return false; 52 } 53 } 54 55 bool WebAssembly::isCopy(const MachineInstr &MI) { 56 switch (MI.getOpcode()) { 57 case WebAssembly::COPY_I32: 58 case WebAssembly::COPY_I32_S: 59 case WebAssembly::COPY_I64: 60 case WebAssembly::COPY_I64_S: 61 case WebAssembly::COPY_F32: 62 case WebAssembly::COPY_F32_S: 63 case WebAssembly::COPY_F64: 64 case WebAssembly::COPY_F64_S: 65 case WebAssembly::COPY_V128: 66 case WebAssembly::COPY_V128_S: 67 case WebAssembly::COPY_EXCEPT_REF: 68 case WebAssembly::COPY_EXCEPT_REF_S: 69 return true; 70 default: 71 return false; 72 } 73 } 74 75 bool WebAssembly::isTee(const MachineInstr &MI) { 76 switch (MI.getOpcode()) { 77 case WebAssembly::TEE_I32: 78 case WebAssembly::TEE_I32_S: 79 case WebAssembly::TEE_I64: 80 case WebAssembly::TEE_I64_S: 81 case WebAssembly::TEE_F32: 82 case WebAssembly::TEE_F32_S: 83 case WebAssembly::TEE_F64: 84 case WebAssembly::TEE_F64_S: 85 case WebAssembly::TEE_V128: 86 case WebAssembly::TEE_V128_S: 87 return true; 88 default: 89 return false; 90 } 91 } 92 93 /// Test whether MI is a child of some other node in an expression tree. 94 bool WebAssembly::isChild(const MachineInstr &MI, 95 const WebAssemblyFunctionInfo &MFI) { 96 if (MI.getNumOperands() == 0) 97 return false; 98 const MachineOperand &MO = MI.getOperand(0); 99 if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 100 return false; 101 unsigned Reg = MO.getReg(); 102 return TargetRegisterInfo::isVirtualRegister(Reg) && 103 MFI.isVRegStackified(Reg); 104 } 105 106 bool WebAssembly::isCallDirect(const MachineInstr &MI) { 107 switch (MI.getOpcode()) { 108 case WebAssembly::CALL_VOID: 109 case WebAssembly::CALL_VOID_S: 110 case WebAssembly::CALL_I32: 111 case WebAssembly::CALL_I32_S: 112 case WebAssembly::CALL_I64: 113 case WebAssembly::CALL_I64_S: 114 case WebAssembly::CALL_F32: 115 case WebAssembly::CALL_F32_S: 116 case WebAssembly::CALL_F64: 117 case WebAssembly::CALL_F64_S: 118 case WebAssembly::CALL_v16i8: 119 case WebAssembly::CALL_v16i8_S: 120 case WebAssembly::CALL_v8i16: 121 case WebAssembly::CALL_v8i16_S: 122 case WebAssembly::CALL_v4i32: 123 case WebAssembly::CALL_v4i32_S: 124 case WebAssembly::CALL_v2i64: 125 case WebAssembly::CALL_v2i64_S: 126 case WebAssembly::CALL_v4f32: 127 case WebAssembly::CALL_v4f32_S: 128 case WebAssembly::CALL_v2f64: 129 case WebAssembly::CALL_v2f64_S: 130 case WebAssembly::CALL_EXCEPT_REF: 131 case WebAssembly::CALL_EXCEPT_REF_S: 132 return true; 133 default: 134 return false; 135 } 136 } 137 138 bool WebAssembly::isCallIndirect(const MachineInstr &MI) { 139 switch (MI.getOpcode()) { 140 case WebAssembly::CALL_INDIRECT_VOID: 141 case WebAssembly::CALL_INDIRECT_VOID_S: 142 case WebAssembly::CALL_INDIRECT_I32: 143 case WebAssembly::CALL_INDIRECT_I32_S: 144 case WebAssembly::CALL_INDIRECT_I64: 145 case WebAssembly::CALL_INDIRECT_I64_S: 146 case WebAssembly::CALL_INDIRECT_F32: 147 case WebAssembly::CALL_INDIRECT_F32_S: 148 case WebAssembly::CALL_INDIRECT_F64: 149 case WebAssembly::CALL_INDIRECT_F64_S: 150 case WebAssembly::CALL_INDIRECT_v16i8: 151 case WebAssembly::CALL_INDIRECT_v16i8_S: 152 case WebAssembly::CALL_INDIRECT_v8i16: 153 case WebAssembly::CALL_INDIRECT_v8i16_S: 154 case WebAssembly::CALL_INDIRECT_v4i32: 155 case WebAssembly::CALL_INDIRECT_v4i32_S: 156 case WebAssembly::CALL_INDIRECT_v2i64: 157 case WebAssembly::CALL_INDIRECT_v2i64_S: 158 case WebAssembly::CALL_INDIRECT_v4f32: 159 case WebAssembly::CALL_INDIRECT_v4f32_S: 160 case WebAssembly::CALL_INDIRECT_v2f64: 161 case WebAssembly::CALL_INDIRECT_v2f64_S: 162 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 163 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S: 164 return true; 165 default: 166 return false; 167 } 168 } 169 170 unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { 171 switch (MI.getOpcode()) { 172 case WebAssembly::CALL_VOID: 173 case WebAssembly::CALL_VOID_S: 174 case WebAssembly::CALL_INDIRECT_VOID: 175 case WebAssembly::CALL_INDIRECT_VOID_S: 176 return 0; 177 case WebAssembly::CALL_I32: 178 case WebAssembly::CALL_I32_S: 179 case WebAssembly::CALL_I64: 180 case WebAssembly::CALL_I64_S: 181 case WebAssembly::CALL_F32: 182 case WebAssembly::CALL_F32_S: 183 case WebAssembly::CALL_F64: 184 case WebAssembly::CALL_F64_S: 185 case WebAssembly::CALL_v16i8: 186 case WebAssembly::CALL_v16i8_S: 187 case WebAssembly::CALL_v8i16: 188 case WebAssembly::CALL_v8i16_S: 189 case WebAssembly::CALL_v4i32: 190 case WebAssembly::CALL_v4i32_S: 191 case WebAssembly::CALL_v2i64: 192 case WebAssembly::CALL_v2i64_S: 193 case WebAssembly::CALL_v4f32: 194 case WebAssembly::CALL_v4f32_S: 195 case WebAssembly::CALL_v2f64: 196 case WebAssembly::CALL_v2f64_S: 197 case WebAssembly::CALL_EXCEPT_REF: 198 case WebAssembly::CALL_EXCEPT_REF_S: 199 case WebAssembly::CALL_INDIRECT_I32: 200 case WebAssembly::CALL_INDIRECT_I32_S: 201 case WebAssembly::CALL_INDIRECT_I64: 202 case WebAssembly::CALL_INDIRECT_I64_S: 203 case WebAssembly::CALL_INDIRECT_F32: 204 case WebAssembly::CALL_INDIRECT_F32_S: 205 case WebAssembly::CALL_INDIRECT_F64: 206 case WebAssembly::CALL_INDIRECT_F64_S: 207 case WebAssembly::CALL_INDIRECT_v16i8: 208 case WebAssembly::CALL_INDIRECT_v16i8_S: 209 case WebAssembly::CALL_INDIRECT_v8i16: 210 case WebAssembly::CALL_INDIRECT_v8i16_S: 211 case WebAssembly::CALL_INDIRECT_v4i32: 212 case WebAssembly::CALL_INDIRECT_v4i32_S: 213 case WebAssembly::CALL_INDIRECT_v2i64: 214 case WebAssembly::CALL_INDIRECT_v2i64_S: 215 case WebAssembly::CALL_INDIRECT_v4f32: 216 case WebAssembly::CALL_INDIRECT_v4f32_S: 217 case WebAssembly::CALL_INDIRECT_v2f64: 218 case WebAssembly::CALL_INDIRECT_v2f64_S: 219 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 220 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S: 221 return 1; 222 default: 223 llvm_unreachable("Not a call instruction"); 224 } 225 } 226 227 bool WebAssembly::isMarker(const MachineInstr &MI) { 228 switch (MI.getOpcode()) { 229 case WebAssembly::BLOCK: 230 case WebAssembly::BLOCK_S: 231 case WebAssembly::END_BLOCK: 232 case WebAssembly::END_BLOCK_S: 233 case WebAssembly::LOOP: 234 case WebAssembly::LOOP_S: 235 case WebAssembly::END_LOOP: 236 case WebAssembly::END_LOOP_S: 237 case WebAssembly::TRY: 238 case WebAssembly::TRY_S: 239 case WebAssembly::END_TRY: 240 case WebAssembly::END_TRY_S: 241 return true; 242 default: 243 return false; 244 } 245 } 246 247 bool WebAssembly::mayThrow(const MachineInstr &MI) { 248 switch (MI.getOpcode()) { 249 case WebAssembly::THROW: 250 case WebAssembly::THROW_S: 251 case WebAssembly::RETHROW: 252 case WebAssembly::RETHROW_S: 253 return true; 254 } 255 if (isCallIndirect(MI)) 256 return true; 257 if (!MI.isCall()) 258 return false; 259 260 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); 261 assert(MO.isGlobal()); 262 const auto *F = dyn_cast<Function>(MO.getGlobal()); 263 if (!F) 264 return true; 265 if (F->doesNotThrow()) 266 return false; 267 // These functions never throw 268 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 269 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) 270 return false; 271 272 // TODO Can we exclude call instructions that are marked as 'nounwind' in the 273 // original LLVm IR? (Even when the callee may throw) 274 return true; 275 } 276