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_ExceptRef: 131 case WebAssembly::CALL_ExceptRef_S: 132 case WebAssembly::RET_CALL: 133 case WebAssembly::RET_CALL_S: 134 return true; 135 default: 136 return false; 137 } 138 } 139 140 bool WebAssembly::isCallIndirect(const MachineInstr &MI) { 141 switch (MI.getOpcode()) { 142 case WebAssembly::CALL_INDIRECT_VOID: 143 case WebAssembly::CALL_INDIRECT_VOID_S: 144 case WebAssembly::CALL_INDIRECT_i32: 145 case WebAssembly::CALL_INDIRECT_i32_S: 146 case WebAssembly::CALL_INDIRECT_i64: 147 case WebAssembly::CALL_INDIRECT_i64_S: 148 case WebAssembly::CALL_INDIRECT_f32: 149 case WebAssembly::CALL_INDIRECT_f32_S: 150 case WebAssembly::CALL_INDIRECT_f64: 151 case WebAssembly::CALL_INDIRECT_f64_S: 152 case WebAssembly::CALL_INDIRECT_v16i8: 153 case WebAssembly::CALL_INDIRECT_v16i8_S: 154 case WebAssembly::CALL_INDIRECT_v8i16: 155 case WebAssembly::CALL_INDIRECT_v8i16_S: 156 case WebAssembly::CALL_INDIRECT_v4i32: 157 case WebAssembly::CALL_INDIRECT_v4i32_S: 158 case WebAssembly::CALL_INDIRECT_v2i64: 159 case WebAssembly::CALL_INDIRECT_v2i64_S: 160 case WebAssembly::CALL_INDIRECT_v4f32: 161 case WebAssembly::CALL_INDIRECT_v4f32_S: 162 case WebAssembly::CALL_INDIRECT_v2f64: 163 case WebAssembly::CALL_INDIRECT_v2f64_S: 164 case WebAssembly::CALL_INDIRECT_ExceptRef: 165 case WebAssembly::CALL_INDIRECT_ExceptRef_S: 166 case WebAssembly::RET_CALL_INDIRECT: 167 case WebAssembly::RET_CALL_INDIRECT_S: 168 return true; 169 default: 170 return false; 171 } 172 } 173 174 unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { 175 switch (MI.getOpcode()) { 176 case WebAssembly::CALL_VOID: 177 case WebAssembly::CALL_VOID_S: 178 case WebAssembly::CALL_INDIRECT_VOID: 179 case WebAssembly::CALL_INDIRECT_VOID_S: 180 case WebAssembly::RET_CALL: 181 case WebAssembly::RET_CALL_S: 182 case WebAssembly::RET_CALL_INDIRECT: 183 case WebAssembly::RET_CALL_INDIRECT_S: 184 return 0; 185 case WebAssembly::CALL_i32: 186 case WebAssembly::CALL_i32_S: 187 case WebAssembly::CALL_i64: 188 case WebAssembly::CALL_i64_S: 189 case WebAssembly::CALL_f32: 190 case WebAssembly::CALL_f32_S: 191 case WebAssembly::CALL_f64: 192 case WebAssembly::CALL_f64_S: 193 case WebAssembly::CALL_v16i8: 194 case WebAssembly::CALL_v16i8_S: 195 case WebAssembly::CALL_v8i16: 196 case WebAssembly::CALL_v8i16_S: 197 case WebAssembly::CALL_v4i32: 198 case WebAssembly::CALL_v4i32_S: 199 case WebAssembly::CALL_v2i64: 200 case WebAssembly::CALL_v2i64_S: 201 case WebAssembly::CALL_v4f32: 202 case WebAssembly::CALL_v4f32_S: 203 case WebAssembly::CALL_v2f64: 204 case WebAssembly::CALL_v2f64_S: 205 case WebAssembly::CALL_ExceptRef: 206 case WebAssembly::CALL_ExceptRef_S: 207 case WebAssembly::CALL_INDIRECT_i32: 208 case WebAssembly::CALL_INDIRECT_i32_S: 209 case WebAssembly::CALL_INDIRECT_i64: 210 case WebAssembly::CALL_INDIRECT_i64_S: 211 case WebAssembly::CALL_INDIRECT_f32: 212 case WebAssembly::CALL_INDIRECT_f32_S: 213 case WebAssembly::CALL_INDIRECT_f64: 214 case WebAssembly::CALL_INDIRECT_f64_S: 215 case WebAssembly::CALL_INDIRECT_v16i8: 216 case WebAssembly::CALL_INDIRECT_v16i8_S: 217 case WebAssembly::CALL_INDIRECT_v8i16: 218 case WebAssembly::CALL_INDIRECT_v8i16_S: 219 case WebAssembly::CALL_INDIRECT_v4i32: 220 case WebAssembly::CALL_INDIRECT_v4i32_S: 221 case WebAssembly::CALL_INDIRECT_v2i64: 222 case WebAssembly::CALL_INDIRECT_v2i64_S: 223 case WebAssembly::CALL_INDIRECT_v4f32: 224 case WebAssembly::CALL_INDIRECT_v4f32_S: 225 case WebAssembly::CALL_INDIRECT_v2f64: 226 case WebAssembly::CALL_INDIRECT_v2f64_S: 227 case WebAssembly::CALL_INDIRECT_ExceptRef: 228 case WebAssembly::CALL_INDIRECT_ExceptRef_S: 229 return 1; 230 default: 231 llvm_unreachable("Not a call instruction"); 232 } 233 } 234 235 bool WebAssembly::isMarker(const MachineInstr &MI) { 236 switch (MI.getOpcode()) { 237 case WebAssembly::BLOCK: 238 case WebAssembly::BLOCK_S: 239 case WebAssembly::END_BLOCK: 240 case WebAssembly::END_BLOCK_S: 241 case WebAssembly::LOOP: 242 case WebAssembly::LOOP_S: 243 case WebAssembly::END_LOOP: 244 case WebAssembly::END_LOOP_S: 245 case WebAssembly::TRY: 246 case WebAssembly::TRY_S: 247 case WebAssembly::END_TRY: 248 case WebAssembly::END_TRY_S: 249 return true; 250 default: 251 return false; 252 } 253 } 254 255 bool WebAssembly::mayThrow(const MachineInstr &MI) { 256 switch (MI.getOpcode()) { 257 case WebAssembly::THROW: 258 case WebAssembly::THROW_S: 259 case WebAssembly::RETHROW: 260 case WebAssembly::RETHROW_S: 261 return true; 262 } 263 if (isCallIndirect(MI)) 264 return true; 265 if (!MI.isCall()) 266 return false; 267 268 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); 269 assert(MO.isGlobal()); 270 const auto *F = dyn_cast<Function>(MO.getGlobal()); 271 if (!F) 272 return true; 273 if (F->doesNotThrow()) 274 return false; 275 // These functions never throw 276 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 277 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) 278 return false; 279 280 // TODO Can we exclude call instructions that are marked as 'nounwind' in the 281 // original LLVm IR? (Even when the callee may throw) 282 return true; 283 } 284