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 "WebAssemblySubtarget.h" 17 #include "llvm/CodeGen/MachineInstr.h" 18 #include "llvm/CodeGen/MachineLoopInfo.h" 19 #include "llvm/IR/Function.h" 20 #include "llvm/MC/MCContext.h" 21 using namespace llvm; 22 23 // Function names in libc++abi and libunwind 24 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; 25 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; 26 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; 27 const char *const WebAssembly::PersonalityWrapperFn = 28 "_Unwind_Wasm_CallPersonality"; 29 30 /// Test whether MI is a child of some other node in an expression tree. 31 bool WebAssembly::isChild(const MachineInstr &MI, 32 const WebAssemblyFunctionInfo &MFI) { 33 if (MI.getNumOperands() == 0) 34 return false; 35 const MachineOperand &MO = MI.getOperand(0); 36 if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 37 return false; 38 Register Reg = MO.getReg(); 39 return Reg.isVirtual() && MFI.isVRegStackified(Reg); 40 } 41 42 bool WebAssembly::mayThrow(const MachineInstr &MI) { 43 switch (MI.getOpcode()) { 44 case WebAssembly::THROW: 45 case WebAssembly::THROW_S: 46 case WebAssembly::RETHROW: 47 case WebAssembly::RETHROW_S: 48 return true; 49 } 50 if (isCallIndirect(MI.getOpcode())) 51 return true; 52 if (!MI.isCall()) 53 return false; 54 55 const MachineOperand &MO = getCalleeOp(MI); 56 assert(MO.isGlobal() || MO.isSymbol()); 57 58 if (MO.isSymbol()) { 59 // Some intrinsics are lowered to calls to external symbols, which are then 60 // lowered to calls to library functions. Most of libcalls don't throw, but 61 // we only list some of them here now. 62 // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo 63 // instead for more accurate info. 64 const char *Name = MO.getSymbolName(); 65 if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 || 66 strcmp(Name, "memset") == 0) 67 return false; 68 return true; 69 } 70 71 const auto *F = dyn_cast<Function>(MO.getGlobal()); 72 if (!F) 73 return true; 74 if (F->doesNotThrow()) 75 return false; 76 // These functions never throw 77 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 78 F->getName() == StdTerminateFn) 79 return false; 80 81 // TODO Can we exclude call instructions that are marked as 'nounwind' in the 82 // original LLVm IR? (Even when the callee may throw) 83 return true; 84 } 85 86 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) { 87 switch (MI.getOpcode()) { 88 case WebAssembly::CALL: 89 case WebAssembly::CALL_S: 90 case WebAssembly::RET_CALL: 91 case WebAssembly::RET_CALL_S: 92 return MI.getOperand(MI.getNumExplicitDefs()); 93 case WebAssembly::CALL_INDIRECT: 94 case WebAssembly::CALL_INDIRECT_S: 95 case WebAssembly::RET_CALL_INDIRECT: 96 case WebAssembly::RET_CALL_INDIRECT_S: 97 return MI.getOperand(MI.getNumExplicitOperands() - 1); 98 default: 99 llvm_unreachable("Not a call instruction"); 100 } 101 } 102 103 MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol( 104 MCContext &Ctx, const WebAssemblySubtarget *Subtarget) { 105 StringRef Name = "__indirect_function_table"; 106 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 107 if (Sym) { 108 if (!Sym->isFunctionTable()) 109 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 110 } else { 111 Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 112 Sym->setFunctionTable(); 113 // The default function table is synthesized by the linker. 114 Sym->setUndefined(); 115 } 116 // MVP object files can't have symtab entries for tables. 117 if (!(Subtarget && Subtarget->hasReferenceTypes())) 118 Sym->setOmitFromLinkingSection(); 119 return Sym; 120 } 121 122 MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol( 123 MCContext &Ctx, const WebAssemblySubtarget *Subtarget) { 124 StringRef Name = "__funcref_call_table"; 125 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 126 if (Sym) { 127 if (!Sym->isFunctionTable()) 128 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 129 } else { 130 Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 131 132 // Setting Weak ensure only one table is left after linking when multiple 133 // modules define the table. 134 Sym->setWeak(true); 135 136 wasm::WasmLimits Limits = {0, 1, 1}; 137 wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits}; 138 Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); 139 Sym->setTableType(TableType); 140 } 141 // MVP object files can't have symtab entries for tables. 142 if (!(Subtarget && Subtarget->hasReferenceTypes())) 143 Sym->setOmitFromLinkingSection(); 144 return Sym; 145 } 146 147 // Find a catch instruction from an EH pad. 148 MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) { 149 assert(EHPad->isEHPad()); 150 auto Pos = EHPad->begin(); 151 // Skip any label or debug instructions. Also skip 'end' marker instructions 152 // that may exist after marker placement in CFGStackify. 153 while (Pos != EHPad->end() && 154 (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode()))) 155 Pos++; 156 if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode())) 157 return &*Pos; 158 return nullptr; 159 } 160 161 unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) { 162 assert(RC != nullptr); 163 switch (RC->getID()) { 164 case WebAssembly::I32RegClassID: 165 return WebAssembly::COPY_I32; 166 case WebAssembly::I64RegClassID: 167 return WebAssembly::COPY_I64; 168 case WebAssembly::F32RegClassID: 169 return WebAssembly::COPY_F32; 170 case WebAssembly::F64RegClassID: 171 return WebAssembly::COPY_F64; 172 case WebAssembly::V128RegClassID: 173 return WebAssembly::COPY_V128; 174 case WebAssembly::FUNCREFRegClassID: 175 return WebAssembly::COPY_FUNCREF; 176 case WebAssembly::EXTERNREFRegClassID: 177 return WebAssembly::COPY_EXTERNREF; 178 default: 179 llvm_unreachable("Unexpected register class"); 180 } 181 } 182