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" 19 using namespace llvm; 20 21 const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; 22 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; 23 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; 24 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; 25 const char *const WebAssembly::PersonalityWrapperFn = 26 "_Unwind_Wasm_CallPersonality"; 27 isArgument(const MachineInstr & MI)28bool WebAssembly::isArgument(const MachineInstr &MI) { 29 switch (MI.getOpcode()) { 30 case WebAssembly::ARGUMENT_I32: 31 case WebAssembly::ARGUMENT_I64: 32 case WebAssembly::ARGUMENT_F32: 33 case WebAssembly::ARGUMENT_F64: 34 case WebAssembly::ARGUMENT_v16i8: 35 case WebAssembly::ARGUMENT_v8i16: 36 case WebAssembly::ARGUMENT_v4i32: 37 case WebAssembly::ARGUMENT_v4f32: 38 return true; 39 default: 40 return false; 41 } 42 } 43 isCopy(const MachineInstr & MI)44bool WebAssembly::isCopy(const MachineInstr &MI) { 45 switch (MI.getOpcode()) { 46 case WebAssembly::COPY_I32: 47 case WebAssembly::COPY_I64: 48 case WebAssembly::COPY_F32: 49 case WebAssembly::COPY_F64: 50 return true; 51 default: 52 return false; 53 } 54 } 55 isTee(const MachineInstr & MI)56bool WebAssembly::isTee(const MachineInstr &MI) { 57 switch (MI.getOpcode()) { 58 case WebAssembly::TEE_I32: 59 case WebAssembly::TEE_I64: 60 case WebAssembly::TEE_F32: 61 case WebAssembly::TEE_F64: 62 return true; 63 default: 64 return false; 65 } 66 } 67 68 /// Test whether MI is a child of some other node in an expression tree. isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)69bool WebAssembly::isChild(const MachineInstr &MI, 70 const WebAssemblyFunctionInfo &MFI) { 71 if (MI.getNumOperands() == 0) 72 return false; 73 const MachineOperand &MO = MI.getOperand(0); 74 if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 75 return false; 76 unsigned Reg = MO.getReg(); 77 return TargetRegisterInfo::isVirtualRegister(Reg) && 78 MFI.isVRegStackified(Reg); 79 } 80 isCallDirect(const MachineInstr & MI)81bool WebAssembly::isCallDirect(const MachineInstr &MI) { 82 switch (MI.getOpcode()) { 83 case WebAssembly::CALL_VOID: 84 case WebAssembly::CALL_I32: 85 case WebAssembly::CALL_I64: 86 case WebAssembly::CALL_F32: 87 case WebAssembly::CALL_F64: 88 case WebAssembly::CALL_v16i8: 89 case WebAssembly::CALL_v8i16: 90 case WebAssembly::CALL_v4i32: 91 case WebAssembly::CALL_v4f32: 92 case WebAssembly::CALL_EXCEPT_REF: 93 return true; 94 default: 95 return false; 96 } 97 } 98 isCallIndirect(const MachineInstr & MI)99bool WebAssembly::isCallIndirect(const MachineInstr &MI) { 100 switch (MI.getOpcode()) { 101 case WebAssembly::CALL_INDIRECT_VOID: 102 case WebAssembly::CALL_INDIRECT_I32: 103 case WebAssembly::CALL_INDIRECT_I64: 104 case WebAssembly::CALL_INDIRECT_F32: 105 case WebAssembly::CALL_INDIRECT_F64: 106 case WebAssembly::CALL_INDIRECT_v16i8: 107 case WebAssembly::CALL_INDIRECT_v8i16: 108 case WebAssembly::CALL_INDIRECT_v4i32: 109 case WebAssembly::CALL_INDIRECT_v4f32: 110 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 111 return true; 112 default: 113 return false; 114 } 115 } 116 getCalleeOpNo(const MachineInstr & MI)117unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { 118 switch (MI.getOpcode()) { 119 case WebAssembly::CALL_VOID: 120 case WebAssembly::CALL_INDIRECT_VOID: 121 return 0; 122 case WebAssembly::CALL_I32: 123 case WebAssembly::CALL_I64: 124 case WebAssembly::CALL_F32: 125 case WebAssembly::CALL_F64: 126 case WebAssembly::CALL_EXCEPT_REF: 127 case WebAssembly::CALL_INDIRECT_I32: 128 case WebAssembly::CALL_INDIRECT_I64: 129 case WebAssembly::CALL_INDIRECT_F32: 130 case WebAssembly::CALL_INDIRECT_F64: 131 case WebAssembly::CALL_INDIRECT_EXCEPT_REF: 132 return 1; 133 default: 134 llvm_unreachable("Not a call instruction"); 135 } 136 } 137 isMarker(const MachineInstr & MI)138bool WebAssembly::isMarker(const MachineInstr &MI) { 139 switch (MI.getOpcode()) { 140 case WebAssembly::BLOCK: 141 case WebAssembly::END_BLOCK: 142 case WebAssembly::LOOP: 143 case WebAssembly::END_LOOP: 144 case WebAssembly::TRY: 145 case WebAssembly::END_TRY: 146 return true; 147 default: 148 return false; 149 } 150 } 151 isThrow(const MachineInstr & MI)152bool WebAssembly::isThrow(const MachineInstr &MI) { 153 switch (MI.getOpcode()) { 154 case WebAssembly::THROW_I32: 155 case WebAssembly::THROW_I64: 156 return true; 157 default: 158 return false; 159 } 160 } 161 isRethrow(const MachineInstr & MI)162bool WebAssembly::isRethrow(const MachineInstr &MI) { 163 switch (MI.getOpcode()) { 164 case WebAssembly::RETHROW: 165 case WebAssembly::RETHROW_TO_CALLER: 166 return true; 167 default: 168 return false; 169 } 170 } 171 isCatch(const MachineInstr & MI)172bool WebAssembly::isCatch(const MachineInstr &MI) { 173 switch (MI.getOpcode()) { 174 case WebAssembly::CATCH_I32: 175 case WebAssembly::CATCH_I64: 176 case WebAssembly::CATCH_ALL: 177 return true; 178 default: 179 return false; 180 } 181 } 182 mayThrow(const MachineInstr & MI)183bool WebAssembly::mayThrow(const MachineInstr &MI) { 184 switch (MI.getOpcode()) { 185 case WebAssembly::THROW_I32: 186 case WebAssembly::THROW_I64: 187 case WebAssembly::RETHROW: 188 return true; 189 } 190 if (isCallIndirect(MI)) 191 return true; 192 if (!MI.isCall()) 193 return false; 194 195 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); 196 assert(MO.isGlobal()); 197 const auto *F = dyn_cast<Function>(MO.getGlobal()); 198 if (!F) 199 return true; 200 if (F->doesNotThrow()) 201 return false; 202 // These functions never throw 203 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 204 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) 205 return false; 206 return true; 207 } 208 isCatchTerminatePad(const MachineBasicBlock & MBB)209bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) { 210 if (!MBB.isEHPad()) 211 return false; 212 bool SeenCatch = false; 213 for (auto &MI : MBB) { 214 if (MI.getOpcode() == WebAssembly::CATCH_I32 || 215 MI.getOpcode() == WebAssembly::CATCH_I64) 216 SeenCatch = true; 217 if (SeenCatch && MI.isCall()) { 218 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); 219 if (CalleeOp.isGlobal() && 220 CalleeOp.getGlobal()->getName() == ClangCallTerminateFn) 221 return true; 222 } 223 } 224 return false; 225 } 226 isCatchAllTerminatePad(const MachineBasicBlock & MBB)227bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) { 228 if (!MBB.isEHPad()) 229 return false; 230 bool SeenCatchAll = false; 231 for (auto &MI : MBB) { 232 if (MI.getOpcode() == WebAssembly::CATCH_ALL) 233 SeenCatchAll = true; 234 if (SeenCatchAll && MI.isCall()) { 235 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); 236 if (CalleeOp.isGlobal() && 237 CalleeOp.getGlobal()->getName() == StdTerminateFn) 238 return true; 239 } 240 } 241 return false; 242 } 243