LLVM 24.0.0git
WebAssemblyISelDAGToDAG.cpp
Go to the documentation of this file.
1//- WebAssemblyISelDAGToDAG.cpp - A dag to dag inst selector for WebAssembly -//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file defines an instruction selector for the WebAssembly target.
11///
12//===----------------------------------------------------------------------===//
13
15#include "WebAssembly.h"
24#include "llvm/IR/Function.h" // To access function attributes.
25#include "llvm/IR/IntrinsicsWebAssembly.h"
28#include "llvm/Support/Debug.h"
31
32using namespace llvm;
33
34#define DEBUG_TYPE "wasm-isel"
35#define PASS_NAME "WebAssembly Instruction Selection"
36
37//===--------------------------------------------------------------------===//
38/// WebAssembly-specific code to select WebAssembly machine instructions for
39/// SelectionDAG operations.
40///
41namespace {
42class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
43 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
44 /// right decision when generating code for different targets.
45 const WebAssemblySubtarget *Subtarget;
46
47public:
48 WebAssemblyDAGToDAGISel() = delete;
49
50 WebAssemblyDAGToDAGISel(WebAssemblyTargetMachine &TM,
51 CodeGenOptLevel OptLevel)
52 : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
53
54 bool runOnMachineFunction(MachineFunction &MF) override {
55 LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
56 "********** Function: "
57 << MF.getName() << '\n');
58
59 Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
60
62 }
63
64 void PreprocessISelDAG() override;
65
66 void Select(SDNode *Node) override;
67
68 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
69 InlineAsm::ConstraintCode ConstraintID,
70 std::vector<SDValue> &OutOps) override;
71
72 bool SelectAddrOperands32(SDValue Op, SDValue &Offset, SDValue &Addr);
73 bool SelectAddrOperands64(SDValue Op, SDValue &Offset, SDValue &Addr);
74 bool SelectAtomicAddrOperands(SDNode *Op, SDValue N, SDValue &Offset,
75 SDValue &Addr, SDValue &Order, bool Is64);
76 bool SelectAtomicAddrOperands32(SDNode *Op, SDValue N, SDValue &Offset,
77 SDValue &Addr, SDValue &Order);
78 bool SelectAtomicAddrOperands64(SDNode *Op, SDValue N, SDValue &Offset,
79 SDValue &Addr, SDValue &Order);
80
81// Include the pieces autogenerated from the target description.
82#include "WebAssemblyGenDAGISel.inc"
83
84private:
85 // add select functions here...
86
87 bool SelectAddrOperands(MVT AddrType, unsigned ConstOpc, SDValue Op,
88 SDValue &Offset, SDValue &Addr);
89 bool SelectAddrAddOperands(MVT OffsetType, SDValue N, SDValue &Offset,
90 SDValue &Addr);
91};
92
93class WebAssemblyDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
94public:
95 static char ID;
96 explicit WebAssemblyDAGToDAGISelLegacy(WebAssemblyTargetMachine &TM,
97 CodeGenOptLevel OptLevel)
99 ID, std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
100};
101} // end anonymous namespace
102
103char WebAssemblyDAGToDAGISelLegacy::ID;
104
105INITIALIZE_PASS(WebAssemblyDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false,
106 false)
107
108void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {
109 // Stack objects that should be allocated to locals are hoisted to WebAssembly
110 // locals when they are first used. However for those without uses, we hoist
111 // them here. It would be nice if there were some hook to do this when they
112 // are added to the MachineFrameInfo, but that's not the case right now.
113 MachineFrameInfo &FrameInfo = MF->getFrameInfo();
114 for (int Idx = 0; Idx < FrameInfo.getObjectIndexEnd(); Idx++)
116
118}
119
120static SDValue getTagSymNode(int Tag, SelectionDAG *DAG) {
122 auto &MF = DAG->getMachineFunction();
123 const auto &TLI = DAG->getTargetLoweringInfo();
124 MVT PtrVT = TLI.getPointerTy(DAG->getDataLayout());
125 const char *SymName = Tag == WebAssembly::CPP_EXCEPTION
126 ? MF.createExternalSymbolName("__cpp_exception")
127 : MF.createExternalSymbolName("__c_longjmp");
128 return DAG->getTargetExternalSymbol(SymName, PtrVT);
129}
130
132 SmallVector<MVT, 4> &Returns,
133 SmallVector<MVT, 4> &Params) {
134 auto toWasmValType = [](MVT VT) {
135 if (VT == MVT::i32) {
136 return wasm::ValType::I32;
137 }
138 if (VT == MVT::i64) {
139 return wasm::ValType::I64;
140 }
141 if (VT == MVT::f32) {
142 return wasm::ValType::F32;
143 }
144 if (VT == MVT::f64) {
145 return wasm::ValType::F64;
146 }
147 if (VT == MVT::externref) {
149 }
150 if (VT == MVT::funcref) {
152 }
153 if (VT == MVT::exnref) {
155 }
156 LLVM_DEBUG(errs() << "Unhandled type for llvm.wasm.ref.test.func: " << VT
157 << "\n");
158 llvm_unreachable("Unhandled type for llvm.wasm.ref.test.func");
159 };
160 auto NParams = Params.size();
161 auto NReturns = Returns.size();
162 auto BitWidth = (NParams + NReturns + 2) * 64;
163 auto Sig = APInt(BitWidth, 0);
164
165 // Annoying special case: if getSignificantBits() <= 64 then InstrEmitter will
166 // emit an Imm instead of a CImm. It simplifies WebAssemblyMCInstLower if we
167 // always emit a CImm. So xor NParams with 0x7ffffff to ensure
168 // getSignificantBits() > 64
169 Sig |= NReturns ^ 0x7ffffff;
170 for (auto &Return : Returns) {
171 auto V = toWasmValType(Return);
172 Sig <<= 64;
173 Sig |= (int64_t)V;
174 }
175 Sig <<= 64;
176 Sig |= NParams;
177 for (auto &Param : Params) {
178 auto V = toWasmValType(Param);
179 Sig <<= 64;
180 Sig |= (int64_t)V;
181 }
182 return Sig;
183}
184
185static unsigned getWebAssemblyMemoryOrder(AtomicOrdering Ordering) {
186 unsigned OrderVal = wasm::WASM_MEM_ORDER_SEQ_CST;
187 switch (Ordering) {
194 break;
197 break;
198 default:
199 llvm_unreachable("Invalid atomic ordering");
200 }
201 return OrderVal;
202}
203
204void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
205 // If we have a custom node, we already have selected!
206 if (Node->isMachineOpcode()) {
207 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
208 Node->setNodeId(-1);
209 return;
210 }
211
212 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());
213 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
214 : WebAssembly::GLOBAL_GET_I32;
215
216 SDLoc DL(Node);
217 MachineFunction &MF = CurDAG->getMachineFunction();
218 switch (Node->getOpcode()) {
219 case ISD::ATOMIC_FENCE: {
220 if (!MF.getSubtarget<WebAssemblySubtarget>().hasAtomics())
221 break;
222
223 uint64_t SyncScopeID = Node->getConstantOperandVal(2);
224 MachineSDNode *Fence = nullptr;
225 switch (SyncScopeID) {
227 // We lower a single-thread fence to a pseudo compiler barrier instruction
228 // preventing instruction reordering. This will not be emitted in final
229 // binary.
230 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,
231 DL, // debug loc
232 MVT::Other, // outchain type
233 Node->getOperand(0) // inchain
234 );
235 break;
236 case SyncScope::System: {
237 unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
238 if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
239 auto Ordering =
240 static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
241 Order = getWebAssemblyMemoryOrder(Ordering);
242 }
243 Fence = CurDAG->getMachineNode(
244 WebAssembly::ATOMIC_FENCE,
245 DL, // debug loc
246 MVT::Other, // outchain type
247 CurDAG->getTargetConstant(Order, DL, MVT::i32), // order
248 Node->getOperand(0) // inchain
249 );
250 break;
251 }
252 default:
253 llvm_unreachable("Unknown scope!");
254 }
255
256 ReplaceNode(Node, Fence);
257 CurDAG->RemoveDeadNode(Node);
258 return;
259 }
260
262 unsigned IntNo = Node->getConstantOperandVal(0);
263 switch (IntNo) {
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);
269 return;
270 }
271
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);
277 return;
278 }
279 case Intrinsic::wasm_ptr_to_funcref: {
280 // Convert a function pointer to a funcref by reading the corresponding
281 // entry from the __indirect_function_table.
282 MachineFunction &MF = CurDAG->getMachineFunction();
284 MCSymbol *Table = WebAssembly::getOrCreateFunctionTableSymbol(
285 MF.getContext(), Subtarget);
286 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
287 SDValue FuncPtr = Node->getOperand(1);
288 if (Subtarget->hasAddr64() && FuncPtr.getValueType() == MVT::i64) {
289 // table.get expects an i32 but on 64 bit platforms the function pointer
290 // is an i64. In that case, i32.wrap_i64 to convert.
291 FuncPtr = SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64, DL,
292 MVT::i32, FuncPtr),
293 0);
294 }
295 MachineSDNode *FuncRef = CurDAG->getMachineNode(
296 WebAssembly::TABLE_GET_FUNCREF, DL, MVT::funcref, TableSym, FuncPtr);
297 ReplaceNode(Node, FuncRef);
298 return;
299 }
300 case Intrinsic::wasm_ref_test_func: {
301 // First emit the TABLE_GET instruction to convert function pointer ==>
302 // funcref
303 MachineFunction &MF = CurDAG->getMachineFunction();
305 MCSymbol *Table = WebAssembly::getOrCreateFunctionTableSymbol(
306 MF.getContext(), Subtarget);
307 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);
308 SDValue FuncPtr = Node->getOperand(1);
309 if (Subtarget->hasAddr64() && FuncPtr.getValueType() == MVT::i64) {
310 // table.get expects an i32 but on 64 bit platforms the function pointer
311 // is an i64. In that case, i32.wrap_i64 to convert.
312 FuncPtr = SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64, DL,
313 MVT::i32, FuncPtr),
314 0);
315 }
316 SDValue FuncRef =
317 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,
318 MVT::funcref, TableSym, FuncPtr),
319 0);
320
321 // Encode the signature information into the type index placeholder.
322 // This gets decoded and converted into the actual type signature in
323 // WebAssemblyMCInstLower.cpp.
324 SmallVector<MVT, 4> Params;
325 SmallVector<MVT, 4> Returns;
326
327 bool IsParam = false;
328 // Operand 0 is the return register, Operand 1 is the function pointer.
329 // The remaining operands encode the type of the function we are testing
330 // for.
331 for (unsigned I = 2, E = Node->getNumOperands(); I < E; ++I) {
332 MVT VT = Node->getOperand(I).getValueType().getSimpleVT();
333 if (VT == MVT::Untyped) {
334 IsParam = true;
335 continue;
336 }
337 if (IsParam) {
338 Params.push_back(VT);
339 } else {
340 Returns.push_back(VT);
341 }
342 }
343 auto Sig = encodeFunctionSignature(CurDAG, DL, Returns, Params);
344
345 auto SigOp = CurDAG->getTargetConstant(
346 Sig, DL, EVT::getIntegerVT(*CurDAG->getContext(), Sig.getBitWidth()));
347 MachineSDNode *RefTestNode = CurDAG->getMachineNode(
348 WebAssembly::REF_TEST_FUNCREF, DL, MVT::i32, {SigOp, FuncRef});
349 ReplaceNode(Node, RefTestNode);
350 return;
351 }
352 }
353 break;
354 }
355
357 unsigned IntNo = Node->getConstantOperandVal(1);
358 const auto &TLI = CurDAG->getTargetLoweringInfo();
359 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());
360 switch (IntNo) {
361 case Intrinsic::wasm_tls_base: {
362 MachineSDNode *TLSBase = llvm::WebAssembly::getTLSBase(
363 *CurDAG, DL, Subtarget, Node->getOperand(0));
364 ReplaceNode(Node, TLSBase);
365 return;
366 }
367
368 case Intrinsic::wasm_catch: {
369 int Tag = Node->getConstantOperandVal(2);
370 SDValue SymNode = getTagSymNode(Tag, CurDAG);
371 unsigned CatchOpcode = WebAssembly::WasmUseLegacyEH
372 ? WebAssembly::CATCH_LEGACY
373 : WebAssembly::CATCH;
374 MachineSDNode *Catch =
375 CurDAG->getMachineNode(CatchOpcode, DL,
376 {
377 PtrVT, // exception pointer
378 MVT::Other // outchain type
379 },
380 {
381 SymNode, // exception symbol
382 Node->getOperand(0) // inchain
383 });
384 ReplaceNode(Node, Catch);
385 return;
386 }
387 }
388 break;
389 }
390
391 case ISD::INTRINSIC_VOID: {
392 unsigned IntNo = Node->getConstantOperandVal(1);
393 switch (IntNo) {
394 case Intrinsic::wasm_throw: {
395 int Tag = Node->getConstantOperandVal(2);
396 SDValue SymNode = getTagSymNode(Tag, CurDAG);
397 MachineSDNode *Throw =
398 CurDAG->getMachineNode(WebAssembly::THROW, DL,
399 MVT::Other, // outchain type
400 {
401 SymNode, // exception symbol
402 Node->getOperand(3), // thrown value
403 Node->getOperand(0) // inchain
404 });
405 ReplaceNode(Node, Throw);
406 return;
407 }
408 case Intrinsic::wasm_rethrow: {
409 // RETHROW's BB argument will be populated in LateEHPrepare. Just use a
410 // '0' as a placeholder for now.
411 MachineSDNode *Rethrow = CurDAG->getMachineNode(
412 WebAssembly::RETHROW, DL,
413 MVT::Other, // outchain type
414 {
415 CurDAG->getConstant(0, DL, MVT::i32), // placeholder
416 Node->getOperand(0) // inchain
417 });
418 ReplaceNode(Node, Rethrow);
419 return;
420 }
421 }
422 break;
423 }
424
427 // CALL has both variable operands and variable results, but ISel only
428 // supports one or the other. Split calls into two nodes glued together, one
429 // for the operands and one for the results. These two nodes will be
430 // recombined in a custom inserter hook into a single MachineInstr.
432 for (size_t i = 1; i < Node->getNumOperands(); ++i) {
433 SDValue Op = Node->getOperand(i);
434 // Remove the wrapper when the call target is a function, an external
435 // symbol (which will be lowered to a library function), or an alias of
436 // a function. If the target is not a function/external symbol, we
437 // shouldn't remove the wrapper, because we cannot call it directly and
438 // instead we want it to be loaded with a CONST instruction and called
439 // with a call_indirect later.
440 if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper) {
441 SDValue NewOp = Op->getOperand(0);
442 if (auto *GlobalOp = dyn_cast<GlobalAddressSDNode>(NewOp.getNode())) {
443 if (isa<Function>(
444 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))
445 Op = NewOp;
446 } else if (isa<ExternalSymbolSDNode>(NewOp.getNode())) {
447 Op = NewOp;
448 }
449 }
450 Ops.push_back(Op);
451 }
452
453 // Add the chain last
454 Ops.push_back(Node->getOperand(0));
455 bool IsRetCall = Node->getOpcode() == WebAssemblyISD::RET_CALL;
456 unsigned Params =
457 IsRetCall ? WebAssembly::RET_CALL_PARAMS : WebAssembly::CALL_PARAMS;
458 MachineSDNode *CallParams =
459 CurDAG->getMachineNode(Params, DL, MVT::Glue, Ops);
460
461 unsigned Results =
462 IsRetCall ? WebAssembly::RET_CALL_RESULTS : WebAssembly::CALL_RESULTS;
463
464 SDValue Link(CallParams, 0);
465 MachineSDNode *CallResults =
466 CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);
467 ReplaceNode(Node, CallResults);
468 return;
469 }
470
471 default:
472 break;
473 }
474
475 // Select the default instruction.
476 SelectCode(Node);
477}
478
479bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(
480 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
481 std::vector<SDValue> &OutOps) {
482 switch (ConstraintID) {
483 case InlineAsm::ConstraintCode::m:
484 // We just support simple memory operands that just have a single address
485 // operand and need no special handling.
486 OutOps.push_back(Op);
487 return false;
488 default:
489 break;
490 }
491
492 return true;
493}
494
495bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType, SDValue N,
496 SDValue &Offset,
497 SDValue &Addr) {
498 assert(N.getNumOperands() == 2 && "Attempting to fold in a non-binary op");
499
500 // WebAssembly constant offsets are performed as unsigned with infinite
501 // precision, so we need to check for NoUnsignedWrap so that we don't fold an
502 // offset for an add that needs wrapping.
503 if (N.getOpcode() == ISD::ADD && !N.getNode()->getFlags().hasNoUnsignedWrap())
504 return false;
505
506 for (size_t i = 0; i < 2; ++i) {
507 SDValue Op = N.getOperand(i);
508 SDValue OtherOp = N.getOperand(i == 0 ? 1 : 0);
509
510 // Folds constants in an add into the offset.
511 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op)) {
512 Offset =
513 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), OffsetType);
514 Addr = OtherOp;
515 return true;
516 }
517
518 // Fold target global addresses into the offset.
519 if (!TM.isPositionIndependent()) {
520 if (Op.getOpcode() == WebAssemblyISD::Wrapper)
521 Op = Op.getOperand(0);
522
523 if (Op.getOpcode() == ISD::TargetGlobalAddress) {
524 Addr = OtherOp;
525 Offset = Op;
526 return true;
527 }
528 }
529 }
530 return false;
531}
532
533bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,
534 unsigned ConstOpc, SDValue N,
535 SDValue &Offset,
536 SDValue &Addr) {
537 SDLoc DL(N);
538
539 // Fold target global addresses into the offset.
540 if (!TM.isPositionIndependent()) {
541 SDValue Op(N);
542 if (Op.getOpcode() == WebAssemblyISD::Wrapper)
543 Op = Op.getOperand(0);
544
545 if (Op.getOpcode() == ISD::TargetGlobalAddress) {
546 Offset = Op;
547 Addr = SDValue(
548 CurDAG->getMachineNode(ConstOpc, DL, AddrType,
549 CurDAG->getTargetConstant(0, DL, AddrType)),
550 0);
551 return true;
552 }
553 }
554
555 // Fold anything inside an add into the offset.
556 if (N.getOpcode() == ISD::ADD &&
557 SelectAddrAddOperands(AddrType, N, Offset, Addr))
558 return true;
559
560 // Likewise, treat an 'or' node as an 'add' if the or'ed bits are known to be
561 // zero and fold them into the offset too.
562 if (N.getOpcode() == ISD::OR) {
563 bool OrIsAdd;
564 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
565 OrIsAdd =
566 CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
567 } else {
568 KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
569 KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
570 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;
571 }
572
573 if (OrIsAdd && SelectAddrAddOperands(AddrType, N, Offset, Addr))
574 return true;
575 }
576
577 // Fold constant addresses into the offset.
578 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
579 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, AddrType);
580 Addr = SDValue(
581 CurDAG->getMachineNode(ConstOpc, DL, AddrType,
582 CurDAG->getTargetConstant(0, DL, AddrType)),
583 0);
584 return true;
585 }
586
587 // Else it's a plain old load/store with no offset.
588 Offset = CurDAG->getTargetConstant(0, DL, AddrType);
589 Addr = N;
590 return true;
591}
592
593bool WebAssemblyDAGToDAGISel::SelectAddrOperands32(SDValue Op, SDValue &Offset,
594 SDValue &Addr) {
595 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32, Op, Offset, Addr);
596}
597
598bool WebAssemblyDAGToDAGISel::SelectAddrOperands64(SDValue Op, SDValue &Offset,
599 SDValue &Addr) {
600 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);
601}
602
604 while (N) {
605 if (auto *MemNode = dyn_cast<MemSDNode>(N))
606 return MemNode;
607 switch (N->getOpcode()) {
608 case ISD::ZERO_EXTEND:
609 case ISD::SIGN_EXTEND:
610 case ISD::ANY_EXTEND:
612 case ISD::AssertZext:
613 case ISD::AssertSext:
614 case ISD::TRUNCATE:
615 case ISD::BITCAST:
616 case ISD::AND:
617 N = N->getOperand(0).getNode();
618 break;
619 default:
620 return nullptr;
621 }
622 }
623 return nullptr;
624}
625
626bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *Op, SDValue N,
627 SDValue &Offset,
628 SDValue &Addr,
629 SDValue &Order,
630 bool Is64) {
631 auto *MemNode = findMemSDNode(Op);
632 if (!MemNode)
633 return false;
634
635 bool Match = Is64 ? SelectAddrOperands64(N, Offset, Addr)
636 : SelectAddrOperands32(N, Offset, Addr);
637 if (!Match)
638 return false;
639
640 auto Ordering = MemNode->getMergedOrdering();
641 unsigned OrderVal = wasm::WASM_MEM_ORDER_SEQ_CST;
642 if (Subtarget->hasRelaxedAtomics())
643 OrderVal = getWebAssemblyMemoryOrder(Ordering);
644 Order = CurDAG->getTargetConstant(OrderVal, SDLoc(Op), MVT::i32);
645 return true;
646}
647
648bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *Op, SDValue N,
649 SDValue &Offset,
650 SDValue &Addr,
651 SDValue &Order) {
652 return SelectAtomicAddrOperands(Op, N, Offset, Addr, Order, /*Is64=*/false);
653}
654
655bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *Op, SDValue N,
656 SDValue &Offset,
657 SDValue &Addr,
658 SDValue &Order) {
659 return SelectAtomicAddrOperands(Op, N, Offset, Addr, Order, /*Is64=*/true);
660}
661
662/// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
663/// for instruction scheduling.
667 std::make_unique<WebAssemblyDAGToDAGISel>(TM, OptLevel)) {}
668
671 CodeGenOptLevel OptLevel) {
672 return new WebAssemblyDAGToDAGISelLegacy(TM, OptLevel);
673}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
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")
#define DEBUG_TYPE
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define I(x, y, z)
Definition MD5.cpp:57
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define PASS_NAME
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.
Definition APInt.h:78
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
Definition DataLayout.h:501
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
Machine Value Type.
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:871
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ 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.
Definition ISDOpcodes.h:862
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition ISDOpcodes.h:187
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:868
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:906
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:749
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:874
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition ISDOpcodes.h:64
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:58
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:61
MachineSDNode * getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain=SDValue())
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
@ WASM_MEM_ORDER_SEQ_CST
Definition Wasm.h:86
@ WASM_MEM_ORDER_ACQ_REL
Definition Wasm.h:87
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:227
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...
Definition Casting.h:547
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.
Definition BitVector.h:878
#define N
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61