15f757f3fSDimitry Andric //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric /// 95f757f3fSDimitry Andric /// \file 105f757f3fSDimitry Andric /// This file implements several utility functions for WebAssembly. 115f757f3fSDimitry Andric /// 125f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 135f757f3fSDimitry Andric 145f757f3fSDimitry Andric #include "WebAssemblyUtilities.h" 155f757f3fSDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 165f757f3fSDimitry Andric #include "WebAssemblySubtarget.h" 175f757f3fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 185f757f3fSDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 195f757f3fSDimitry Andric #include "llvm/IR/Function.h" 205f757f3fSDimitry Andric #include "llvm/MC/MCContext.h" 215f757f3fSDimitry Andric using namespace llvm; 225f757f3fSDimitry Andric 235f757f3fSDimitry Andric // Function names in libc++abi and libunwind 245f757f3fSDimitry Andric const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; 255f757f3fSDimitry Andric const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; 265f757f3fSDimitry Andric const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; 275f757f3fSDimitry Andric const char *const WebAssembly::PersonalityWrapperFn = 285f757f3fSDimitry Andric "_Unwind_Wasm_CallPersonality"; 295f757f3fSDimitry Andric 305f757f3fSDimitry Andric /// Test whether MI is a child of some other node in an expression tree. 315f757f3fSDimitry Andric bool WebAssembly::isChild(const MachineInstr &MI, 325f757f3fSDimitry Andric const WebAssemblyFunctionInfo &MFI) { 335f757f3fSDimitry Andric if (MI.getNumOperands() == 0) 345f757f3fSDimitry Andric return false; 355f757f3fSDimitry Andric const MachineOperand &MO = MI.getOperand(0); 365f757f3fSDimitry Andric if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 375f757f3fSDimitry Andric return false; 385f757f3fSDimitry Andric Register Reg = MO.getReg(); 395f757f3fSDimitry Andric return Reg.isVirtual() && MFI.isVRegStackified(Reg); 405f757f3fSDimitry Andric } 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric bool WebAssembly::mayThrow(const MachineInstr &MI) { 435f757f3fSDimitry Andric switch (MI.getOpcode()) { 445f757f3fSDimitry Andric case WebAssembly::THROW: 455f757f3fSDimitry Andric case WebAssembly::THROW_S: 465f757f3fSDimitry Andric case WebAssembly::RETHROW: 475f757f3fSDimitry Andric case WebAssembly::RETHROW_S: 485f757f3fSDimitry Andric return true; 495f757f3fSDimitry Andric } 505f757f3fSDimitry Andric if (isCallIndirect(MI.getOpcode())) 515f757f3fSDimitry Andric return true; 525f757f3fSDimitry Andric if (!MI.isCall()) 535f757f3fSDimitry Andric return false; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric const MachineOperand &MO = getCalleeOp(MI); 565f757f3fSDimitry Andric assert(MO.isGlobal() || MO.isSymbol()); 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric if (MO.isSymbol()) { 595f757f3fSDimitry Andric // Some intrinsics are lowered to calls to external symbols, which are then 605f757f3fSDimitry Andric // lowered to calls to library functions. Most of libcalls don't throw, but 615f757f3fSDimitry Andric // we only list some of them here now. 625f757f3fSDimitry Andric // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo 635f757f3fSDimitry Andric // instead for more accurate info. 645f757f3fSDimitry Andric const char *Name = MO.getSymbolName(); 655f757f3fSDimitry Andric if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 || 665f757f3fSDimitry Andric strcmp(Name, "memset") == 0) 675f757f3fSDimitry Andric return false; 685f757f3fSDimitry Andric return true; 695f757f3fSDimitry Andric } 705f757f3fSDimitry Andric 715f757f3fSDimitry Andric const auto *F = dyn_cast<Function>(MO.getGlobal()); 725f757f3fSDimitry Andric if (!F) 735f757f3fSDimitry Andric return true; 745f757f3fSDimitry Andric if (F->doesNotThrow()) 755f757f3fSDimitry Andric return false; 765f757f3fSDimitry Andric // These functions never throw 775f757f3fSDimitry Andric if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 785f757f3fSDimitry Andric F->getName() == StdTerminateFn) 795f757f3fSDimitry Andric return false; 805f757f3fSDimitry Andric 815f757f3fSDimitry Andric // TODO Can we exclude call instructions that are marked as 'nounwind' in the 825f757f3fSDimitry Andric // original LLVm IR? (Even when the callee may throw) 835f757f3fSDimitry Andric return true; 845f757f3fSDimitry Andric } 855f757f3fSDimitry Andric 865f757f3fSDimitry Andric const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) { 875f757f3fSDimitry Andric switch (MI.getOpcode()) { 885f757f3fSDimitry Andric case WebAssembly::CALL: 895f757f3fSDimitry Andric case WebAssembly::CALL_S: 905f757f3fSDimitry Andric case WebAssembly::RET_CALL: 915f757f3fSDimitry Andric case WebAssembly::RET_CALL_S: 925f757f3fSDimitry Andric return MI.getOperand(MI.getNumExplicitDefs()); 935f757f3fSDimitry Andric case WebAssembly::CALL_INDIRECT: 945f757f3fSDimitry Andric case WebAssembly::CALL_INDIRECT_S: 955f757f3fSDimitry Andric case WebAssembly::RET_CALL_INDIRECT: 965f757f3fSDimitry Andric case WebAssembly::RET_CALL_INDIRECT_S: 975f757f3fSDimitry Andric return MI.getOperand(MI.getNumExplicitOperands() - 1); 985f757f3fSDimitry Andric default: 995f757f3fSDimitry Andric llvm_unreachable("Not a call instruction"); 1005f757f3fSDimitry Andric } 1015f757f3fSDimitry Andric } 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol( 1045f757f3fSDimitry Andric MCContext &Ctx, const WebAssemblySubtarget *Subtarget) { 1055f757f3fSDimitry Andric StringRef Name = "__indirect_function_table"; 1065f757f3fSDimitry Andric MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 1075f757f3fSDimitry Andric if (Sym) { 1085f757f3fSDimitry Andric if (!Sym->isFunctionTable()) 1095f757f3fSDimitry Andric Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 1105f757f3fSDimitry Andric } else { 1115f757f3fSDimitry Andric Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 1125f757f3fSDimitry Andric Sym->setFunctionTable(); 1135f757f3fSDimitry Andric // The default function table is synthesized by the linker. 1145f757f3fSDimitry Andric Sym->setUndefined(); 1155f757f3fSDimitry Andric } 1165f757f3fSDimitry Andric // MVP object files can't have symtab entries for tables. 1175f757f3fSDimitry Andric if (!(Subtarget && Subtarget->hasReferenceTypes())) 1185f757f3fSDimitry Andric Sym->setOmitFromLinkingSection(); 1195f757f3fSDimitry Andric return Sym; 1205f757f3fSDimitry Andric } 1215f757f3fSDimitry Andric 1225f757f3fSDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol( 1235f757f3fSDimitry Andric MCContext &Ctx, const WebAssemblySubtarget *Subtarget) { 1245f757f3fSDimitry Andric StringRef Name = "__funcref_call_table"; 1255f757f3fSDimitry Andric MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 1265f757f3fSDimitry Andric if (Sym) { 1275f757f3fSDimitry Andric if (!Sym->isFunctionTable()) 1285f757f3fSDimitry Andric Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 1295f757f3fSDimitry Andric } else { 1305f757f3fSDimitry Andric Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 1315f757f3fSDimitry Andric 1325f757f3fSDimitry Andric // Setting Weak ensure only one table is left after linking when multiple 1335f757f3fSDimitry Andric // modules define the table. 1345f757f3fSDimitry Andric Sym->setWeak(true); 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric wasm::WasmLimits Limits = {0, 1, 1}; 137*7a6dacacSDimitry Andric wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits}; 1385f757f3fSDimitry Andric Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); 1395f757f3fSDimitry Andric Sym->setTableType(TableType); 1405f757f3fSDimitry Andric } 1415f757f3fSDimitry Andric // MVP object files can't have symtab entries for tables. 1425f757f3fSDimitry Andric if (!(Subtarget && Subtarget->hasReferenceTypes())) 1435f757f3fSDimitry Andric Sym->setOmitFromLinkingSection(); 1445f757f3fSDimitry Andric return Sym; 1455f757f3fSDimitry Andric } 1465f757f3fSDimitry Andric 1475f757f3fSDimitry Andric // Find a catch instruction from an EH pad. 1485f757f3fSDimitry Andric MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) { 1495f757f3fSDimitry Andric assert(EHPad->isEHPad()); 1505f757f3fSDimitry Andric auto Pos = EHPad->begin(); 1515f757f3fSDimitry Andric // Skip any label or debug instructions. Also skip 'end' marker instructions 1525f757f3fSDimitry Andric // that may exist after marker placement in CFGStackify. 1535f757f3fSDimitry Andric while (Pos != EHPad->end() && 1545f757f3fSDimitry Andric (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode()))) 1555f757f3fSDimitry Andric Pos++; 1565f757f3fSDimitry Andric if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode())) 1575f757f3fSDimitry Andric return &*Pos; 1585f757f3fSDimitry Andric return nullptr; 1595f757f3fSDimitry Andric } 1605f757f3fSDimitry Andric 1615f757f3fSDimitry Andric unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) { 1625f757f3fSDimitry Andric assert(RC != nullptr); 1635f757f3fSDimitry Andric switch (RC->getID()) { 1645f757f3fSDimitry Andric case WebAssembly::I32RegClassID: 1655f757f3fSDimitry Andric return WebAssembly::COPY_I32; 1665f757f3fSDimitry Andric case WebAssembly::I64RegClassID: 1675f757f3fSDimitry Andric return WebAssembly::COPY_I64; 1685f757f3fSDimitry Andric case WebAssembly::F32RegClassID: 1695f757f3fSDimitry Andric return WebAssembly::COPY_F32; 1705f757f3fSDimitry Andric case WebAssembly::F64RegClassID: 1715f757f3fSDimitry Andric return WebAssembly::COPY_F64; 1725f757f3fSDimitry Andric case WebAssembly::V128RegClassID: 1735f757f3fSDimitry Andric return WebAssembly::COPY_V128; 1745f757f3fSDimitry Andric case WebAssembly::FUNCREFRegClassID: 1755f757f3fSDimitry Andric return WebAssembly::COPY_FUNCREF; 1765f757f3fSDimitry Andric case WebAssembly::EXTERNREFRegClassID: 1775f757f3fSDimitry Andric return WebAssembly::COPY_EXTERNREF; 1785f757f3fSDimitry Andric default: 1795f757f3fSDimitry Andric llvm_unreachable("Unexpected register class"); 1805f757f3fSDimitry Andric } 1815f757f3fSDimitry Andric } 182