LLVM 23.0.0git
WebAssemblyUtilities.cpp
Go to the documentation of this file.
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
18#include "llvm/IR/Function.h"
19#include "llvm/MC/MCContext.h"
20using namespace llvm;
21
22// Function names in libc++abi and libunwind
23const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
24const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
25const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
27 "_Unwind_Wasm_CallPersonality";
28
29/// Test whether MI is a child of some other node in an expression tree.
31 const WebAssemblyFunctionInfo &MFI) {
32 if (MI.getNumOperands() == 0)
33 return false;
34 const MachineOperand &MO = MI.getOperand(0);
35 if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
36 return false;
37 Register Reg = MO.getReg();
38 return Reg.isVirtual() && MFI.isVRegStackified(Reg);
39}
40
42 switch (MI.getOpcode()) {
43 case WebAssembly::THROW:
44 case WebAssembly::THROW_S:
45 case WebAssembly::THROW_REF:
46 case WebAssembly::THROW_REF_S:
47 case WebAssembly::RETHROW:
48 case WebAssembly::RETHROW_S:
49 return true;
50 }
51 if (isCallIndirect(MI.getOpcode()))
52 return true;
53 if (!MI.isCall())
54 return false;
55
56 const MachineOperand &MO = getCalleeOp(MI);
57 assert(MO.isGlobal() || MO.isSymbol());
58
59 if (MO.isSymbol()) {
60 // Some intrinsics are lowered to calls to external symbols, which are then
61 // lowered to calls to library functions. Most of libcalls don't throw, but
62 // we only list some of them here now.
63 // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
64 // instead for more accurate info.
65 const char *Name = MO.getSymbolName();
66 if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
67 strcmp(Name, "memset") == 0)
68 return false;
69 return true;
70 }
71
72 const auto *F = dyn_cast<Function>(MO.getGlobal());
73 if (!F)
74 return true;
75 if (F->doesNotThrow())
76 return false;
77 // These functions never throw
78 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
79 F->getName() == StdTerminateFn)
80 return false;
81
82 // TODO Can we exclude call instructions that are marked as 'nounwind' in the
83 // original LLVm IR? (Even when the callee may throw)
84 return true;
85}
86
88 switch (MI.getOpcode()) {
89 case WebAssembly::CALL:
90 case WebAssembly::CALL_S:
91 case WebAssembly::RET_CALL:
92 case WebAssembly::RET_CALL_S:
93 return MI.getOperand(MI.getNumExplicitDefs());
94 case WebAssembly::CALL_INDIRECT:
95 case WebAssembly::CALL_INDIRECT_S:
96 case WebAssembly::RET_CALL_INDIRECT:
97 case WebAssembly::RET_CALL_INDIRECT_S:
98 return MI.getOperand(MI.getNumExplicitOperands() - 1);
99 default:
100 llvm_unreachable("Not a call instruction");
101 }
102}
103
105 MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
106 StringRef Name = "__indirect_function_table";
107 auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));
108 if (Sym) {
109 if (!Sym->isFunctionTable())
110 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
111 } else {
112 bool is64 = Subtarget && Subtarget->getTargetTriple().isArch64Bit();
113 Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));
114 Sym->setFunctionTable(is64);
115 // The default function table is synthesized by the linker.
116 }
117 // MVP object files can't have symtab entries for tables.
118 if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))
120 return Sym;
121}
122
124 MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
125 StringRef Name = "__funcref_call_table";
126 auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(Name));
127 if (Sym) {
128 if (!Sym->isFunctionTable())
129 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
130 } else {
131 Sym = static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(Name));
132
133 // Setting Weak ensure only one table is left after linking when multiple
134 // modules define the table.
135 Sym->setWeak(true);
136
137 wasm::WasmLimits Limits = {0, 1, 1, 0};
138 wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits};
139 Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
140 Sym->setTableType(TableType);
141 }
142 // MVP object files can't have symtab entries for tables.
143 if (!(Subtarget && Subtarget->hasCallIndirectOverlong()))
145 return Sym;
146}
147
148// Find a catch instruction from an EH pad.
150 assert(EHPad->isEHPad());
151 auto Pos = EHPad->begin();
152 // Skip any label or debug instructions. Also skip 'end' marker instructions
153 // that may exist after marker placement in CFGStackify.
154 while (Pos != EHPad->end() &&
155 (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
156 Pos++;
157 if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
158 return &*Pos;
159 return nullptr;
160}
161
163 assert(RC != nullptr);
164 switch (RC->getID()) {
165 case WebAssembly::I32RegClassID:
166 return WebAssembly::COPY_I32;
167 case WebAssembly::I64RegClassID:
168 return WebAssembly::COPY_I64;
169 case WebAssembly::F32RegClassID:
170 return WebAssembly::COPY_F32;
171 case WebAssembly::F64RegClassID:
172 return WebAssembly::COPY_F64;
173 case WebAssembly::V128RegClassID:
174 return WebAssembly::COPY_V128;
175 case WebAssembly::FUNCREFRegClassID:
176 return WebAssembly::COPY_FUNCREF;
177 case WebAssembly::EXTERNREFRegClassID:
178 return WebAssembly::COPY_EXTERNREF;
179 case WebAssembly::EXNREFRegClassID:
180 return WebAssembly::COPY_EXNREF;
181 default:
182 llvm_unreachable("Unexpected register class");
183 }
184}
185
187 const WebAssemblySubtarget *Subtarget) {
188 const auto &TM = static_cast<const WebAssemblyTargetMachine &>(
189 Subtarget->getTargetLowering()->getTargetMachine());
190 return Subtarget->hasMultivalue() && TM.usesMultivalueABI();
191}
192
193bool WebAssembly::canLowerReturn(size_t ResultSize,
194 const WebAssemblySubtarget *Subtarget) {
195 return ResultSize <= 1 || canLowerMultivalueReturn(Subtarget);
196}
197
199 const WebAssemblySubtarget *Subtarget,
200 SDValue Chain) {
201 MVT PtrVT = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
202
203 unsigned Opcode;
204 const char *SymName;
205 if (Subtarget->hasLibcallThreadContext()) {
206 Opcode = WebAssembly::CALL;
207 SymName = "__wasm_get_tls_base";
208 } else {
209 Opcode = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
210 : WebAssembly::GLOBAL_GET_I32;
211 SymName = "__tls_base";
212 }
213
214 SDValue Sym = DAG.getTargetExternalSymbol(SymName, PtrVT);
215
216 if (Chain.getNode())
217 return DAG.getMachineNode(Opcode, DL, {PtrVT, MVT::Other}, {Sym, Chain});
218 return DAG.getMachineNode(Opcode, DL, PtrVT, Sym);
219}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
This file declares WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the declaration of the WebAssembly-specific utility functions.
Context object for machine code objects.
Definition MCContext.h:83
void setFunctionTable(bool is64)
void setWeak(bool isWeak)
void setOmitFromLinkingSection()
Machine Value Type.
bool isEHPad() const
Returns true if the block is a landing pad.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
Represents a location in source code.
Definition SMLoc.h:22
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
unsigned getID() const
Return the register class ID number.
LLVM_ABI bool isArch64Bit() const
Test whether the architecture is 64-bit.
Definition Triple.cpp:2058
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
const Triple & getTargetTriple() const
const WebAssemblyTargetLowering * getTargetLowering() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const char *const StdTerminateFn
const char *const CxaBeginCatchFn
bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI)
Test whether MI is a child of some other node in an expression tree.
bool isCallIndirect(unsigned Opc)
bool canLowerMultivalueReturn(const WebAssemblySubtarget *Subtarget)
Returns true if multivalue returns of a function can be lowered directly, i.e., not indirectly via a ...
const char *const CxaRethrowFn
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
bool isMarker(unsigned Opc)
unsigned getCopyOpcodeForRegClass(const TargetRegisterClass *RC)
Returns the appropriate copy opcode for the given register class.
const MachineOperand & getCalleeOp(const MachineInstr &MI)
Returns the operand number of a callee, assuming the argument is a call instruction.
MachineInstr * findCatch(MachineBasicBlock *EHPad)
Find a catch instruction from an EH pad.
bool isCatch(unsigned Opc)
MCSymbolWasm * getOrCreateFuncrefCallTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __funcref_call_table, for use in funcref calls when lowered to table.set + call_indirect.
const char *const PersonalityWrapperFn
bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget)
Returns true if the function's return value(s) can be lowered directly, i.e., not indirectly via a po...
bool mayThrow(const MachineInstr &MI)
MachineSDNode * getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain=SDValue())
@ WASM_SYMBOL_TYPE_TABLE
Definition Wasm.h:234
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643