LLVM: lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
24#include "llvm/IR/IntrinsicsWebAssembly.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "wasm-isel"
33#define PASS_NAME "WebAssembly Instruction Selection"
34
35
36
37
38
39namespace {
40class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
41
42
44
45public:
46 WebAssemblyDAGToDAGISel() = delete;
47
51
53 LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
54 "********** Function: "
56
58
60 }
61
62 void PreprocessISelDAG() override;
63
65
66 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
68 std::vector &OutOps) override;
69
72
73
74#include "WebAssemblyGenDAGISel.inc"
75
76private:
77
78
79 bool SelectAddrOperands(MVT AddrType, unsigned ConstOpc, SDValue Op,
83};
84
86public:
87 static char ID;
91 ID, std::make_unique(TM, OptLevel)) {}
92};
93}
94
95char WebAssemblyDAGToDAGISelLegacy::ID;
96
98 false)
99
100void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
101
102
103
104
108
110}
111
118 ? MF.createExternalSymbolName("__cpp_exception")
119 : MF.createExternalSymbolName("__c_longjmp");
121}
122
126 auto toWasmValType = [](MVT VT) {
127 if (VT == MVT::i32) {
129 }
130 if (VT == MVT::i64) {
132 }
133 if (VT == MVT::f32) {
135 }
136 if (VT == MVT::f64) {
138 }
139 if (VT == MVT::externref) {
141 }
142 if (VT == MVT::funcref) {
144 }
145 if (VT == MVT::exnref) {
147 }
148 LLVM_DEBUG(errs() << "Unhandled type for llvm.wasm.ref.test.func: " << VT
149 << "\n");
150 llvm_unreachable("Unhandled type for llvm.wasm.ref.test.func");
151 };
152 auto NParams = Params.size();
153 auto NReturns = Returns.size();
154 auto BitWidth = (NParams + NReturns + 2) * 64;
156
157
158
159
160
161 Sig |= NReturns ^ 0x7ffffff;
162 for (auto &Return : Returns) {
163 auto V = toWasmValType(Return);
164 Sig <<= 64;
165 Sig |= (int64_t)V;
166 }
167 Sig <<= 64;
168 Sig |= NParams;
169 for (auto &Param : Params) {
170 auto V = toWasmValType(Param);
171 Sig <<= 64;
172 Sig |= (int64_t)V;
173 }
174 return Sig;
175}
176
177void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
178
179 if (Node->isMachineOpcode()) {
181 Node->setNodeId(-1);
182 return;
183 }
184
185 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
186 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
187 : WebAssembly::GLOBAL_GET_I32;
188
189
190 SDLoc DL(Node);
191 MachineFunction &MF = CurDAG->getMachineFunction();
192 switch (Node->getOpcode()) {
193 case ISD::ATOMIC_FENCE: {
194 if (!MF.getSubtarget().hasAtomics())
195 break;
196
197 uint64_t SyncScopeID = Node->getConstantOperandVal(2);
198 MachineSDNode *Fence = nullptr;
199 switch (SyncScopeID) {
201
202
203
204 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
205 DL,
206 MVT::Other,
207 Node->getOperand(0)
208 );
209 break;
211
212
213 Fence = CurDAG->getMachineNode(
214 WebAssembly::ATOMIC_FENCE,
215 DL,
216 MVT::Other,
217 CurDAG->getTargetConstant(0, DL, MVT::i32),
218 Node->getOperand(0)
219 );
220 break;
221 default:
223 }
224
225 ReplaceNode(Node, Fence);
226 CurDAG->RemoveDeadNode(Node);
227 return;
228 }
229
231 unsigned IntNo = Node->getConstantOperandVal(0);
232 switch (IntNo) {
233 case Intrinsic::wasm_tls_size: {
234 MachineSDNode *TLSSize = CurDAG->getMachineNode(
235 GlobalGetIns, DL, PtrVT,
236 CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));
237 ReplaceNode(Node, TLSSize);
238 return;
239 }
240
241 case Intrinsic::wasm_tls_align: {
242 MachineSDNode *TLSAlign = CurDAG->getMachineNode(
243 GlobalGetIns, DL, PtrVT,
244 CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));
245 ReplaceNode(Node, TLSAlign);
246 return;
247 }
248 case Intrinsic::wasm_ref_test_func: {
249
250
251 MachineFunction &MF = CurDAG->getMachineFunction();
255 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
258
259
260 FuncPtr = SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64, DL,
261 MVT::i32, FuncPtr),
262 0);
263 }
265 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
266 MVT::funcref, TableSym, FuncPtr),
267 0);
268
269
270
271
274
275 bool IsParam = false;
276
277
278
279 for (unsigned I = 2, E = Node->getNumOperands(); I < E; ++I) {
280 MVT VT = Node->getOperand(I).getValueType().getSimpleVT();
281 if (VT == MVT::Untyped) {
282 IsParam = true;
283 continue;
284 }
285 if (IsParam) {
287 } else {
289 }
290 }
292
293 auto SigOp = CurDAG->getTargetConstant(
295 MachineSDNode *RefTestNode = CurDAG->getMachineNode(
296 WebAssembly::REF_TEST_FUNCREF, DL, MVT::i32, {SigOp, FuncRef});
297 ReplaceNode(Node, RefTestNode);
298 return;
299 }
300 }
301 break;
302 }
303
305 unsigned IntNo = Node->getConstantOperandVal(1);
306 const auto &TLI = CurDAG->getTargetLoweringInfo();
307 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
308 switch (IntNo) {
309 case Intrinsic::wasm_tls_base: {
310 MachineSDNode *TLSBase = CurDAG->getMachineNode(
311 GlobalGetIns, DL, PtrVT, MVT::Other,
312 CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),
313 Node->getOperand(0));
314 ReplaceNode(Node, TLSBase);
315 return;
316 }
317
318 case Intrinsic::wasm_catch: {
319 int Tag = Node->getConstantOperandVal(2);
322 ? WebAssembly::CATCH_LEGACY
323 : WebAssembly::CATCH;
324 MachineSDNode *Catch =
325 CurDAG->getMachineNode(CatchOpcode, DL,
326 {
327 PtrVT,
328 MVT::Other
329 },
330 {
331 SymNode,
332 Node->getOperand(0)
333 });
334 ReplaceNode(Node, Catch);
335 return;
336 }
337 }
338 break;
339 }
340
342 unsigned IntNo = Node->getConstantOperandVal(1);
343 switch (IntNo) {
344 case Intrinsic::wasm_throw: {
345 int Tag = Node->getConstantOperandVal(2);
347 MachineSDNode *Throw =
348 CurDAG->getMachineNode(WebAssembly::THROW, DL,
349 MVT::Other,
350 {
351 SymNode,
352 Node->getOperand(3),
353 Node->getOperand(0)
354 });
355 ReplaceNode(Node, Throw);
356 return;
357 }
358 case Intrinsic::wasm_rethrow: {
359
360
361 MachineSDNode *Rethrow = CurDAG->getMachineNode(
362 WebAssembly::RETHROW, DL,
363 MVT::Other,
364 {
365 CurDAG->getConstant(0, DL, MVT::i32),
366 Node->getOperand(0)
367 });
368 ReplaceNode(Node, Rethrow);
369 return;
370 }
371 }
372 break;
373 }
374
377
378
379
380
382 for (size_t i = 1; i < Node->getNumOperands(); ++i) {
384
385
386
387
388
389
390 if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper) {
391 SDValue NewOp = Op->getOperand(0);
394 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
395 Op = NewOp;
397 Op = NewOp;
398 }
399 }
401 }
402
403
404 Ops.push_back(Node->getOperand(0));
405 MachineSDNode *CallParams =
406 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);
407
409 ? WebAssembly::CALL_RESULTS
410 : WebAssembly::RET_CALL_RESULTS;
411
412 SDValue Link(CallParams, 0);
413 MachineSDNode *CallResults =
414 CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
415 ReplaceNode(Node, CallResults);
416 return;
417 }
418
419 default:
420 break;
421 }
422
423
424 SelectCode(Node);
425}
426
427bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
429 std::vector &OutOps) {
430 switch (ConstraintID) {
431 case InlineAsm::ConstraintCode::m:
432
433
434 OutOps.push_back(Op);
435 return false;
436 default:
437 break;
438 }
439
440 return true;
441}
442
443bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType, SDValue N,
446 assert(N.getNumOperands() == 2 && "Attempting to fold in a non-binary op");
447
448
449
450
451 if (N.getOpcode() == ISD::ADD && .getNode()->getFlags().hasNoUnsignedWrap())
452 return false;
453
454 for (size_t i = 0; i < 2; ++i) {
456 SDValue OtherOp = N.getOperand(i == 0 ? 1 : 0);
457
458
461 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), OffsetType);
462 Addr = OtherOp;
463 return true;
464 }
465
466
467 if (!TM.isPositionIndependent()) {
468 if (Op.getOpcode() == WebAssemblyISD::Wrapper)
470
472 Addr = OtherOp;
474 return true;
475 }
476 }
477 }
478 return false;
479}
480
481bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
482 unsigned ConstOpc, SDValue N,
486
487
488 if (!TM.isPositionIndependent()) {
490 if (Op.getOpcode() == WebAssemblyISD::Wrapper)
492
496 CurDAG->getMachineNode(ConstOpc, DL, AddrType,
497 CurDAG->getTargetConstant(0, DL, AddrType)),
498 0);
499 return true;
500 }
501 }
502
503
505 SelectAddrAddOperands(AddrType, N, Offset, Addr))
506 return true;
507
508
509
510 if (N.getOpcode() == ISD::OR) {
511 bool OrIsAdd;
513 OrIsAdd =
514 CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
515 } else {
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;
519 }
520
521 if (OrIsAdd && SelectAddrAddOperands(AddrType, N, Offset, Addr))
522 return true;
523 }
524
525
527 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, AddrType);
529 CurDAG->getMachineNode(ConstOpc, DL, AddrType,
530 CurDAG->getTargetConstant(0, DL, AddrType)),
531 0);
532 return true;
533 }
534
535
536 Offset = CurDAG->getTargetConstant(0, DL, AddrType);
537 Addr = N;
538 return true;
539}
540
543 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32, Op, Offset, Addr);
544}
545
548 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);
549}
550
551
552
555 return new WebAssemblyDAGToDAGISelLegacy(TM, OptLevel);
556}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 SDValue getTagSymNode(int Tag, SelectionDAG *DAG)
Definition WebAssemblyISelDAGToDAG.cpp:112
static APInt encodeFunctionSignature(SelectionDAG *DAG, SDLoc &DL, SmallVector< MVT, 4 > &Returns, SmallVector< MVT, 4 > &Params)
Definition WebAssemblyISelDAGToDAG.cpp:123
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.
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.
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)
#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...
@ 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
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - 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.
Definition WebAssemblyISelDAGToDAG.cpp:553
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 - 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.
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.