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