24#include "llvm/IR/IntrinsicsWebAssembly.h"
32#define DEBUG_TYPE "wasm-isel"
33#define PASS_NAME "WebAssembly Instruction Selection"
46 WebAssemblyDAGToDAGISel() =
delete;
54 "********** Function: "
68 std::vector<SDValue> &OutOps)
override;
74#include "WebAssemblyGenDAGISel.inc"
79 bool SelectAddrOperands(
MVT AddrType,
unsigned ConstOpc,
SDValue Op,
91 ID, std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
95char WebAssemblyDAGToDAGISelLegacy::ID;
100void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
118 ? MF.createExternalSymbolName(
"__cpp_exception")
119 : MF.createExternalSymbolName(
"__c_longjmp");
126 auto toWasmValType = [](
MVT VT) {
127 if (VT == MVT::i32) {
128 return wasm::ValType::I32;
130 if (VT == MVT::i64) {
131 return wasm::ValType::I64;
133 if (VT == MVT::f32) {
134 return wasm::ValType::F32;
136 if (VT == MVT::f64) {
137 return wasm::ValType::F64;
139 if (VT == MVT::externref) {
140 return wasm::ValType::EXTERNREF;
142 if (VT == MVT::funcref) {
143 return wasm::ValType::FUNCREF;
145 if (VT == MVT::exnref) {
146 return wasm::ValType::EXNREF;
148 LLVM_DEBUG(
errs() <<
"Unhandled type for llvm.wasm.ref.test.func: " << VT
152 auto NParams = Params.
size();
153 auto NReturns = Returns.
size();
154 auto BitWidth = (NParams + NReturns + 2) * 64;
161 Sig |= NReturns ^ 0x7ffffff;
162 for (
auto &Return : Returns) {
163 auto V = toWasmValType(Return);
169 for (
auto &Param : Params) {
170 auto V = toWasmValType(Param);
177void WebAssemblyDAGToDAGISel::Select(
SDNode *
Node) {
179 if (
Node->isMachineOpcode()) {
185 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
186 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
187 : WebAssembly::GLOBAL_GET_I32;
192 switch (
Node->getOpcode()) {
199 switch (SyncScopeID) {
204 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
213 Fence = CurDAG->getMachineNode(
214 WebAssembly::ATOMIC_FENCE,
217 CurDAG->getTargetConstant(0,
DL, MVT::i32),
225 ReplaceNode(
Node, Fence);
226 CurDAG->RemoveDeadNode(
Node);
231 unsigned IntNo =
Node->getConstantOperandVal(0);
233 case Intrinsic::wasm_tls_size: {
235 GlobalGetIns,
DL, PtrVT,
236 CurDAG->getTargetExternalSymbol(
"__tls_size", PtrVT));
237 ReplaceNode(
Node, TLSSize);
241 case Intrinsic::wasm_tls_align: {
243 GlobalGetIns,
DL, PtrVT,
244 CurDAG->getTargetExternalSymbol(
"__tls_align", PtrVT));
245 ReplaceNode(
Node, TLSAlign);
248 case Intrinsic::wasm_ref_test_func: {
255 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
257 if (Subtarget->hasAddr64() && FuncPtr.
getValueType() == MVT::i64) {
260 FuncPtr =
SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64,
DL,
265 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF,
DL,
266 MVT::funcref, TableSym, FuncPtr),
275 bool IsParam =
false;
279 for (
unsigned I = 2, E =
Node->getNumOperands();
I < E; ++
I) {
280 MVT VT =
Node->getOperand(
I).getValueType().getSimpleVT();
281 if (VT == MVT::Untyped) {
293 auto SigOp = CurDAG->getTargetConstant(
296 WebAssembly::REF_TEST_FUNCREF,
DL, MVT::i32, {SigOp, FuncRef});
297 ReplaceNode(
Node, RefTestNode);
305 unsigned IntNo =
Node->getConstantOperandVal(1);
306 const auto &TLI = CurDAG->getTargetLoweringInfo();
307 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
309 case Intrinsic::wasm_tls_base: {
311 GlobalGetIns,
DL, PtrVT, MVT::Other,
312 CurDAG->getTargetExternalSymbol(
"__tls_base", PtrVT),
313 Node->getOperand(0));
314 ReplaceNode(
Node, TLSBase);
318 case Intrinsic::wasm_catch: {
319 int Tag =
Node->getConstantOperandVal(2);
322 ? WebAssembly::CATCH_LEGACY
323 : WebAssembly::CATCH;
325 CurDAG->getMachineNode(CatchOpcode,
DL,
342 unsigned IntNo =
Node->getConstantOperandVal(1);
344 case Intrinsic::wasm_throw: {
345 int Tag =
Node->getConstantOperandVal(2);
348 CurDAG->getMachineNode(WebAssembly::THROW,
DL,
355 ReplaceNode(
Node, Throw);
358 case Intrinsic::wasm_rethrow: {
362 WebAssembly::RETHROW,
DL,
365 CurDAG->getConstant(0,
DL, MVT::i32),
368 ReplaceNode(
Node, Rethrow);
375 case WebAssemblyISD::CALL:
376 case WebAssemblyISD::RET_CALL: {
382 for (
size_t i = 1; i <
Node->getNumOperands(); ++i) {
390 if (i == 1 &&
Op->getOpcode() == WebAssemblyISD::Wrapper) {
392 if (
auto *GlobalOp = dyn_cast<GlobalAddressSDNode>(NewOp.
getNode())) {
394 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
396 }
else if (isa<ExternalSymbolSDNode>(NewOp.
getNode())) {
406 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS,
DL, MVT::Glue, Ops);
408 unsigned Results =
Node->getOpcode() == WebAssemblyISD::CALL
409 ? WebAssembly::CALL_RESULTS
410 : WebAssembly::RET_CALL_RESULTS;
414 CurDAG->getMachineNode(
Results,
DL,
Node->getVTList(), Link);
415 ReplaceNode(
Node, CallResults);
427bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
429 std::vector<SDValue> &OutOps) {
430 switch (ConstraintID) {
431 case InlineAsm::ConstraintCode::m:
434 OutOps.push_back(
Op);
443bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(
MVT OffsetType,
SDValue N,
446 assert(
N.getNumOperands() == 2 &&
"Attempting to fold in a non-binary op");
451 if (
N.getOpcode() ==
ISD::ADD && !
N.getNode()->getFlags().hasNoUnsignedWrap())
454 for (
size_t i = 0; i < 2; ++i) {
456 SDValue OtherOp =
N.getOperand(i == 0 ? 1 : 0);
461 CurDAG->getTargetConstant(CN->getZExtValue(),
SDLoc(
N), OffsetType);
467 if (!
TM.isPositionIndependent()) {
468 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
469 Op =
Op.getOperand(0);
481bool WebAssemblyDAGToDAGISel::SelectAddrOperands(
MVT AddrType,
488 if (!
TM.isPositionIndependent()) {
490 if (
Op.getOpcode() == WebAssemblyISD::Wrapper)
491 Op =
Op.getOperand(0);
496 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
497 CurDAG->getTargetConstant(0,
DL, AddrType)),
514 CurDAG->MaskedValueIsZero(
N->getOperand(0), CN->getAPIntValue());
516 KnownBits Known0 = CurDAG->computeKnownBits(
N->getOperand(0), 0);
517 KnownBits Known1 = CurDAG->computeKnownBits(
N->getOperand(1), 0);
518 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
521 if (OrIsAdd && SelectAddrAddOperands(AddrType,
N,
Offset,
Addr))
527 Offset = CurDAG->getTargetConstant(CN->getZExtValue(),
DL, AddrType);
529 CurDAG->getMachineNode(ConstOpc,
DL, AddrType,
530 CurDAG->getTargetConstant(0,
DL, AddrType)),
536 Offset = CurDAG->getTargetConstant(0,
DL, AddrType);
543 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32,
Op,
Offset,
Addr);
548 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64,
Op,
Offset,
Addr);
555 return new WebAssemblyDAGToDAGISelLegacy(TM, OptLevel);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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.
DEMANGLE_DUMP_METHOD void dump() const
Class for arbitrary precision integers.
This class represents an Operation in the Expression.
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.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
static MVT getIntegerVT(unsigned BitWidth)
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
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.
An SDNode that represents everything that will be needed to construct a MachineInstr.
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 bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
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)
#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.
@ 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.
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
@ 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
This is an optimization pass for GlobalISel generic memory operations.
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.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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.