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: {
341 *CurDAG,
DL, Subtarget,
Node->getOperand(0));
342 ReplaceNode(Node, TLSBase);
346 case Intrinsic::wasm_catch: {
347 int Tag =
Node->getConstantOperandVal(2);
350 ? WebAssembly::CATCH_LEGACY
351 : WebAssembly::CATCH;
352 MachineSDNode *
Catch =
353 CurDAG->getMachineNode(CatchOpcode,
DL,
362 ReplaceNode(Node,
Catch);
370 unsigned IntNo =
Node->getConstantOperandVal(1);
372 case Intrinsic::wasm_throw: {
373 int Tag =
Node->getConstantOperandVal(2);
375 MachineSDNode *Throw =
376 CurDAG->getMachineNode(WebAssembly::THROW,
DL,
383 ReplaceNode(Node, Throw);
386 case Intrinsic::wasm_rethrow: {
389 MachineSDNode *Rethrow = CurDAG->getMachineNode(
390 WebAssembly::RETHROW,
DL,
393 CurDAG->getConstant(0,
DL, MVT::i32),
396 ReplaceNode(Node, Rethrow);
410 for (
size_t i = 1; i <
Node->getNumOperands(); ++i) {
418 if (i == 1 &&
Op->getOpcode() == WebAssemblyISD::Wrapper) {
422 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
432 Ops.push_back(
Node->getOperand(0));
433 MachineSDNode *CallParams =
434 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS,
DL, MVT::Glue,
Ops);
437 ? WebAssembly::CALL_RESULTS
438 : WebAssembly::RET_CALL_RESULTS;
441 MachineSDNode *CallResults =
442 CurDAG->getMachineNode(
Results,
DL,
Node->getVTList(), Link);
443 ReplaceNode(Node, CallResults);
455bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
457 std::vector<SDValue> &OutOps) {
458 switch (ConstraintID) {
459 case InlineAsm::ConstraintCode::m:
462 OutOps.push_back(
Op);
471bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType,
SDValue N,
474 assert(
N.getNumOperands() == 2 &&
"Attempting to fold in a non-binary op");
479 if (
N.getOpcode() ==
ISD::ADD && !
N.getNode()->getFlags().hasNoUnsignedWrap())
482 for (
size_t i = 0; i < 2; ++i) {
484 SDValue OtherOp =
N.getOperand(i == 0 ? 1 : 0);
489 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(
N), OffsetType);
495 if (!TM.isPositionIndependent()) {
496 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
497 Op =
Op.getOperand(0);
509bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
516 if (!TM.isPositionIndependent()) {
518 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
519 Op =
Op.getOperand(0);
524 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
525 CurDAG->getTargetConstant(0,
DL, AddrType)),
533 SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
542 CurDAG->MaskedValueIsZero(
N->getOperand(0), CN->getAPIntValue());
544 KnownBits Known0 = CurDAG->computeKnownBits(
N->getOperand(0), 0);
545 KnownBits Known1 = CurDAG->computeKnownBits(
N->getOperand(1), 0);
546 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
549 if (OrIsAdd && SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
555 Offset = CurDAG->getTargetConstant(CN->getZExtValue(),
DL, AddrType);
557 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
558 CurDAG->getTargetConstant(0,
DL, AddrType)),
564 Offset = CurDAG->getTargetConstant(0,
DL, AddrType);
571 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32,
Op,
Offset, Addr);
576 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64,
Op,
Offset, Addr);
583 switch (
N->getOpcode()) {
593 N =
N->getOperand(0).getNode();
602bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *
Op,
SDValue N,
611 bool Match = Is64 ? SelectAddrOperands64(
N,
Offset, Addr)
612 : SelectAddrOperands32(
N,
Offset, Addr);
616 auto Ordering = MemNode->getMergedOrdering();
620 Order = CurDAG->getTargetConstant(OrderVal, SDLoc(
Op), MVT::i32);
624bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *
Op,
SDValue N,
628 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
false);
631bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *
Op,
SDValue N,
635 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
true);
642 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
MachineSDNode * getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain=SDValue())
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.