xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
16*0fca6ea1SDimitry Andric #include "WebAssemblyTargetMachine.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.
isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)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 
mayThrow(const MachineInstr & MI)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 
getCalleeOp(const MachineInstr & MI)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 
getOrCreateFunctionTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)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 {
111*0fca6ea1SDimitry Andric     bool is64 = Subtarget && Subtarget->getTargetTriple().isArch64Bit();
1125f757f3fSDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
113*0fca6ea1SDimitry Andric     Sym->setFunctionTable(is64);
1145f757f3fSDimitry Andric     // The default function table is synthesized by the linker.
1155f757f3fSDimitry Andric     Sym->setUndefined();
1165f757f3fSDimitry Andric   }
1175f757f3fSDimitry Andric   // MVP object files can't have symtab entries for tables.
1185f757f3fSDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
1195f757f3fSDimitry Andric     Sym->setOmitFromLinkingSection();
1205f757f3fSDimitry Andric   return Sym;
1215f757f3fSDimitry Andric }
1225f757f3fSDimitry Andric 
getOrCreateFuncrefCallTableSymbol(MCContext & Ctx,const WebAssemblySubtarget * Subtarget)1235f757f3fSDimitry Andric MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
1245f757f3fSDimitry Andric     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
1255f757f3fSDimitry Andric   StringRef Name = "__funcref_call_table";
1265f757f3fSDimitry Andric   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
1275f757f3fSDimitry Andric   if (Sym) {
1285f757f3fSDimitry Andric     if (!Sym->isFunctionTable())
1295f757f3fSDimitry Andric       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
1305f757f3fSDimitry Andric   } else {
1315f757f3fSDimitry Andric     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
1325f757f3fSDimitry Andric 
1335f757f3fSDimitry Andric     // Setting Weak ensure only one table is left after linking when multiple
1345f757f3fSDimitry Andric     // modules define the table.
1355f757f3fSDimitry Andric     Sym->setWeak(true);
1365f757f3fSDimitry Andric 
1375f757f3fSDimitry Andric     wasm::WasmLimits Limits = {0, 1, 1};
1387a6dacacSDimitry Andric     wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits};
1395f757f3fSDimitry Andric     Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
1405f757f3fSDimitry Andric     Sym->setTableType(TableType);
1415f757f3fSDimitry Andric   }
1425f757f3fSDimitry Andric   // MVP object files can't have symtab entries for tables.
1435f757f3fSDimitry Andric   if (!(Subtarget && Subtarget->hasReferenceTypes()))
1445f757f3fSDimitry Andric     Sym->setOmitFromLinkingSection();
1455f757f3fSDimitry Andric   return Sym;
1465f757f3fSDimitry Andric }
1475f757f3fSDimitry Andric 
1485f757f3fSDimitry Andric // Find a catch instruction from an EH pad.
findCatch(MachineBasicBlock * EHPad)1495f757f3fSDimitry Andric MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
1505f757f3fSDimitry Andric   assert(EHPad->isEHPad());
1515f757f3fSDimitry Andric   auto Pos = EHPad->begin();
1525f757f3fSDimitry Andric   // Skip any label or debug instructions. Also skip 'end' marker instructions
1535f757f3fSDimitry Andric   // that may exist after marker placement in CFGStackify.
1545f757f3fSDimitry Andric   while (Pos != EHPad->end() &&
1555f757f3fSDimitry Andric          (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
1565f757f3fSDimitry Andric     Pos++;
1575f757f3fSDimitry Andric   if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
1585f757f3fSDimitry Andric     return &*Pos;
1595f757f3fSDimitry Andric   return nullptr;
1605f757f3fSDimitry Andric }
1615f757f3fSDimitry Andric 
getCopyOpcodeForRegClass(const TargetRegisterClass * RC)1625f757f3fSDimitry Andric unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
1635f757f3fSDimitry Andric   assert(RC != nullptr);
1645f757f3fSDimitry Andric   switch (RC->getID()) {
1655f757f3fSDimitry Andric   case WebAssembly::I32RegClassID:
1665f757f3fSDimitry Andric     return WebAssembly::COPY_I32;
1675f757f3fSDimitry Andric   case WebAssembly::I64RegClassID:
1685f757f3fSDimitry Andric     return WebAssembly::COPY_I64;
1695f757f3fSDimitry Andric   case WebAssembly::F32RegClassID:
1705f757f3fSDimitry Andric     return WebAssembly::COPY_F32;
1715f757f3fSDimitry Andric   case WebAssembly::F64RegClassID:
1725f757f3fSDimitry Andric     return WebAssembly::COPY_F64;
1735f757f3fSDimitry Andric   case WebAssembly::V128RegClassID:
1745f757f3fSDimitry Andric     return WebAssembly::COPY_V128;
1755f757f3fSDimitry Andric   case WebAssembly::FUNCREFRegClassID:
1765f757f3fSDimitry Andric     return WebAssembly::COPY_FUNCREF;
1775f757f3fSDimitry Andric   case WebAssembly::EXTERNREFRegClassID:
1785f757f3fSDimitry Andric     return WebAssembly::COPY_EXTERNREF;
179*0fca6ea1SDimitry Andric   case WebAssembly::EXNREFRegClassID:
180*0fca6ea1SDimitry Andric     return WebAssembly::COPY_EXNREF;
1815f757f3fSDimitry Andric   default:
1825f757f3fSDimitry Andric     llvm_unreachable("Unexpected register class");
1835f757f3fSDimitry Andric   }
1845f757f3fSDimitry Andric }
185*0fca6ea1SDimitry Andric 
canLowerMultivalueReturn(const WebAssemblySubtarget * Subtarget)186*0fca6ea1SDimitry Andric bool WebAssembly::canLowerMultivalueReturn(
187*0fca6ea1SDimitry Andric     const WebAssemblySubtarget *Subtarget) {
188*0fca6ea1SDimitry Andric   const auto &TM = static_cast<const WebAssemblyTargetMachine &>(
189*0fca6ea1SDimitry Andric       Subtarget->getTargetLowering()->getTargetMachine());
190*0fca6ea1SDimitry Andric   return Subtarget->hasMultivalue() && TM.usesMultivalueABI();
191*0fca6ea1SDimitry Andric }
192*0fca6ea1SDimitry Andric 
canLowerReturn(size_t ResultSize,const WebAssemblySubtarget * Subtarget)193*0fca6ea1SDimitry Andric bool WebAssembly::canLowerReturn(size_t ResultSize,
194*0fca6ea1SDimitry Andric                                  const WebAssemblySubtarget *Subtarget) {
195*0fca6ea1SDimitry Andric   return ResultSize <= 1 || canLowerMultivalueReturn(Subtarget);
196*0fca6ea1SDimitry Andric }
197