25#include "llvm/IR/IntrinsicsWebAssembly.h"
34#define DEBUG_TYPE "wasm-isel"
35#define PASS_NAME "WebAssembly Instruction Selection"
48 WebAssemblyDAGToDAGISel() =
delete;
56 "********** Function: "
64 void PreprocessISelDAG()
override;
68 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
70 std::vector<SDValue> &OutOps)
override;
82#include "WebAssemblyGenDAGISel.inc"
87 bool SelectAddrOperands(
MVT AddrType,
unsigned ConstOpc,
SDValue Op,
99 ID, std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
103char WebAssemblyDAGToDAGISelLegacy::ID;
108void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
114 for (
int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
126 ? MF.createExternalSymbolName(
"__cpp_exception")
127 : MF.createExternalSymbolName(
"__c_longjmp");
134 auto toWasmValType = [](
MVT VT) {
135 if (VT == MVT::i32) {
138 if (VT == MVT::i64) {
141 if (VT == MVT::f32) {
144 if (VT == MVT::f64) {
147 if (VT == MVT::externref) {
150 if (VT == MVT::funcref) {
153 if (VT == MVT::exnref) {
156 LLVM_DEBUG(
errs() <<
"Unhandled type for llvm.wasm.ref.test.func: " << VT
160 auto NParams = Params.
size();
161 auto NReturns = Returns.
size();
162 auto BitWidth = (NParams + NReturns + 2) * 64;
169 Sig |= NReturns ^ 0x7ffffff;
170 for (
auto &Return : Returns) {
171 auto V = toWasmValType(Return);
177 for (
auto &Param : Params) {
178 auto V = toWasmValType(Param);
204void WebAssemblyDAGToDAGISel::Select(
SDNode *
Node) {
206 if (
Node->isMachineOpcode()) {
212 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
213 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
214 : WebAssembly::GLOBAL_GET_I32;
217 MachineFunction &MF = CurDAG->getMachineFunction();
218 switch (
Node->getOpcode()) {
220 if (!MF.
getSubtarget<WebAssemblySubtarget>().hasAtomics())
223 uint64_t SyncScopeID =
Node->getConstantOperandVal(2);
224 MachineSDNode *
Fence =
nullptr;
225 switch (SyncScopeID) {
230 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
238 if (MF.
getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
243 Fence = CurDAG->getMachineNode(
244 WebAssembly::ATOMIC_FENCE,
247 CurDAG->getTargetConstant(Order,
DL, MVT::i32),
256 ReplaceNode(Node, Fence);
257 CurDAG->RemoveDeadNode(Node);
262 unsigned IntNo =
Node->getConstantOperandVal(0);
264 case Intrinsic::wasm_tls_size: {
265 MachineSDNode *TLSSize = CurDAG->getMachineNode(
266 GlobalGetIns,
DL, PtrVT,
267 CurDAG->getTargetExternalSymbol(
"__tls_size", PtrVT));
268 ReplaceNode(Node, TLSSize);
272 case Intrinsic::wasm_tls_align: {
273 MachineSDNode *TLSAlign = CurDAG->getMachineNode(
274 GlobalGetIns,
DL, PtrVT,
275 CurDAG->getTargetExternalSymbol(
"__tls_align", PtrVT));
276 ReplaceNode(Node, TLSAlign);
279 case Intrinsic::wasm_ptr_to_funcref: {
282 MachineFunction &MF = CurDAG->getMachineFunction();
286 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
291 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
295 MachineSDNode *FuncRef = CurDAG->getMachineNode(
296 WebAssembly::TABLE_GET_FUNCREF,
DL, MVT::funcref, TableSym, FuncPtr);
297 ReplaceNode(Node, FuncRef);
300 case Intrinsic::wasm_ref_test_func: {
303 MachineFunction &MF = CurDAG->getMachineFunction();
307 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
312 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
317 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF,
DL,
318 MVT::funcref, TableSym, FuncPtr),
327 bool IsParam =
false;
331 for (
unsigned I = 2,
E =
Node->getNumOperands();
I <
E; ++
I) {
332 MVT VT =
Node->getOperand(
I).getValueType().getSimpleVT();
333 if (VT == MVT::Untyped) {
345 auto SigOp = CurDAG->getTargetConstant(
347 MachineSDNode *RefTestNode = CurDAG->getMachineNode(
348 WebAssembly::REF_TEST_FUNCREF,
DL, MVT::i32, {SigOp, FuncRef});
349 ReplaceNode(Node, RefTestNode);
357 unsigned IntNo =
Node->getConstantOperandVal(1);
358 const auto &TLI = CurDAG->getTargetLoweringInfo();
359 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
361 case Intrinsic::wasm_tls_base: {
363 *CurDAG,
DL, Subtarget,
Node->getOperand(0));
364 ReplaceNode(Node, TLSBase);
368 case Intrinsic::wasm_catch: {
369 int Tag =
Node->getConstantOperandVal(2);
372 ? WebAssembly::CATCH_LEGACY
373 : WebAssembly::CATCH;
374 MachineSDNode *
Catch =
375 CurDAG->getMachineNode(CatchOpcode,
DL,
384 ReplaceNode(Node,
Catch);
392 unsigned IntNo =
Node->getConstantOperandVal(1);
394 case Intrinsic::wasm_throw: {
395 int Tag =
Node->getConstantOperandVal(2);
397 MachineSDNode *Throw =
398 CurDAG->getMachineNode(WebAssembly::THROW,
DL,
405 ReplaceNode(Node, Throw);
408 case Intrinsic::wasm_rethrow: {
411 MachineSDNode *Rethrow = CurDAG->getMachineNode(
412 WebAssembly::RETHROW,
DL,
415 CurDAG->getConstant(0,
DL, MVT::i32),
418 ReplaceNode(Node, Rethrow);
432 for (
size_t i = 1; i <
Node->getNumOperands(); ++i) {
440 if (i == 1 &&
Op->getOpcode() == WebAssemblyISD::Wrapper) {
444 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
454 Ops.push_back(
Node->getOperand(0));
455 MachineSDNode *CallParams =
456 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS,
DL, MVT::Glue,
Ops);
459 ? WebAssembly::CALL_RESULTS
460 : WebAssembly::RET_CALL_RESULTS;
463 MachineSDNode *CallResults =
464 CurDAG->getMachineNode(
Results,
DL,
Node->getVTList(), Link);
465 ReplaceNode(Node, CallResults);
477bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
479 std::vector<SDValue> &OutOps) {
480 switch (ConstraintID) {
481 case InlineAsm::ConstraintCode::m:
484 OutOps.push_back(
Op);
493bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType,
SDValue N,
496 assert(
N.getNumOperands() == 2 &&
"Attempting to fold in a non-binary op");
501 if (
N.getOpcode() ==
ISD::ADD && !
N.getNode()->getFlags().hasNoUnsignedWrap())
504 for (
size_t i = 0; i < 2; ++i) {
506 SDValue OtherOp =
N.getOperand(i == 0 ? 1 : 0);
511 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(
N), OffsetType);
517 if (!TM.isPositionIndependent()) {
518 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
519 Op =
Op.getOperand(0);
531bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
538 if (!TM.isPositionIndependent()) {
540 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
541 Op =
Op.getOperand(0);
546 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
547 CurDAG->getTargetConstant(0,
DL, AddrType)),
555 SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
564 CurDAG->MaskedValueIsZero(
N->getOperand(0), CN->getAPIntValue());
566 KnownBits Known0 = CurDAG->computeKnownBits(
N->getOperand(0), 0);
567 KnownBits Known1 = CurDAG->computeKnownBits(
N->getOperand(1), 0);
568 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
571 if (OrIsAdd && SelectAddrAddOperands(AddrType,
N,
Offset, Addr))
577 Offset = CurDAG->getTargetConstant(CN->getZExtValue(),
DL, AddrType);
579 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
580 CurDAG->getTargetConstant(0,
DL, AddrType)),
586 Offset = CurDAG->getTargetConstant(0,
DL, AddrType);
593 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32,
Op,
Offset, Addr);
598 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64,
Op,
Offset, Addr);
605 switch (
N->getOpcode()) {
615 N =
N->getOperand(0).getNode();
624bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *
Op,
SDValue N,
633 bool Match = Is64 ? SelectAddrOperands64(
N,
Offset, Addr)
634 : SelectAddrOperands32(
N,
Offset, Addr);
638 auto Ordering = MemNode->getMergedOrdering();
642 Order = CurDAG->getTargetConstant(OrderVal, SDLoc(
Op), MVT::i32);
646bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *
Op,
SDValue N,
650 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
false);
653bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *
Op,
SDValue N,
657 return SelectAtomicAddrOperands(
Op,
N,
Offset, Addr, Order,
true);
665 std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
670 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.
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
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)
WebAssemblyISelDAGToDAGPass(WebAssemblyTargetMachine &TM, CodeGenOptLevel OptLevel)
This pass converts a legalized DAG into a WebAssembly-specific DAG, ready for instruction scheduling.
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.
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
FunctionPass * createWebAssemblyISelDagLegacyPass(WebAssemblyTargetMachine &TM, CodeGenOptLevel OptLevel)
Implement std::hash so that hash_code can be used in STL containers.
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.