WebAssemblyUtilities.cpp revision 344779
1//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// This file implements several utility functions for WebAssembly. 12/// 13//===----------------------------------------------------------------------===// 14 15#include "WebAssemblyUtilities.h" 16#include "WebAssemblyMachineFunctionInfo.h" 17#include "llvm/CodeGen/MachineInstr.h" 18#include "llvm/CodeGen/MachineLoopInfo.h" 19using namespace llvm; 20 21const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; 22const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; 23const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; 24const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; 25const char *const WebAssembly::PersonalityWrapperFn = 26 "_Unwind_Wasm_CallPersonality"; 27 28bool WebAssembly::isArgument(const MachineInstr &MI) { 29 switch (MI.getOpcode()) { 30 case WebAssembly::ARGUMENT_i32: 31 case WebAssembly::ARGUMENT_i32_S: 32 case WebAssembly::ARGUMENT_i64: 33 case WebAssembly::ARGUMENT_i64_S: 34 case WebAssembly::ARGUMENT_f32: 35 case WebAssembly::ARGUMENT_f32_S: 36 case WebAssembly::ARGUMENT_f64: 37 case WebAssembly::ARGUMENT_f64_S: 38 case WebAssembly::ARGUMENT_v16i8: 39 case WebAssembly::ARGUMENT_v16i8_S: 40 case WebAssembly::ARGUMENT_v8i16: 41 case WebAssembly::ARGUMENT_v8i16_S: 42 case WebAssembly::ARGUMENT_v4i32: 43 case WebAssembly::ARGUMENT_v4i32_S: 44 case WebAssembly::ARGUMENT_v2i64: 45 case WebAssembly::ARGUMENT_v2i64_S: 46 case WebAssembly::ARGUMENT_v4f32: 47 case WebAssembly::ARGUMENT_v4f32_S: 48 case WebAssembly::ARGUMENT_v2f64: 49 case WebAssembly::ARGUMENT_v2f64_S: 50 return true; 51 default: 52 return false; 53 } 54} 55 56bool WebAssembly::isCopy(const MachineInstr &MI) { 57 switch (MI.getOpcode()) { 58 case WebAssembly::COPY_I32: 59 case WebAssembly::COPY_I32_S: 60 case WebAssembly::COPY_I64: 61 case WebAssembly::COPY_I64_S: 62 case WebAssembly::COPY_F32: 63 case WebAssembly::COPY_F32_S: 64 case WebAssembly::COPY_F64: 65 case WebAssembly::COPY_F64_S: 66 case WebAssembly::COPY_V128: 67 case WebAssembly::COPY_V128_S: 68 return true; 69 default: 70 return false; 71 } 72} 73 74bool WebAssembly::isTee(const MachineInstr &MI) { 75 switch (MI.getOpcode()) { 76 case WebAssembly::TEE_I32: 77 case WebAssembly::TEE_I32_S: 78 case WebAssembly::TEE_I64: 79 case WebAssembly::TEE_I64_S: 80 case WebAssembly::TEE_F32: 81 case WebAssembly::TEE_F32_S: 82 case WebAssembly::TEE_F64: 83 case WebAssembly::TEE_F64_S: 84 case WebAssembly::TEE_V128: 85 case WebAssembly::TEE_V128_S: 86 return true; 87 default: 88 return false; 89 } 90} 91 92/// Test whether MI is a child of some other node in an expression tree. 93bool WebAssembly::isChild(const MachineInstr &MI, 94 const WebAssemblyFunctionInfo &MFI) { 95 if (MI.getNumOperands() == 0) 96 return false; 97 const MachineOperand &MO = MI.getOperand(0); 98 if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 99 return false; 100 unsigned Reg = MO.getReg(); 101 return TargetRegisterInfo::isVirtualRegister(Reg) && 102 MFI.isVRegStackified(Reg); 103} 104 105bool WebAssembly::isCallDirect(const MachineInstr &MI) { 106 switch (MI.getOpcode()) { 107 case WebAssembly::CALL_VOID: 108 case WebAssembly::CALL_VOID_S: 109 case WebAssembly::CALL_I32: 110 case WebAssembly::CALL_I32_S: 111 case WebAssembly::CALL_I64: 112 case WebAssembly::CALL_I64_S: 113 case WebAssembly::CALL_F32: 114 case WebAssembly::CALL_F32_S: 115 case WebAssembly::CALL_F64: 116 case WebAssembly::CALL_F64_S: 117 case WebAssembly::CALL_v16i8: 118 case WebAssembly::CALL_v16i8_S: 119 case WebAssembly::CALL_v8i16: 120 case WebAssembly::CALL_v8i16_S: 121 case WebAssembly::CALL_v4i32: 122 case WebAssembly::CALL_v4i32_S: 123 case WebAssembly::CALL_v2i64: 124 case WebAssembly::CALL_v2i64_S: 125 case WebAssembly::CALL_v4f32: 126 case WebAssembly::CALL_v4f32_S: 127 case WebAssembly::CALL_v2f64: 128 case WebAssembly::CALL_v2f64_S: 129 case WebAssembly::CALL_EXCEPT_REF: 130 case WebAssembly::CALL_EXCEPT_REF_S: 131 return true; 132 default: 133 return false; 134 } 135} 136 137bool WebAssembly::isCallIndirect(const MachineInstr &MI) { 138 switch (MI.getOpcode()) { 139 case WebAssembly::CALL_INDIRECT_VOID: 140 case WebAssembly::CALL_INDIRECT_VOID_S: 141 case WebAssembly::CALL_INDIRECT_I32: 142 case WebAssembly::CALL_INDIRECT_I32_S: 143 case WebAssembly::CALL_INDIRECT_I64: 144 case WebAssembly::CALL_INDIRECT_I64_S: 145 case WebAssembly::CALL_INDIRECT_F32: 146 case WebAssembly::CALL_INDIRECT_F32_S: 147 case WebAssembly::CALL_INDIRECT_F64: 148 case WebAssembly::CALL_INDIRECT_F64_S: 149 case WebAssembly::CALL_INDIRECT_v16i8: 150 case WebAssembly::CALL_INDIRECT_v16i8_S: 151 case WebAssembly::CALL_INDIRECT_v8i16: 152 case WebAssembly::CALL_INDIRECT_v8i16_S: 153 case WebAssembly::CALL_INDIRECT_v4i32: 154 case WebAssembly::CALL_INDIRECT_v4i32_S: 155 case WebAssembly::CALL_INDIRECT_v2i64: 156 case WebAssembly::CALL_INDIRECT_v2i64_S: 157 case WebAssembly::CALL_INDIRECT_v4f32: 158 case WebAssembly::CALL_INDIRECT_v4f32_S: 159 case WebAssembly::CALL_INDIRECT_v2f64: 160 case WebAssembly::CALL_INDIRECT_v2f64_S: 161 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 162 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S: 163 return true; 164 default: 165 return false; 166 } 167} 168 169unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { 170 switch (MI.getOpcode()) { 171 case WebAssembly::CALL_VOID: 172 case WebAssembly::CALL_VOID_S: 173 case WebAssembly::CALL_INDIRECT_VOID: 174 case WebAssembly::CALL_INDIRECT_VOID_S: 175 return 0; 176 case WebAssembly::CALL_I32: 177 case WebAssembly::CALL_I32_S: 178 case WebAssembly::CALL_I64: 179 case WebAssembly::CALL_I64_S: 180 case WebAssembly::CALL_F32: 181 case WebAssembly::CALL_F32_S: 182 case WebAssembly::CALL_F64: 183 case WebAssembly::CALL_F64_S: 184 case WebAssembly::CALL_v16i8: 185 case WebAssembly::CALL_v16i8_S: 186 case WebAssembly::CALL_v8i16: 187 case WebAssembly::CALL_v8i16_S: 188 case WebAssembly::CALL_v4i32: 189 case WebAssembly::CALL_v4i32_S: 190 case WebAssembly::CALL_v2i64: 191 case WebAssembly::CALL_v2i64_S: 192 case WebAssembly::CALL_v4f32: 193 case WebAssembly::CALL_v4f32_S: 194 case WebAssembly::CALL_v2f64: 195 case WebAssembly::CALL_v2f64_S: 196 case WebAssembly::CALL_EXCEPT_REF: 197 case WebAssembly::CALL_EXCEPT_REF_S: 198 case WebAssembly::CALL_INDIRECT_I32: 199 case WebAssembly::CALL_INDIRECT_I32_S: 200 case WebAssembly::CALL_INDIRECT_I64: 201 case WebAssembly::CALL_INDIRECT_I64_S: 202 case WebAssembly::CALL_INDIRECT_F32: 203 case WebAssembly::CALL_INDIRECT_F32_S: 204 case WebAssembly::CALL_INDIRECT_F64: 205 case WebAssembly::CALL_INDIRECT_F64_S: 206 case WebAssembly::CALL_INDIRECT_v16i8: 207 case WebAssembly::CALL_INDIRECT_v16i8_S: 208 case WebAssembly::CALL_INDIRECT_v8i16: 209 case WebAssembly::CALL_INDIRECT_v8i16_S: 210 case WebAssembly::CALL_INDIRECT_v4i32: 211 case WebAssembly::CALL_INDIRECT_v4i32_S: 212 case WebAssembly::CALL_INDIRECT_v2i64: 213 case WebAssembly::CALL_INDIRECT_v2i64_S: 214 case WebAssembly::CALL_INDIRECT_v4f32: 215 case WebAssembly::CALL_INDIRECT_v4f32_S: 216 case WebAssembly::CALL_INDIRECT_v2f64: 217 case WebAssembly::CALL_INDIRECT_v2f64_S: 218 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 219 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S: 220 return 1; 221 default: 222 llvm_unreachable("Not a call instruction"); 223 } 224} 225 226bool WebAssembly::isMarker(const MachineInstr &MI) { 227 switch (MI.getOpcode()) { 228 case WebAssembly::BLOCK: 229 case WebAssembly::BLOCK_S: 230 case WebAssembly::END_BLOCK: 231 case WebAssembly::END_BLOCK_S: 232 case WebAssembly::LOOP: 233 case WebAssembly::LOOP_S: 234 case WebAssembly::END_LOOP: 235 case WebAssembly::END_LOOP_S: 236 case WebAssembly::TRY: 237 case WebAssembly::TRY_S: 238 case WebAssembly::END_TRY: 239 case WebAssembly::END_TRY_S: 240 return true; 241 default: 242 return false; 243 } 244} 245 246bool WebAssembly::isThrow(const MachineInstr &MI) { 247 switch (MI.getOpcode()) { 248 case WebAssembly::THROW_I32: 249 case WebAssembly::THROW_I32_S: 250 case WebAssembly::THROW_I64: 251 case WebAssembly::THROW_I64_S: 252 return true; 253 default: 254 return false; 255 } 256} 257 258bool WebAssembly::isRethrow(const MachineInstr &MI) { 259 switch (MI.getOpcode()) { 260 case WebAssembly::RETHROW: 261 case WebAssembly::RETHROW_S: 262 case WebAssembly::RETHROW_TO_CALLER: 263 case WebAssembly::RETHROW_TO_CALLER_S: 264 return true; 265 default: 266 return false; 267 } 268} 269 270bool WebAssembly::isCatch(const MachineInstr &MI) { 271 switch (MI.getOpcode()) { 272 case WebAssembly::CATCH_I32: 273 case WebAssembly::CATCH_I32_S: 274 case WebAssembly::CATCH_I64: 275 case WebAssembly::CATCH_I64_S: 276 case WebAssembly::CATCH_ALL: 277 case WebAssembly::CATCH_ALL_S: 278 return true; 279 default: 280 return false; 281 } 282} 283 284bool WebAssembly::mayThrow(const MachineInstr &MI) { 285 switch (MI.getOpcode()) { 286 case WebAssembly::THROW_I32: 287 case WebAssembly::THROW_I32_S: 288 case WebAssembly::THROW_I64: 289 case WebAssembly::THROW_I64_S: 290 case WebAssembly::RETHROW: 291 case WebAssembly::RETHROW_S: 292 return true; 293 } 294 if (isCallIndirect(MI)) 295 return true; 296 if (!MI.isCall()) 297 return false; 298 299 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); 300 assert(MO.isGlobal()); 301 const auto *F = dyn_cast<Function>(MO.getGlobal()); 302 if (!F) 303 return true; 304 if (F->doesNotThrow()) 305 return false; 306 // These functions never throw 307 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 308 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) 309 return false; 310 return true; 311} 312 313bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) { 314 if (!MBB.isEHPad()) 315 return false; 316 bool SeenCatch = false; 317 for (auto &MI : MBB) { 318 if (MI.getOpcode() == WebAssembly::CATCH_I32 || 319 MI.getOpcode() == WebAssembly::CATCH_I64 || 320 MI.getOpcode() == WebAssembly::CATCH_I32_S || 321 MI.getOpcode() == WebAssembly::CATCH_I64_S) 322 SeenCatch = true; 323 if (SeenCatch && MI.isCall()) { 324 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); 325 if (CalleeOp.isGlobal() && 326 CalleeOp.getGlobal()->getName() == ClangCallTerminateFn) 327 return true; 328 } 329 } 330 return false; 331} 332 333bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) { 334 if (!MBB.isEHPad()) 335 return false; 336 bool SeenCatchAll = false; 337 for (auto &MI : MBB) { 338 if (MI.getOpcode() == WebAssembly::CATCH_ALL || 339 MI.getOpcode() == WebAssembly::CATCH_ALL_S) 340 SeenCatchAll = true; 341 if (SeenCatchAll && MI.isCall()) { 342 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); 343 if (CalleeOp.isGlobal() && 344 CalleeOp.getGlobal()->getName() == StdTerminateFn) 345 return true; 346 } 347 } 348 return false; 349} 350