25#include "llvm/IR/IntrinsicsWebAssembly.h"
33#define DEBUG_TYPE "wasm-isel"
34#define PASS_NAME "WebAssembly Instruction Selection"
47 WebAssemblyDAGToDAGISel() =
delete;
55 "********** Function: "
63 void PreprocessISelDAG()
override;
67 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
69 std::vector<SDValue> &OutOps)
override;
81#include "WebAssemblyGenDAGISel.inc"
86 bool SelectAddrOperands(
MVT AddrType,
unsigned ConstOpc,
SDValue Op,
98 ID, std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
102char WebAssemblyDAGToDAGISelLegacy::ID;
107void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
113 for (
int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
125 ? MF.createExternalSymbolName(
"__cpp_exception")
126 : MF.createExternalSymbolName(
"__c_longjmp");
133 auto toWasmValType = [](
MVT VT) {
134 if (VT == MVT::i32) {
137 if (VT == MVT::i64) {
140 if (VT == MVT::f32) {
143 if (VT == MVT::f64) {
146 if (VT == MVT::externref) {
149 if (VT == MVT::funcref) {
152 if (VT == MVT::exnref) {
155 LLVM_DEBUG(
errs() <<
"Unhandled type for llvm.wasm.ref.test.func: " << VT
159 auto NParams = Params.
size();
160 auto NReturns = Returns.
size();
161 auto BitWidth = (NParams + NReturns + 2) * 64;
168 Sig |= NReturns ^ 0x7ffffff;
169 for (
auto &Return : Returns) {
170 auto V = toWasmValType(Return);
176 for (
auto &Param : Params) {
177 auto V = toWasmValType(Param);
203void WebAssemblyDAGToDAGISel::Select(
SDNode *
Node) {
205 if (
Node->isMachineOpcode()) {
211 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
212 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
213 : WebAssembly::GLOBAL_GET_I32;
216 MachineFunction &MF = CurDAG->getMachineFunction();
217 switch (
Node->getOpcode()) {
219 if (!MF.
getSubtarget<WebAssemblySubtarget>().hasAtomics())
222 uint64_t SyncScopeID =
Node->getConstantOperandVal(2);
223 MachineSDNode *Fence =
nullptr;
224 switch (SyncScopeID) {
229 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
237 if (MF.
getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
242 Fence = CurDAG->getMachineNode(
243 WebAssembly::ATOMIC_FENCE,
246 CurDAG->getTargetConstant(Order,
DL, MVT::i32),
255 ReplaceNode(Node, Fence);
256 CurDAG->RemoveDeadNode(Node);
261 unsigned IntNo =
Node->getConstantOperandVal(0);
263 case Intrinsic::wasm_tls_size: {
264 MachineSDNode *TLSSize = CurDAG->getMachineNode(
265 GlobalGetIns,
DL, PtrVT,
266 CurDAG->getTargetExternalSymbol(
"__tls_size", PtrVT));
267 ReplaceNode(Node, TLSSize);
271 case Intrinsic::wasm_tls_align: {
272 MachineSDNode *TLSAlign = CurDAG->getMachineNode(
273 GlobalGetIns,
DL, PtrVT,
274 CurDAG->getTargetExternalSymbol(
"__tls_align", PtrVT));
275 ReplaceNode(Node, TLSAlign);
278 case Intrinsic::wasm_ref_test_func: {
281 MachineFunction &MF = CurDAG->getMachineFunction();
285 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
290 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
295 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF,
DL,
296 MVT::funcref, TableSym, FuncPtr),
305 bool IsParam =
false;
309 for (
unsigned I = 2,
E =
Node->getNumOperands();
I <
E; ++
I) {
310 MVT VT =
Node->getOperand(
I).getValueType().getSimpleVT();
311 if (VT == MVT::Untyped) {
323 auto SigOp = CurDAG->getTargetConstant(
325 MachineSDNode *RefTestNode = CurDAG->getMachineNode(
326 WebAssembly::REF_TEST_FUNCREF,
DL, MVT::i32, {SigOp, FuncRef});
327 ReplaceNode(Node, RefTestNode);
335 unsigned IntNo =
Node->getConstantOperandVal(1);
336 const auto &TLI = CurDAG->getTargetLoweringInfo();
337 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
339 case Intrinsic::wasm_tls_base: {
340 MachineSDNode *TLSBase = CurDAG->getMachineNode(
341 GlobalGetIns,
DL, PtrVT, MVT::Other,
342 CurDAG->getTargetExternalSymbol(
"__tls_base", PtrVT),
343 Node->getOperand(0));
344 ReplaceNode(Node, TLSBase);
348 case Intrinsic::wasm_catch: {
349 int Tag =
Node->getConstantOperandVal(2);
352 ? WebAssembly::CATCH_LEGACY
353 : WebAssembly::CATCH;
354 MachineSDNode *
Catch =
355 CurDAG->getMachineNode(CatchOpcode,
DL,
364 ReplaceNode(Node,
Catch);
372 unsigned IntNo =
Node->getConstantOperandVal(1);
374 case Intrinsic::wasm_throw: {
375 int Tag =
Node->getConstantOperandVal(2);
377 MachineSDNode *Throw =
378 CurDAG->getMachineNode(WebAssembly::THROW,
DL,
385 ReplaceNode(Node, Throw);
388 case Intrinsic::wasm_rethrow: {
391 MachineSDNode *Rethrow = CurDAG->getMachineNode(
392 WebAssembly::RETHROW,
DL,
395 CurDAG->getConstant(0,
DL, MVT::i32),
398 ReplaceNode(Node, Rethrow);
412 for (
size_t i = 1; i <
Node->getNumOperands(); ++i) {
420 if (i == 1 &&
Op->getOpcode() == WebAssemblyISD::Wrapper) {
424 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
434 Ops.push_back(
Node->getOperand(0));
435 MachineSDNode *CallParams =
436 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS,
DL, MVT::Glue,
Ops);
439 ? WebAssembly::CALL_RESULTS
440 : WebAssembly::RET_CALL_RESULTS;
443 MachineSDNode *CallResults =
444 CurDAG->getMachineNode(
Results,
DL,
Node->getVTList(), Link);
445 ReplaceNode(Node, CallResults);
457bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
459 std::vector<SDValue> &OutOps) {
460 switch (ConstraintID) {
461 case InlineAsm::ConstraintCode::m:
464 OutOps.push_back(
Op);
473bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType,
SDValue N,
476 assert(
N.getNumOperands() == 2 &&
"Attempting to fold in a non-binary op");
481 if (
N.getOpcode() ==
ISD::ADD && !
N.getNode()->getFlags().hasNoUnsignedWrap())
484 for (
size_t i = 0; i < 2; ++i) {
486 SDValue OtherOp =
N.getOperand(i == 0 ? 1 : 0);
491 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(
N), OffsetType);
497 if (!TM.isPositionIndependent()) {
498 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
499 Op =
Op.getOperand(0);
511bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
518 if (!TM.isPositionIndependent()) {
520 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
521 Op =
Op.getOperand(0);
526 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
527 CurDAG->getTargetConstant(0,
DL, AddrType)),
535 SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
544 CurDAG->MaskedValueIsZero(
N->getOperand(0), CN->getAPIntValue());
546 KnownBits Known0 = CurDAG->computeKnownBits(
N->getOperand(0), 0);
547 KnownBits Known1 = CurDAG->computeKnownBits(
N->getOperand(1), 0);
548 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
551 if (OrIsAdd && SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
557 Offset = CurDAG->getTargetConstant(CN->getZExtValue(),
DL, AddrType);
559 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
560 CurDAG->getTargetConstant(0,
DL, AddrType)),
566 Offset = CurDAG->getTargetConstant(0,
DL, AddrType);
573 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32,
Op,
Offset, Addr);
578 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64,
Op,
Offset, Addr);
585 switch (
N->getOpcode()) {
595 N =
N->getOperand(0).getNode();
604bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *
Op,
SDValue N,
613 bool Match = Is64 ? SelectAddrOperands64(
N,
Offset, Addr)
614 : SelectAddrOperands32(
N,
Offset, Addr);
618 auto Ordering = MemNode->getMergedOrdering();
622 Order = CurDAG->getTargetConstant(OrderVal, SDLoc(
Op), MVT::i32);
626bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *
Op,
SDValue N,
630 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
false);
633bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *
Op,
SDValue N,
637 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
true);
644 return new WebAssemblyDAGToDAGISelLegacy(TM, OptLevel);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MemSDNode * findMemSDNode(SDNode *N)
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static unsigned getWebAssemblyMemoryOrder(AtomicOrdering Ordering)
static SDValue getTagSymNode(int Tag, SelectionDAG *DAG)
static APInt encodeFunctionSignature(SelectionDAG *DAG, SDLoc &DL, SmallVector< MVT, 4 > &Returns, SmallVector< MVT, 4 > &Params)
This file defines the interfaces that WebAssembly uses to lower LLVM code into a selection DAG.
This file provides WebAssembly-specific target descriptions.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the declaration of the WebAssembly-specific utility functions.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Class for arbitrary precision integers.
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
FunctionPass class - This class is used to implement most global optimizations.
static MVT getIntegerVT(unsigned BitWidth)
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MCContext & getContext() const
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
This is an abstract virtual class for memory operations.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
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
EVT getValueType() const
Return the ValueType of the referenced return value.
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual void PreprocessISelDAG()
PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts...
virtual bool runOnMachineFunction(MachineFunction &mf)
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
const TargetLowering & getTargetLoweringInfo() const
const DataLayout & getDataLayout() const
MachineFunction & getMachineFunction() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static std::optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)
bool hasRelaxedAtomics() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ ADD
Simple integer binary arithmetic operators.
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
@ ATOMIC_FENCE
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ SIGN_EXTEND
Conversion operators.
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
@ AND
Bitwise operators - logical and, logical or, logical xor.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ System
Synchronized with respect to all concurrently executing threads.
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
cl::opt< bool > WasmUseLegacyEH
NodeAddr< NodeBase * > Node
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.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOptLevel OptLevel)
This pass converts a legalized DAG into a WebAssembly-specific DAG, ready for instruction scheduling.
CodeGenOptLevel
Code generation optimization level.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
constexpr unsigned BitWidth
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.