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_ptr_to_funcref: {
281 MachineFunction &MF = CurDAG->getMachineFunction();
285 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
290 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
294 MachineSDNode *FuncRef = CurDAG->getMachineNode(
295 WebAssembly::TABLE_GET_FUNCREF,
DL, MVT::funcref, TableSym, FuncPtr);
296 ReplaceNode(Node, FuncRef);
299 case Intrinsic::wasm_ref_test_func: {
302 MachineFunction &MF = CurDAG->getMachineFunction();
306 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
311 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
316 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF,
DL,
317 MVT::funcref, TableSym, FuncPtr),
326 bool IsParam =
false;
330 for (
unsigned I = 2,
E =
Node->getNumOperands();
I <
E; ++
I) {
331 MVT VT =
Node->getOperand(
I).getValueType().getSimpleVT();
332 if (VT == MVT::Untyped) {
344 auto SigOp = CurDAG->getTargetConstant(
346 MachineSDNode *RefTestNode = CurDAG->getMachineNode(
347 WebAssembly::REF_TEST_FUNCREF,
DL, MVT::i32, {SigOp, FuncRef});
348 ReplaceNode(Node, RefTestNode);
356 unsigned IntNo =
Node->getConstantOperandVal(1);
357 const auto &TLI = CurDAG->getTargetLoweringInfo();
358 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
360 case Intrinsic::wasm_tls_base: {
362 *CurDAG,
DL, Subtarget,
Node->getOperand(0));
363 ReplaceNode(Node, TLSBase);
367 case Intrinsic::wasm_catch: {
368 int Tag =
Node->getConstantOperandVal(2);
371 ? WebAssembly::CATCH_LEGACY
372 : WebAssembly::CATCH;
373 MachineSDNode *
Catch =
374 CurDAG->getMachineNode(CatchOpcode,
DL,
383 ReplaceNode(Node,
Catch);
391 unsigned IntNo =
Node->getConstantOperandVal(1);
393 case Intrinsic::wasm_throw: {
394 int Tag =
Node->getConstantOperandVal(2);
396 MachineSDNode *Throw =
397 CurDAG->getMachineNode(WebAssembly::THROW,
DL,
404 ReplaceNode(Node, Throw);
407 case Intrinsic::wasm_rethrow: {
410 MachineSDNode *Rethrow = CurDAG->getMachineNode(
411 WebAssembly::RETHROW,
DL,
414 CurDAG->getConstant(0,
DL, MVT::i32),
417 ReplaceNode(Node, Rethrow);
431 for (
size_t i = 1; i <
Node->getNumOperands(); ++i) {
439 if (i == 1 &&
Op->getOpcode() == WebAssemblyISD::Wrapper) {
443 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
453 Ops.push_back(
Node->getOperand(0));
454 MachineSDNode *CallParams =
455 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS,
DL, MVT::Glue,
Ops);
458 ? WebAssembly::CALL_RESULTS
459 : WebAssembly::RET_CALL_RESULTS;
462 MachineSDNode *CallResults =
463 CurDAG->getMachineNode(
Results,
DL,
Node->getVTList(), Link);
464 ReplaceNode(Node, CallResults);
476bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
478 std::vector<SDValue> &OutOps) {
479 switch (ConstraintID) {
480 case InlineAsm::ConstraintCode::m:
483 OutOps.push_back(
Op);
492bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType,
SDValue N,
495 assert(
N.getNumOperands() == 2 &&
"Attempting to fold in a non-binary op");
500 if (
N.getOpcode() ==
ISD::ADD && !
N.getNode()->getFlags().hasNoUnsignedWrap())
503 for (
size_t i = 0; i < 2; ++i) {
505 SDValue OtherOp =
N.getOperand(i == 0 ? 1 : 0);
510 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(
N), OffsetType);
516 if (!TM.isPositionIndependent()) {
517 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
518 Op =
Op.getOperand(0);
530bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
537 if (!TM.isPositionIndependent()) {
539 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
540 Op =
Op.getOperand(0);
545 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
546 CurDAG->getTargetConstant(0,
DL, AddrType)),
554 SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
563 CurDAG->MaskedValueIsZero(
N->getOperand(0), CN->getAPIntValue());
565 KnownBits Known0 = CurDAG->computeKnownBits(
N->getOperand(0), 0);
566 KnownBits Known1 = CurDAG->computeKnownBits(
N->getOperand(1), 0);
567 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
570 if (OrIsAdd && SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
576 Offset = CurDAG->getTargetConstant(CN->getZExtValue(),
DL, AddrType);
578 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
579 CurDAG->getTargetConstant(0,
DL, AddrType)),
585 Offset = CurDAG->getTargetConstant(0,
DL, AddrType);
592 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32,
Op,
Offset, Addr);
597 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64,
Op,
Offset, Addr);
604 switch (
N->getOpcode()) {
614 N =
N->getOperand(0).getNode();
623bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *
Op,
SDValue N,
632 bool Match = Is64 ? SelectAddrOperands64(
N,
Offset, Addr)
633 : SelectAddrOperands32(
N,
Offset, Addr);
637 auto Ordering = MemNode->getMergedOrdering();
641 Order = CurDAG->getTargetConstant(OrderVal, SDLoc(
Op), MVT::i32);
645bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *
Op,
SDValue N,
649 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
false);
652bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *
Op,
SDValue N,
656 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
true);
663 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.