LLVM 24.0.0git
WebAssemblyISelLowering.cpp
Go to the documentation of this file.
1//=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
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 implements the WebAssemblyTargetLowering class.
11///
12//===----------------------------------------------------------------------===//
13
32#include "llvm/IR/Function.h"
33#include "llvm/IR/Intrinsics.h"
34#include "llvm/IR/IntrinsicsWebAssembly.h"
39using namespace llvm;
40
41#define DEBUG_TYPE "wasm-lower"
42
44 const TargetMachine &TM, const WebAssemblySubtarget &STI)
45 : TargetLowering(TM, STI), Subtarget(&STI) {
46 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
47
48 // Set the load count for memcmp expand optimization
51
52 // Booleans always contain 0 or 1.
54 // Except in SIMD vectors
56 // We don't know the microarchitecture here, so just reduce register pressure.
58 // Tell ISel that we have a stack pointer.
60 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
61 // Set up the register classes.
62 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
63 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
64 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
65 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
66 if (Subtarget->hasSIMD128()) {
67 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
68 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
69 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
70 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
71 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
72 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
73 }
74 if (Subtarget->hasFP16()) {
75 addRegisterClass(MVT::v8f16, &WebAssembly::V128RegClass);
76 }
77 if (Subtarget->hasReferenceTypes()) {
78 addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
79 addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);
80 if (Subtarget->hasExceptionHandling()) {
81 addRegisterClass(MVT::exnref, &WebAssembly::EXNREFRegClass);
82 }
83 }
84 // Compute derived properties from the register classes.
85 computeRegisterProperties(Subtarget->getRegisterInfo());
86
87 // Transform loads and stores to pointers in address space 1 to loads and
88 // stores to WebAssembly global variables, outside linear memory.
89 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) {
92 }
93 if (Subtarget->hasSIMD128()) {
94 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
95 MVT::v2f64}) {
98 }
99 }
100 if (Subtarget->hasFP16()) {
101 setOperationAction(ISD::LOAD, MVT::v8f16, Custom);
103 }
104 if (Subtarget->hasReferenceTypes()) {
105 // We need custom load and store lowering for both externref, funcref and
106 // Other. The MVT::Other here represents tables of reference types.
107 for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) {
110 }
111 }
112
120
121 // Take the default expansion for va_arg, va_copy, and va_end. There is no
122 // default action for va_start, so we do that custom.
127
128 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64, MVT::v8f16}) {
129 if (!Subtarget->hasFP16() && T == MVT::v8f16) {
130 continue;
131 }
132 // Don't expand the floating-point types to constant pools.
134 // Expand floating-point comparisons.
138 // Expand floating-point library function operators.
141 // Expand vector FREM, but use a libcall rather than an expansion for scalar
142 if (MVT(T).isVector())
144 else
146 // Note supported floating-point library function operators that otherwise
147 // default to expand.
151 // Support minimum and maximum, which otherwise default to expand.
154 if (Subtarget->hasSIMD128() && MVT(T).isVector()) {
157 }
158 // When experimental v8f16 support is enabled these instructions don't need
159 // to be expanded.
160 if (T != MVT::v8f16) {
163 }
164 if (Subtarget->hasFP16() && T == MVT::f32) {
166 setTruncStoreAction(T, MVT::f16, Legal);
167 } else {
169 setTruncStoreAction(T, MVT::f16, Expand);
170 }
171 }
172
173 // Expand unavailable integer operations.
174 for (auto Op :
178 for (auto T : {MVT::i32, MVT::i64})
180 if (Subtarget->hasSIMD128())
181 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
183 }
184
185 if (Subtarget->hasWideArithmetic()) {
191 }
192
193 if (Subtarget->hasNontrappingFPToInt())
195 for (auto T : {MVT::i32, MVT::i64})
197
198 if (Subtarget->hasRelaxedSIMD()) {
201 {MVT::v4f32, MVT::v2f64}, Custom);
202 }
203
204 // Combine expands these operations, because wasi-libc and emscripten do not
205 // yet have the dedicated libcalls.
208
209 // SIMD-specific configuration
210 if (Subtarget->hasSIMD128()) {
211
213
214 // Combine wide-vector muls, with extend inputs, to extmul_half.
217
218 // Combine vector mask reductions into alltrue/anytrue
220
221 // Convert vector to integer bitcasts to bitmask
223
224 // Hoist bitcasts out of shuffles
226
227 // Combine extends of extract_subvectors into widening ops
229
230 // Combine int_to_fp or fp_extend of extract_vectors and vice versa into
231 // conversions ops
234
235 // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa
236 // into conversion ops
240
242
243 // Support saturating add/sub for i8x16 and i16x8
245 for (auto T : {MVT::v16i8, MVT::v8i16})
247
248 // Support integer abs
249 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
251
252 // Custom lower BUILD_VECTORs to minimize number of replace_lanes
253 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
254 MVT::v2f64})
256
257 if (Subtarget->hasFP16()) {
261 }
262
263 // We have custom shuffle lowering to expose the shuffle mask
264 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
265 MVT::v2f64})
267
268 if (Subtarget->hasFP16())
270
271 // Support splatting
272 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
273 MVT::v2f64})
275
276 setOperationAction(ISD::AVGCEILU, {MVT::v8i16, MVT::v16i8}, Legal);
277
278 // Custom lowering since wasm shifts must have a scalar shift amount
279 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
280 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
282
283 // Custom lower lane accesses to expand out variable indices
285 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
286 MVT::v2f64})
288
289 // There is no i8x16.mul instruction
290 setOperationAction(ISD::MUL, MVT::v16i8, Expand);
291
292 // Expand integer operations supported for scalars but not SIMD
293 for (auto Op :
295 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
297
298 // But we do have integer min and max operations
299 for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
300 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
302
303 // And we have popcnt for i8x16. It can be used to expand ctlz/cttz.
304 setOperationAction(ISD::CTPOP, MVT::v16i8, Legal);
305 setOperationAction(ISD::CTLZ, MVT::v16i8, Expand);
306 setOperationAction(ISD::CTTZ, MVT::v16i8, Expand);
307
308 // Custom lower bit counting operations for other types to scalarize them.
309 for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP})
310 for (auto T : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
312
313 // Expand float operations supported for scalars but not SIMD
316 for (auto T : {MVT::v4f32, MVT::v2f64})
318
319 // Unsigned comparison operations are unavailable for i64x2 vectors.
321 setCondCodeAction(CC, MVT::v2i64, Custom);
322
323 // 64x2 conversions are not in the spec
324 for (auto Op :
326 for (auto T : {MVT::v2i64, MVT::v2f64})
328
329 // But saturating fp_to_int conversions are
331 setOperationAction(Op, MVT::v4i32, Custom);
332 if (Subtarget->hasFP16()) {
333 setOperationAction(Op, MVT::v8i16, Custom);
334 }
335 }
336
337 // Support vector extending
342 }
343
344 if (Subtarget->hasFP16()) {
345 setOperationAction(ISD::FMA, MVT::v8f16, Legal);
346 }
347
348 if (Subtarget->hasRelaxedSIMD()) {
351 }
352
353 // Partial MLA reductions.
355 setPartialReduceMLAAction(Op, MVT::v4i32, MVT::v16i8, Legal);
356 setPartialReduceMLAAction(Op, MVT::v4i32, MVT::v8i16, Legal);
357 }
358 }
359
360 // As a special case, these operators use the type to mean the type to
361 // sign-extend from.
363 if (!Subtarget->hasSignExt()) {
364 // Sign extends are legal only when extending a vector extract
365 auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
366 for (auto T : {MVT::i8, MVT::i16, MVT::i32})
368 }
371
372 // Dynamic stack allocation: use the default expansion.
376
380
381 // Expand these forms; we pattern-match the forms that we can handle in isel.
382 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
383 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
385
386 if (Subtarget->hasReferenceTypes())
387 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
388 for (auto T : {MVT::externref, MVT::funcref})
390
391 // There is no vector conditional select instruction
392 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
393 MVT::v2f64, MVT::v8f16})
395
396 // We have custom switch handling.
398
399 // WebAssembly doesn't have:
400 // - Floating-point extending loads.
401 // - Floating-point truncating stores.
402 // - i1 extending loads.
403 // - truncating SIMD stores and most extending loads
404 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
405 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
406 for (auto T : MVT::integer_valuetypes())
407 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
408 setLoadExtAction(Ext, T, MVT::i1, Promote);
409 if (Subtarget->hasSIMD128()) {
410 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
411 MVT::v2f64}) {
412 for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
413 if (MVT(T) != MemT) {
415 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
416 setLoadExtAction(Ext, T, MemT, Expand);
417 }
418 }
419 }
420 // But some vector extending loads are legal
421 for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
422 setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
423 setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
424 setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
425 }
426 setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal);
427 }
428
429 // Don't do anything clever with build_pairs
431
432 // Trap lowers to wasm unreachable
433 setOperationAction(ISD::TRAP, MVT::Other, Legal);
435
436 // Exception handling intrinsics
440
442
443 // Always convert switches to br_tables unless there is only one case, which
444 // is equivalent to a simple branch. This reduces code size for wasm, and we
445 // defer possible jump table optimizations to the VM.
447}
448
450WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(
451 const AtomicRMWInst *AI) const {
452 // We have wasm instructions for these
453 switch (AI->getOperation()) {
461 default:
462 break;
463 }
465}
466
467bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const {
468 // Implementation copied from X86TargetLowering.
469 unsigned Opc = VecOp.getOpcode();
470
471 // Assume target opcodes can't be scalarized.
472 // TODO - do we have any exceptions?
474 return false;
475
476 // If the vector op is not supported, try to convert to scalar.
477 EVT VecVT = VecOp.getValueType();
479 return true;
480
481 // If the vector op is supported, but the scalar op is not, the transform may
482 // not be worthwhile.
483 EVT ScalarVT = VecVT.getScalarType();
484 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
485}
486
487FastISel *WebAssemblyTargetLowering::createFastISel(
488 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo,
489 const LibcallLoweringInfo *LibcallLowering) const {
490 return WebAssembly::createFastISel(FuncInfo, LibInfo, LibcallLowering);
491}
492
493MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
494 EVT VT) const {
495 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
496 if (BitWidth > 1 && BitWidth < 8)
497 BitWidth = 8;
498
499 if (BitWidth > 64) {
500 // The shift will be lowered to a libcall, and compiler-rt libcalls expect
501 // the count to be an i32.
502 BitWidth = 32;
504 "32-bit shift counts ought to be enough for anyone");
505 }
506
509 "Unable to represent scalar shift amount type");
510 return Result;
511}
512
513// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
514// undefined result on invalid/overflow, to the WebAssembly opcode, which
515// traps on invalid/overflow.
518 const TargetInstrInfo &TII,
519 bool IsUnsigned, bool Int64,
520 bool Float64, unsigned LoweredOpcode) {
522
523 Register OutReg = MI.getOperand(0).getReg();
524 Register InReg = MI.getOperand(1).getReg();
525
526 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
527 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
528 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
529 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
530 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
531 unsigned Eqz = WebAssembly::EQZ_I32;
532 unsigned And = WebAssembly::AND_I32;
533 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
534 int64_t Substitute = IsUnsigned ? 0 : Limit;
535 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
536 auto &Context = BB->getParent()->getFunction().getContext();
537 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
538
539 const BasicBlock *LLVMBB = BB->getBasicBlock();
540 MachineFunction *F = BB->getParent();
541 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
542 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
543 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
544
546 F->insert(It, FalseMBB);
547 F->insert(It, TrueMBB);
548 F->insert(It, DoneMBB);
549
550 // Transfer the remainder of BB and its successor edges to DoneMBB.
551 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
553
554 BB->addSuccessor(TrueMBB);
555 BB->addSuccessor(FalseMBB);
556 TrueMBB->addSuccessor(DoneMBB);
557 FalseMBB->addSuccessor(DoneMBB);
558
559 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
560 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
561 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
562 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
563 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
564 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
565 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
566
567 MI.eraseFromParent();
568 // For signed numbers, we can do a single comparison to determine whether
569 // fabs(x) is within range.
570 if (IsUnsigned) {
571 Tmp0 = InReg;
572 } else {
573 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
574 }
575 BuildMI(BB, DL, TII.get(FConst), Tmp1)
576 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
577 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
578
579 // For unsigned numbers, we have to do a separate comparison with zero.
580 if (IsUnsigned) {
581 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
582 Register SecondCmpReg =
583 MRI.createVirtualRegister(&WebAssembly::I32RegClass);
584 Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
585 BuildMI(BB, DL, TII.get(FConst), Tmp1)
586 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
587 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
588 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
589 CmpReg = AndReg;
590 }
591
592 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
593
594 // Create the CFG diamond to select between doing the conversion or using
595 // the substitute value.
596 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
597 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
598 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
599 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
600 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
601 .addReg(FalseReg)
602 .addMBB(FalseMBB)
603 .addReg(TrueReg)
604 .addMBB(TrueMBB);
605
606 return DoneMBB;
607}
608
609// Lower a `MEMCPY` instruction into a CFG triangle around a `MEMORY_COPY`
610// instruction to handle the zero-length case.
613 const TargetInstrInfo &TII, bool Int64) {
615
616 MachineOperand DstMem = MI.getOperand(0);
617 MachineOperand SrcMem = MI.getOperand(1);
618 MachineOperand Dst = MI.getOperand(2);
619 MachineOperand Src = MI.getOperand(3);
620 MachineOperand Len = MI.getOperand(4);
621
622 // If the length is a constant, we don't actually need the check.
623 if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
624 if (Def->getOpcode() == WebAssembly::CONST_I32 ||
625 Def->getOpcode() == WebAssembly::CONST_I64) {
626 if (Def->getOperand(1).getImm() == 0) {
627 // A zero-length memcpy is a no-op.
628 MI.eraseFromParent();
629 return BB;
630 }
631 // A non-zero-length memcpy doesn't need a zero check.
632 unsigned MemoryCopy =
633 Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
634 BuildMI(*BB, MI, DL, TII.get(MemoryCopy))
635 .add(DstMem)
636 .add(SrcMem)
637 .add(Dst)
638 .add(Src)
639 .add(Len);
640 MI.eraseFromParent();
641 return BB;
642 }
643 }
644
645 // We're going to add an extra use to `Len` to test if it's zero; that
646 // use shouldn't be a kill, even if the original use is.
647 MachineOperand NoKillLen = Len;
648 NoKillLen.setIsKill(false);
649
650 // Decide on which `MachineInstr` opcode we're going to use.
651 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
652 unsigned MemoryCopy =
653 Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
654
655 // Create two new basic blocks; one for the new `memory.fill` that we can
656 // branch over, and one for the rest of the instructions after the original
657 // `memory.fill`.
658 const BasicBlock *LLVMBB = BB->getBasicBlock();
659 MachineFunction *F = BB->getParent();
660 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
661 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
662
664 F->insert(It, TrueMBB);
665 F->insert(It, DoneMBB);
666
667 // Transfer the remainder of BB and its successor edges to DoneMBB.
668 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
670
671 // Connect the CFG edges.
672 BB->addSuccessor(TrueMBB);
673 BB->addSuccessor(DoneMBB);
674 TrueMBB->addSuccessor(DoneMBB);
675
676 // Create a virtual register for the `Eqz` result.
677 unsigned EqzReg;
678 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
679
680 // Erase the original `memory.copy`.
681 MI.eraseFromParent();
682
683 // Test if `Len` is zero.
684 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
685
686 // Insert a new `memory.copy`.
687 BuildMI(TrueMBB, DL, TII.get(MemoryCopy))
688 .add(DstMem)
689 .add(SrcMem)
690 .add(Dst)
691 .add(Src)
692 .add(Len);
693
694 // Create the CFG triangle.
695 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
696 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
697
698 return DoneMBB;
699}
700
701// Lower a `MEMSET` instruction into a CFG triangle around a `MEMORY_FILL`
702// instruction to handle the zero-length case.
705 const TargetInstrInfo &TII, bool Int64) {
707
708 MachineOperand Mem = MI.getOperand(0);
709 MachineOperand Dst = MI.getOperand(1);
710 MachineOperand Val = MI.getOperand(2);
711 MachineOperand Len = MI.getOperand(3);
712
713 // If the length is a constant, we don't actually need the check.
714 if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
715 if (Def->getOpcode() == WebAssembly::CONST_I32 ||
716 Def->getOpcode() == WebAssembly::CONST_I64) {
717 if (Def->getOperand(1).getImm() == 0) {
718 // A zero-length memset is a no-op.
719 MI.eraseFromParent();
720 return BB;
721 }
722 // A non-zero-length memset doesn't need a zero check.
723 unsigned MemoryFill =
724 Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
725 BuildMI(*BB, MI, DL, TII.get(MemoryFill))
726 .add(Mem)
727 .add(Dst)
728 .add(Val)
729 .add(Len);
730 MI.eraseFromParent();
731 return BB;
732 }
733 }
734
735 // We're going to add an extra use to `Len` to test if it's zero; that
736 // use shouldn't be a kill, even if the original use is.
737 MachineOperand NoKillLen = Len;
738 NoKillLen.setIsKill(false);
739
740 // Decide on which `MachineInstr` opcode we're going to use.
741 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
742 unsigned MemoryFill =
743 Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
744
745 // Create two new basic blocks; one for the new `memory.fill` that we can
746 // branch over, and one for the rest of the instructions after the original
747 // `memory.fill`.
748 const BasicBlock *LLVMBB = BB->getBasicBlock();
749 MachineFunction *F = BB->getParent();
750 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
751 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
752
754 F->insert(It, TrueMBB);
755 F->insert(It, DoneMBB);
756
757 // Transfer the remainder of BB and its successor edges to DoneMBB.
758 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
760
761 // Connect the CFG edges.
762 BB->addSuccessor(TrueMBB);
763 BB->addSuccessor(DoneMBB);
764 TrueMBB->addSuccessor(DoneMBB);
765
766 // Create a virtual register for the `Eqz` result.
767 unsigned EqzReg;
768 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
769
770 // Erase the original `memory.fill`.
771 MI.eraseFromParent();
772
773 // Test if `Len` is zero.
774 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
775
776 // Insert a new `memory.copy`.
777 BuildMI(TrueMBB, DL, TII.get(MemoryFill)).add(Mem).add(Dst).add(Val).add(Len);
778
779 // Create the CFG triangle.
780 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
781 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
782
783 return DoneMBB;
784}
785
786static MachineBasicBlock *
789 const TargetInstrInfo &TII) {
790 assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
791 CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
792 bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
793 MachineInstr &CallParams = *CallResults.getPrevNode();
794 assert(CallParams.getOpcode() ==
795 (IsRetCall ? WebAssembly::RET_CALL_PARAMS : WebAssembly::CALL_PARAMS));
796
797 bool IsIndirect =
798 CallParams.getOperand(0).isReg() || CallParams.getOperand(0).isFI();
799
800 bool IsFuncrefCall = false;
801 if (IsIndirect && CallParams.getOperand(0).isReg()) {
802 Register Reg = CallParams.getOperand(0).getReg();
803 const MachineFunction *MF = BB->getParent();
804 const MachineRegisterInfo &MRI = MF->getRegInfo();
805 const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
806 IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
807 assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
808 }
809
810 unsigned CallOp;
811 if (IsIndirect && IsRetCall) {
812 CallOp = WebAssembly::RET_CALL_INDIRECT;
813 } else if (IsIndirect) {
814 CallOp = WebAssembly::CALL_INDIRECT;
815 } else if (IsRetCall) {
816 CallOp = WebAssembly::RET_CALL;
817 } else {
818 CallOp = WebAssembly::CALL;
819 }
820
821 MachineFunction &MF = *BB->getParent();
822 const MCInstrDesc &MCID = TII.get(CallOp);
823 MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
824
825 // Move the function pointer to the end of the arguments for indirect calls
826 if (IsIndirect) {
827 auto FnPtr = CallParams.getOperand(0);
828 CallParams.removeOperand(0);
829
830 // For funcrefs, call_indirect is done through __funcref_call_table and the
831 // funcref is always installed in slot 0 of the table, therefore instead of
832 // having the function pointer added at the end of the params list, a zero
833 // (the index in
834 // __funcref_call_table is added).
835 if (IsFuncrefCall) {
836 Register RegZero =
837 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
838 MachineInstrBuilder MIBC0 =
839 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
840
841 BB->insert(CallResults.getIterator(), MIBC0);
842 MachineInstrBuilder(MF, CallParams).addReg(RegZero);
843 } else
844 CallParams.addOperand(FnPtr);
845 }
846
847 for (auto Def : CallResults.defs())
848 MIB.add(Def);
849
850 if (IsIndirect) {
851 // Placeholder for the type index.
852 // This gets replaced with the correct value in WebAssemblyMCInstLower.cpp
853 MIB.addImm(0);
854 // The table into which this call_indirect indexes.
855 MCSymbolWasm *Table = IsFuncrefCall
857 MF.getContext(), Subtarget)
859 MF.getContext(), Subtarget);
860 if (Subtarget->hasCallIndirectOverlong()) {
861 MIB.addSym(Table);
862 } else {
863 // For the MVP there is at most one table whose number is 0, but we can't
864 // write a table symbol or issue relocations. Instead we just ensure the
865 // table is live and write a zero.
866 Table->setNoStrip();
867 MIB.addImm(0);
868 }
869 }
870
871 // Avoid duplicating the implicit operands.
872 for (auto Use : CallParams.explicit_uses())
873 MIB.add(Use);
874
875 BB->insert(CallResults.getIterator(), MIB);
876 CallParams.eraseFromParent();
877 CallResults.eraseFromParent();
878
879 // If this is a funcref call, to avoid hidden GC roots, we need to clear the
880 // table slot with ref.null upon call_indirect return.
881 //
882 // This generates the following code, which comes right after a call_indirect
883 // of a funcref:
884 //
885 // i32.const 0
886 // ref.null func
887 // table.set __funcref_call_table
888 if (IsIndirect && IsFuncrefCall) {
890 MF.getContext(), Subtarget);
891 Register RegZero =
892 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
893 MachineInstr *Const0 =
894 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
895 BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
896
897 Register RegFuncref =
898 MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
899 MachineInstr *RefNull =
900 BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref);
901 BB->insertAfter(Const0->getIterator(), RefNull);
902
903 MachineInstr *TableSet =
904 BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
905 .addSym(Table)
906 .addReg(RegZero)
907 .addReg(RegFuncref);
908 BB->insertAfter(RefNull->getIterator(), TableSet);
909 }
910
911 return BB;
912}
913
914MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
915 MachineInstr &MI, MachineBasicBlock *BB) const {
916 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
917 DebugLoc DL = MI.getDebugLoc();
918
919 switch (MI.getOpcode()) {
920 default:
921 llvm_unreachable("Unexpected instr type to insert");
922 case WebAssembly::FP_TO_SINT_I32_F32:
923 return LowerFPToInt(MI, DL, BB, TII, false, false, false,
924 WebAssembly::I32_TRUNC_S_F32);
925 case WebAssembly::FP_TO_UINT_I32_F32:
926 return LowerFPToInt(MI, DL, BB, TII, true, false, false,
927 WebAssembly::I32_TRUNC_U_F32);
928 case WebAssembly::FP_TO_SINT_I64_F32:
929 return LowerFPToInt(MI, DL, BB, TII, false, true, false,
930 WebAssembly::I64_TRUNC_S_F32);
931 case WebAssembly::FP_TO_UINT_I64_F32:
932 return LowerFPToInt(MI, DL, BB, TII, true, true, false,
933 WebAssembly::I64_TRUNC_U_F32);
934 case WebAssembly::FP_TO_SINT_I32_F64:
935 return LowerFPToInt(MI, DL, BB, TII, false, false, true,
936 WebAssembly::I32_TRUNC_S_F64);
937 case WebAssembly::FP_TO_UINT_I32_F64:
938 return LowerFPToInt(MI, DL, BB, TII, true, false, true,
939 WebAssembly::I32_TRUNC_U_F64);
940 case WebAssembly::FP_TO_SINT_I64_F64:
941 return LowerFPToInt(MI, DL, BB, TII, false, true, true,
942 WebAssembly::I64_TRUNC_S_F64);
943 case WebAssembly::FP_TO_UINT_I64_F64:
944 return LowerFPToInt(MI, DL, BB, TII, true, true, true,
945 WebAssembly::I64_TRUNC_U_F64);
946 case WebAssembly::MEMCPY_A32:
947 return LowerMemcpy(MI, DL, BB, TII, false);
948 case WebAssembly::MEMCPY_A64:
949 return LowerMemcpy(MI, DL, BB, TII, true);
950 case WebAssembly::MEMSET_A32:
951 return LowerMemset(MI, DL, BB, TII, false);
952 case WebAssembly::MEMSET_A64:
953 return LowerMemset(MI, DL, BB, TII, true);
954 case WebAssembly::CALL_RESULTS:
955 case WebAssembly::RET_CALL_RESULTS:
956 return LowerCallResults(MI, DL, BB, Subtarget, TII);
957 }
958}
959
960std::pair<unsigned, const TargetRegisterClass *>
961WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
962 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
963 // First, see if this is a constraint that directly corresponds to a
964 // WebAssembly register class.
965 if (Constraint.size() == 1) {
966 switch (Constraint[0]) {
967 case 'r':
968 assert(VT != MVT::iPTR && "Pointer MVT not expected here");
969 if (Subtarget->hasSIMD128() && VT.isVector()) {
970 if (VT.getSizeInBits() == 128)
971 return std::make_pair(0U, &WebAssembly::V128RegClass);
972 }
973 if (VT.isInteger() && !VT.isVector()) {
974 if (VT.getSizeInBits() <= 32)
975 return std::make_pair(0U, &WebAssembly::I32RegClass);
976 if (VT.getSizeInBits() <= 64)
977 return std::make_pair(0U, &WebAssembly::I64RegClass);
978 }
979 if (VT.isFloatingPoint() && !VT.isVector()) {
980 switch (VT.getSizeInBits()) {
981 case 32:
982 return std::make_pair(0U, &WebAssembly::F32RegClass);
983 case 64:
984 return std::make_pair(0U, &WebAssembly::F64RegClass);
985 default:
986 break;
987 }
988 }
989 break;
990 default:
991 break;
992 }
993 }
994
996}
997
998bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const {
999 // Assume ctz is a relatively cheap operation.
1000 return true;
1001}
1002
1003bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
1004 // Assume clz is a relatively cheap operation.
1005 return true;
1006}
1007
1008bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
1009 const AddrMode &AM,
1010 Type *Ty, unsigned AS,
1011 Instruction *I) const {
1012 // WebAssembly offsets are added as unsigned without wrapping. The
1013 // isLegalAddressingMode gives us no way to determine if wrapping could be
1014 // happening, so we approximate this by accepting only non-negative offsets.
1015 if (AM.BaseOffs < 0)
1016 return false;
1017
1018 // WebAssembly has no scale register operands.
1019 if (AM.Scale != 0)
1020 return false;
1021
1022 // Everything else is legal.
1023 return true;
1024}
1025
1026bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
1027 EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/,
1028 MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const {
1029 // WebAssembly supports unaligned accesses, though it should be declared
1030 // with the p2align attribute on loads and stores which do so, and there
1031 // may be a performance impact. We tell LLVM they're "fast" because
1032 // for the kinds of things that LLVM uses this for (merging adjacent stores
1033 // of constants, etc.), WebAssembly implementations will either want the
1034 // unaligned access or they'll split anyway.
1035 if (Fast)
1036 *Fast = 1;
1037 return true;
1038}
1039
1040bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
1041 AttributeList Attr) const {
1042 // The current thinking is that wasm engines will perform this optimization,
1043 // so we can save on code size.
1044 return true;
1045}
1046
1047bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
1048 EVT ExtT = ExtVal.getValueType();
1049 SDValue N0 = peekThroughFreeze(ExtVal->getOperand(0));
1050 auto *Load = dyn_cast<LoadSDNode>(N0);
1051 if (!Load)
1052 return false;
1053 EVT MemT = Load->getValueType(0);
1054 return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
1055 (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
1056 (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
1057}
1058
1059bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
1060 const GlobalAddressSDNode *GA) const {
1061 // Wasm doesn't support function addresses with offsets
1062 const GlobalValue *GV = GA->getGlobal();
1064}
1065
1066EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
1067 LLVMContext &C,
1068 EVT VT) const {
1069 if (VT.isVector()) {
1070 if (VT.getVectorElementType() == MVT::f16 && !Subtarget->hasFP16())
1071 return VT.changeElementType(C, MVT::i1);
1072
1074 }
1075
1076 // So far, all branch instructions in Wasm take an I32 condition.
1077 // The default TargetLowering::getSetCCResultType returns the pointer size,
1078 // which would be useful to reduce instruction counts when testing
1079 // against 64-bit pointers/values if at some point Wasm supports that.
1080 return EVT::getIntegerVT(C, 32);
1081}
1082
1083void WebAssemblyTargetLowering::getTgtMemIntrinsic(
1085 MachineFunction &MF, unsigned Intrinsic) const {
1087 switch (Intrinsic) {
1088 case Intrinsic::wasm_memory_atomic_notify:
1090 Info.memVT = MVT::i32;
1091 Info.ptrVal = I.getArgOperand(0);
1092 Info.offset = 0;
1093 Info.align = Align(4);
1094 // atomic.notify instruction does not really load the memory specified with
1095 // this argument, but MachineMemOperand should either be load or store, so
1096 // we set this to a load.
1097 // FIXME Volatile isn't really correct, but currently all LLVM atomic
1098 // instructions are treated as volatiles in the backend, so we should be
1099 // consistent. The same applies for wasm_atomic_wait intrinsics too.
1101 Infos.push_back(Info);
1102 return;
1103 case Intrinsic::wasm_memory_atomic_wait32:
1105 Info.memVT = MVT::i32;
1106 Info.ptrVal = I.getArgOperand(0);
1107 Info.offset = 0;
1108 Info.align = Align(4);
1110 Infos.push_back(Info);
1111 return;
1112 case Intrinsic::wasm_memory_atomic_wait64:
1114 Info.memVT = MVT::i64;
1115 Info.ptrVal = I.getArgOperand(0);
1116 Info.offset = 0;
1117 Info.align = Align(8);
1119 Infos.push_back(Info);
1120 return;
1121 case Intrinsic::wasm_loadf16_f32:
1123 Info.memVT = MVT::f16;
1124 Info.ptrVal = I.getArgOperand(0);
1125 Info.offset = 0;
1126 Info.align = Align(2);
1128 Infos.push_back(Info);
1129 return;
1130 case Intrinsic::wasm_storef16_f32:
1132 Info.memVT = MVT::f16;
1133 Info.ptrVal = I.getArgOperand(1);
1134 Info.offset = 0;
1135 Info.align = Align(2);
1137 Infos.push_back(Info);
1138 return;
1139 default:
1140 return;
1141 }
1142}
1143
1144void WebAssemblyTargetLowering::computeKnownBitsForTargetNode(
1145 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
1146 const SelectionDAG &DAG, unsigned Depth) const {
1147 switch (Op.getOpcode()) {
1148 default:
1149 break;
1151 unsigned IntNo = Op.getConstantOperandVal(0);
1152 switch (IntNo) {
1153 default:
1154 break;
1155 case Intrinsic::wasm_bitmask: {
1156 unsigned BitWidth = Known.getBitWidth();
1157 EVT VT = Op.getOperand(1).getSimpleValueType();
1158 unsigned PossibleBits = VT.getVectorNumElements();
1159 APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits);
1160 Known.Zero |= ZeroMask;
1161 break;
1162 }
1163 }
1164 break;
1165 }
1166 case WebAssemblyISD::EXTEND_LOW_U:
1167 case WebAssemblyISD::EXTEND_HIGH_U: {
1168 // We know the high half, of each destination vector element, will be zero.
1169 SDValue SrcOp = Op.getOperand(0);
1170 EVT VT = SrcOp.getSimpleValueType();
1171 unsigned BitWidth = Known.getBitWidth();
1172 if (VT == MVT::v8i8 || VT == MVT::v16i8) {
1173 assert(BitWidth >= 8 && "Unexpected width!");
1175 Known.Zero |= Mask;
1176 } else if (VT == MVT::v4i16 || VT == MVT::v8i16) {
1177 assert(BitWidth >= 16 && "Unexpected width!");
1179 Known.Zero |= Mask;
1180 } else if (VT == MVT::v2i32 || VT == MVT::v4i32) {
1181 assert(BitWidth >= 32 && "Unexpected width!");
1183 Known.Zero |= Mask;
1184 }
1185 break;
1186 }
1187 // For 128-bit addition if the upper bits are all zero then it's known that
1188 // the upper bits of the result will have all bits guaranteed zero except the
1189 // first.
1190 case WebAssemblyISD::I64_ADD128:
1191 if (Op.getResNo() == 1) {
1192 SDValue LHS_HI = Op.getOperand(1);
1193 SDValue RHS_HI = Op.getOperand(3);
1194 if (isNullConstant(LHS_HI) && isNullConstant(RHS_HI))
1195 Known.Zero.setBitsFrom(1);
1196 }
1197 break;
1198 }
1199}
1200
1202WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
1203 if (VT.isFixedLengthVector()) {
1204 MVT EltVT = VT.getVectorElementType();
1205 // We have legal vector types with these lane types, so widening the
1206 // vector would let us use some of the lanes directly without having to
1207 // extend or truncate values.
1208 if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
1209 EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64)
1210 return TypeWidenVector;
1211 }
1212
1214}
1215
1216bool WebAssemblyTargetLowering::isFMAFasterThanFMulAndFAdd(
1217 const MachineFunction &MF, EVT VT) const {
1218 if (!Subtarget->hasFP16() || !VT.isVector())
1219 return false;
1220
1221 EVT ScalarVT = VT.getScalarType();
1222 if (!ScalarVT.isSimple())
1223 return false;
1224
1225 return ScalarVT.getSimpleVT().SimpleTy == MVT::f16;
1226}
1227
1228bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
1229 SDValue Op, const TargetLoweringOpt &TLO) const {
1230 // ISel process runs DAGCombiner after legalization; this step is called
1231 // SelectionDAG optimization phase. This post-legalization combining process
1232 // runs DAGCombiner on each node, and if there was a change to be made,
1233 // re-runs legalization again on it and its user nodes to make sure
1234 // everythiing is in a legalized state.
1235 //
1236 // The legalization calls lowering routines, and we do our custom lowering for
1237 // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
1238 // into zeros. But there is a set of routines in DAGCombiner that turns unused
1239 // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
1240 // turns unused vector elements into undefs. But this routine does not work
1241 // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
1242 // combination can result in a infinite loop, in which undefs are converted to
1243 // zeros in legalization and back to undefs in combining.
1244 //
1245 // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
1246 // running for build_vectors.
1247 if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
1248 return false;
1249 return true;
1250}
1251
1252//===----------------------------------------------------------------------===//
1253// WebAssembly Lowering private implementation.
1254//===----------------------------------------------------------------------===//
1255
1256//===----------------------------------------------------------------------===//
1257// Lowering Code
1258//===----------------------------------------------------------------------===//
1259
1260static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
1262 DAG.getContext()->diagnose(
1263 DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
1264}
1265
1266// Test whether the given calling convention is supported.
1268 // We currently support the language-independent target-independent
1269 // conventions. We don't yet have a way to annotate calls with properties like
1270 // "cold", and we don't have any call-clobbered registers, so these are mostly
1271 // all handled the same.
1272 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
1273 CallConv == CallingConv::Cold ||
1274 CallConv == CallingConv::PreserveMost ||
1275 CallConv == CallingConv::PreserveAll ||
1276 CallConv == CallingConv::CXX_FAST_TLS ||
1278 CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail;
1279}
1280
1281SDValue
1282WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
1283 SmallVectorImpl<SDValue> &InVals) const {
1284 SelectionDAG &DAG = CLI.DAG;
1285 SDLoc DL = CLI.DL;
1286 SDValue Chain = CLI.Chain;
1287 SDValue Callee = CLI.Callee;
1289 auto Layout = MF.getDataLayout();
1290
1291 // A call through a funcref is expressed in IR as a call through the pointer
1292 // produced by the llvm.wasm.funcref.to_ptr intrinsic. Detect this here and
1293 // recover the underlying funcref value so the call can be lowered to a
1294 // table.set + call_indirect through the dedicated __funcref_call_table.
1295 bool IsFuncrefCall = false;
1296 if (Callee.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
1297 Callee.getConstantOperandVal(0) == Intrinsic::wasm_funcref_to_ptr) {
1298 Callee = Callee.getOperand(1);
1299 IsFuncrefCall = true;
1300 }
1301
1302 CallingConv::ID CallConv = CLI.CallConv;
1303 if (!callingConvSupported(CallConv))
1304 fail(DL, DAG,
1305 "WebAssembly doesn't support language-specific or target-specific "
1306 "calling conventions yet");
1307 if (CLI.IsPatchPoint)
1308 fail(DL, DAG, "WebAssembly doesn't support patch point yet");
1309
1310 if (CLI.IsTailCall) {
1311 auto NoTail = [&](const char *Msg) {
1312 if (CLI.CB && CLI.CB->isMustTailCall())
1313 fail(DL, DAG, Msg);
1314 CLI.IsTailCall = false;
1315 };
1316
1317 if (!Subtarget->hasTailCall())
1318 NoTail("WebAssembly 'tail-call' feature not enabled");
1319
1320 // Varargs calls cannot be tail calls because the buffer is on the stack
1321 if (CLI.IsVarArg)
1322 NoTail("WebAssembly does not support varargs tail calls");
1323
1324 // Do not tail call unless caller and callee return types match
1325 const Function &F = MF.getFunction();
1326 const TargetMachine &TM = getTargetMachine();
1327 Type *RetTy = F.getReturnType();
1328 SmallVector<MVT, 4> CallerRetTys;
1329 SmallVector<MVT, 4> CalleeRetTys;
1330 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1331 computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
1332 bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
1333 std::equal(CallerRetTys.begin(), CallerRetTys.end(),
1334 CalleeRetTys.begin());
1335 if (!TypesMatch)
1336 NoTail("WebAssembly tail call requires caller and callee return types to "
1337 "match");
1338
1339 // If pointers to local stack values are passed, we cannot tail call
1340 if (CLI.CB) {
1341 for (auto &Arg : CLI.CB->args()) {
1342 Value *Val = Arg.get();
1343 // Trace the value back through pointer operations
1344 while (true) {
1345 Value *Src = Val->stripPointerCastsAndAliases();
1346 if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
1347 Src = GEP->getPointerOperand();
1348 if (Val == Src)
1349 break;
1350 Val = Src;
1351 }
1352 if (isa<AllocaInst>(Val)) {
1353 NoTail(
1354 "WebAssembly does not support tail calling with stack arguments");
1355 break;
1356 }
1357 }
1358 }
1359
1360 // A byval argument is copied into this function's stack frame below, and
1361 // a tail call releases that frame before the callee reads the copy.
1362 if (llvm::any_of(CLI.Outs, [](const ISD::OutputArg &Out) {
1363 return Out.Flags.isByVal() && Out.Flags.getByValSize() != 0;
1364 }))
1365 NoTail("WebAssembly does not support tail calling with byval arguments");
1366 }
1367
1368 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
1369 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
1370 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
1371
1372 // The generic code may have added an sret argument. If we're lowering an
1373 // invoke function, the ABI requires that the function pointer be the first
1374 // argument, so we may have to swap the arguments.
1375 if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
1376 Outs[0].Flags.isSRet()) {
1377 std::swap(Outs[0], Outs[1]);
1378 std::swap(OutVals[0], OutVals[1]);
1379 }
1380
1381 bool HasSwiftSelfArg = false;
1382 bool HasSwiftErrorArg = false;
1383 std::optional<unsigned> SwiftAsyncIdx;
1384 unsigned NumFixedArgs = 0;
1385 for (unsigned I = 0; I < Outs.size(); ++I) {
1386 const ISD::OutputArg &Out = Outs[I];
1387 SDValue &OutVal = OutVals[I];
1388 HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
1389 HasSwiftErrorArg |= Out.Flags.isSwiftError();
1390 if (Out.Flags.isSwiftAsync())
1391 SwiftAsyncIdx = I;
1392 if (Out.Flags.isNest())
1393 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1394 if (Out.Flags.isInAlloca())
1395 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1396 if (Out.Flags.isInConsecutiveRegs())
1397 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1398 if (Out.Flags.isInConsecutiveRegsLast())
1399 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1400 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
1401 auto &MFI = MF.getFrameInfo();
1402 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
1403 Out.Flags.getNonZeroByValAlign(),
1404 /*isSS=*/false);
1405 SDValue SizeNode =
1406 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
1407 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1408 Align Alignment = Out.Flags.getNonZeroByValAlign();
1409 Chain = DAG.getMemcpy(Chain, DL, FINode, OutVal, SizeNode, Alignment,
1410 Alignment,
1411 /*isVolatile*/ false, /*AlwaysInline=*/false,
1412 /*CI=*/nullptr, std::nullopt, MachinePointerInfo(),
1413 MachinePointerInfo());
1414 OutVal = FINode;
1415 }
1416 // Count the number of fixed args *after* legalization.
1417 NumFixedArgs += !Out.Flags.isVarArg();
1418 }
1419
1420 bool IsVarArg = CLI.IsVarArg;
1421 auto PtrVT = getPointerTy(Layout);
1422
1423 // As in computeSignatureVTs, swiftasync comes first.
1424 if (SwiftAsyncIdx) {
1425 WebAssembly::moveToFront(Outs, *SwiftAsyncIdx);
1426 WebAssembly::moveToFront(OutVals, *SwiftAsyncIdx);
1427 }
1428
1429 // For swiftcc and swifttailcc, emit additional swiftself, swifterror, and
1430 // (for swifttailcc) swiftasync arguments if there aren't. These additional
1431 // arguments are also added for callee signature. They are necessary to match
1432 // callee and caller signature for indirect call.
1433 if (CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail) {
1434 Type *PtrTy = PointerType::getUnqual(*DAG.getContext());
1435 if (!HasSwiftSelfArg) {
1436 NumFixedArgs++;
1437 ISD::ArgFlagsTy Flags;
1438 Flags.setSwiftSelf();
1439 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1440 CLI.Outs.push_back(Arg);
1441 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1442 CLI.OutVals.push_back(ArgVal);
1443 }
1444 if (!HasSwiftErrorArg) {
1445 NumFixedArgs++;
1446 ISD::ArgFlagsTy Flags;
1447 Flags.setSwiftError();
1448 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1449 CLI.Outs.push_back(Arg);
1450 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1451 CLI.OutVals.push_back(ArgVal);
1452 }
1453 if (CallConv == CallingConv::SwiftTail && SwiftAsyncIdx == std::nullopt) {
1454 NumFixedArgs++;
1455 ISD::ArgFlagsTy Flags;
1456 Flags.setSwiftAsync();
1457 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1458 CLI.Outs.insert(CLI.Outs.begin(), Arg);
1459 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1460 CLI.OutVals.insert(CLI.OutVals.begin(), ArgVal);
1461 }
1462 }
1463
1464 // Analyze operands of the call, assigning locations to each operand.
1466 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1467
1468 if (IsVarArg) {
1469 // Outgoing non-fixed arguments are placed in a buffer. First
1470 // compute their offsets and the total amount of buffer space needed.
1471 for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
1472 const ISD::OutputArg &Out = Outs[I];
1473 SDValue &Arg = OutVals[I];
1474 EVT VT = Arg.getValueType();
1475 assert(VT != MVT::iPTR && "Legalized args should be concrete");
1476 Type *Ty = VT.getTypeForEVT(*DAG.getContext());
1478 std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
1479 unsigned Offset =
1480 CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
1481 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
1482 Offset, VT.getSimpleVT(),
1484 }
1485 }
1486
1487 unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
1488
1489 SDValue FINode;
1490 if (IsVarArg && NumBytes) {
1491 // For non-fixed arguments, next emit stores to store the argument values
1492 // to the stack buffer at the offsets computed above.
1493 MaybeAlign StackAlign = Layout.getStackAlignment();
1494 assert(StackAlign && "data layout string is missing stack alignment");
1495 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, *StackAlign,
1496 /*isSS=*/false);
1497 unsigned ValNo = 0;
1499 for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) {
1500 assert(ArgLocs[ValNo].getValNo() == ValNo &&
1501 "ArgLocs should remain in order and only hold varargs args");
1502 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
1503 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1504 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
1505 DAG.getConstant(Offset, DL, PtrVT));
1506 Chains.push_back(
1507 DAG.getStore(Chain, DL, Arg, Add,
1509 }
1510 if (!Chains.empty())
1511 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
1512 } else if (IsVarArg) {
1513 FINode = DAG.getIntPtrConstant(0, DL);
1514 }
1515
1516 if (Callee->getOpcode() == ISD::GlobalAddress) {
1517 // If the callee is a GlobalAddress node (quite common, every direct call
1518 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
1519 // doesn't at MO_GOT which is not needed for direct calls.
1520 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
1523 GA->getOffset());
1524 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
1525 getPointerTy(DAG.getDataLayout()), Callee);
1526 }
1527
1528 // Compute the operands for the CALLn node.
1530 Ops.push_back(Chain);
1531 Ops.push_back(Callee);
1532
1533 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
1534 // isn't reliable.
1535 Ops.append(OutVals.begin(),
1536 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
1537 // Add a pointer to the vararg buffer.
1538 if (IsVarArg)
1539 Ops.push_back(FINode);
1540
1541 SmallVector<EVT, 8> InTys;
1542 for (const auto &In : Ins) {
1543 assert(!In.Flags.isByVal() && "byval is not valid for return values");
1544 assert(!In.Flags.isNest() && "nest is not valid for return values");
1545 if (In.Flags.isInAlloca())
1546 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
1547 if (In.Flags.isInConsecutiveRegs())
1548 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
1549 if (In.Flags.isInConsecutiveRegsLast())
1550 fail(DL, DAG,
1551 "WebAssembly hasn't implemented cons regs last return values");
1552 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1553 // registers.
1554 InTys.push_back(In.VT);
1555 }
1556
1557 // Lastly, if this is a call to a funcref we need to add an instruction
1558 // table.set to the chain and transform the call.
1559 if (IsFuncrefCall) {
1560 // In the absence of function references proposal where a funcref call is
1561 // lowered to call_ref, using reference types we generate a table.set to set
1562 // the funcref to a special table used solely for this purpose, followed by
1563 // a call_indirect. Here we just generate the table set, and return the
1564 // SDValue of the table.set so that LowerCall can finalize the lowering by
1565 // generating the call_indirect.
1566 SDValue Chain = Ops[0];
1567
1569 MF.getContext(), Subtarget);
1570 SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
1571 SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
1572 SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
1573 SDValue TableSet = DAG.getMemIntrinsicNode(
1574 WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
1575 MVT::funcref, MachinePointerInfo(), Align(1),
1577
1578 Ops[0] = TableSet; // The new chain is the TableSet itself
1579 }
1580
1581 if (CLI.IsTailCall) {
1582 // ret_calls do not return values to the current frame
1583 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1584 return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
1585 }
1586
1587 InTys.push_back(MVT::Other);
1588 SDVTList InTyList = DAG.getVTList(InTys);
1589 SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
1590
1591 for (size_t I = 0; I < Ins.size(); ++I)
1592 InVals.push_back(Res.getValue(I));
1593
1594 // Return the chain
1595 return Res.getValue(Ins.size());
1596}
1597
1598bool WebAssemblyTargetLowering::CanLowerReturn(
1599 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
1600 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext & /*Context*/,
1601 const Type *RetTy) const {
1602 // WebAssembly can only handle returning tuples with multivalue enabled
1603 return WebAssembly::canLowerReturn(Outs.size(), Subtarget);
1604}
1605
1606SDValue WebAssemblyTargetLowering::LowerReturn(
1607 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
1609 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
1610 SelectionDAG &DAG) const {
1611 assert(WebAssembly::canLowerReturn(Outs.size(), Subtarget) &&
1612 "MVP WebAssembly can only return up to one value");
1613 if (!callingConvSupported(CallConv))
1614 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1615
1616 SmallVector<SDValue, 4> RetOps(1, Chain);
1617 RetOps.append(OutVals.begin(), OutVals.end());
1618 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
1619
1620 // Record the number and types of the return values.
1621 for (const ISD::OutputArg &Out : Outs) {
1622 assert(!Out.Flags.isByVal() && "byval is not valid for return values");
1623 assert(!Out.Flags.isNest() && "nest is not valid for return values");
1624 assert(!Out.Flags.isVarArg() && "non-fixed return value is not valid");
1625 if (Out.Flags.isInAlloca())
1626 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
1627 if (Out.Flags.isInConsecutiveRegs())
1628 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
1629 if (Out.Flags.isInConsecutiveRegsLast())
1630 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
1631 }
1632
1633 return Chain;
1634}
1635
1636SDValue WebAssemblyTargetLowering::LowerFormalArguments(
1637 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
1638 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
1639 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
1640 if (!callingConvSupported(CallConv))
1641 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1642
1644 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
1645
1646 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
1647 // of the incoming values before they're represented by virtual registers.
1648 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
1649
1650 bool HasSwiftErrorArg = false;
1651 bool HasSwiftSelfArg = false;
1652 std::optional<unsigned> SwiftAsyncIdx;
1653 for (auto [I, In] : enumerate(Ins))
1654 if (In.Flags.isSwiftAsync())
1655 SwiftAsyncIdx = I;
1656 // As in computeSignatureVTs, swiftasync or its padding comes first.
1657 bool PadSwiftAsync = CallConv == CallingConv::SwiftTail && !SwiftAsyncIdx;
1658 auto GetParamIdx = [&](unsigned InIdx) -> unsigned {
1659 if (SwiftAsyncIdx)
1660 return InIdx == *SwiftAsyncIdx ? 0 : InIdx + (InIdx < *SwiftAsyncIdx);
1661 return InIdx + PadSwiftAsync;
1662 };
1663
1664 SmallVector<MVT, 4> ParamVTs;
1665 for (auto [I, In] : enumerate(Ins)) {
1666 HasSwiftSelfArg |= In.Flags.isSwiftSelf();
1667 HasSwiftErrorArg |= In.Flags.isSwiftError();
1668 if (In.Flags.isInAlloca())
1669 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1670 if (In.Flags.isNest())
1671 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1672 if (In.Flags.isInConsecutiveRegs())
1673 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1674 if (In.Flags.isInConsecutiveRegsLast())
1675 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1676 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1677 // registers.
1678 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
1679 DAG.getTargetConstant(GetParamIdx(I),
1680 DL, MVT::i32))
1681 : DAG.getUNDEF(In.VT));
1682
1683 // Record the number and types of arguments.
1684 ParamVTs.push_back(In.VT);
1685 }
1686
1687 if (SwiftAsyncIdx)
1688 WebAssembly::moveToFront(ParamVTs, *SwiftAsyncIdx);
1689 else if (PadSwiftAsync)
1690 ParamVTs.insert(ParamVTs.begin(), getPointerTy(MF.getDataLayout()));
1691 for (MVT VT : ParamVTs)
1692 MFI->addParam(VT);
1693
1694 // For swiftcc and swifttailcc, emit additional swiftself and swifterror
1695 // arguments if there aren't. These additional arguments are also added for
1696 // callee signature. They are necessary to match callee and caller signature
1697 // for indirect call.
1698 auto PtrVT = getPointerTy(MF.getDataLayout());
1699 if (CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail) {
1700 if (!HasSwiftSelfArg) {
1701 MFI->addParam(PtrVT);
1702 }
1703 if (!HasSwiftErrorArg) {
1704 MFI->addParam(PtrVT);
1705 }
1706 }
1707 // Varargs are copied into a buffer allocated by the caller, and a pointer to
1708 // the buffer is passed as an argument.
1709 if (IsVarArg) {
1710 MVT PtrVT = getPointerTy(MF.getDataLayout());
1711 Register VarargVreg =
1713 MFI->setVarargBufferVreg(VarargVreg);
1714 Chain = DAG.getCopyToReg(
1715 Chain, DL, VarargVreg,
1716 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
1717 DAG.getTargetConstant(ParamVTs.size(), DL, MVT::i32)));
1718 MFI->addParam(PtrVT);
1719 }
1720
1721 // Record the number and types of arguments and results.
1722 SmallVector<MVT, 4> Params;
1725 MF.getFunction(), DAG.getTarget(), Params, Results);
1726 for (MVT VT : Results)
1727 MFI->addResult(VT);
1728 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
1729 // the param logic here with ComputeSignatureVTs
1730 assert(MFI->getParams().size() == Params.size() &&
1731 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
1732 Params.begin()));
1733
1734 return Chain;
1735}
1736
1737void WebAssemblyTargetLowering::ReplaceNodeResults(
1739 switch (N->getOpcode()) {
1741 // Do not add any results, signifying that N should not be custom lowered
1742 // after all. This happens because simd128 turns on custom lowering for
1743 // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1744 // illegal type.
1745 break;
1749 // Do not add any results, signifying that N should not be custom lowered.
1750 // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
1751 break;
1752 case ISD::FP_ROUND: {
1753 EVT VT = N->getValueType(0);
1754 SDValue Src = N->getOperand(0);
1755 if (VT == MVT::v4f16 && Src.getValueType() == MVT::v4f32) {
1756 Results.push_back(
1757 DAG.getNode(WebAssemblyISD::DEMOTE_ZERO, SDLoc(N), MVT::v8f16, Src));
1758 }
1759 break;
1760 }
1761 case ISD::ADD:
1762 case ISD::SUB:
1763 Results.push_back(Replace128Op(N, DAG));
1764 break;
1765 default:
1767 "ReplaceNodeResults not implemented for this op for WebAssembly!");
1768 }
1769}
1770
1771//===----------------------------------------------------------------------===//
1772// Custom lowering hooks.
1773//===----------------------------------------------------------------------===//
1774
1775SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1776 SelectionDAG &DAG) const {
1777 SDLoc DL(Op);
1778 switch (Op.getOpcode()) {
1779 default:
1780 llvm_unreachable("unimplemented operation lowering");
1781 return SDValue();
1782 case ISD::FrameIndex:
1783 return LowerFrameIndex(Op, DAG);
1784 case ISD::GlobalAddress:
1785 return LowerGlobalAddress(Op, DAG);
1787 return LowerGlobalTLSAddress(Op, DAG);
1789 return LowerExternalSymbol(Op, DAG);
1790 case ISD::JumpTable:
1791 return LowerJumpTable(Op, DAG);
1792 case ISD::BR_JT:
1793 return LowerBR_JT(Op, DAG);
1794 case ISD::VASTART:
1795 return LowerVASTART(Op, DAG);
1796 case ISD::BlockAddress:
1797 case ISD::BRIND:
1798 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
1799 return SDValue();
1800 case ISD::RETURNADDR:
1801 return LowerRETURNADDR(Op, DAG);
1802 case ISD::FRAMEADDR:
1803 return LowerFRAMEADDR(Op, DAG);
1804 case ISD::CopyToReg:
1805 return LowerCopyToReg(Op, DAG);
1808 return LowerAccessVectorElement(Op, DAG);
1812 return LowerIntrinsic(Op, DAG);
1814 return LowerSIGN_EXTEND_INREG(Op, DAG);
1818 return LowerEXTEND_VECTOR_INREG(Op, DAG);
1819 case ISD::BUILD_VECTOR:
1820 return LowerBUILD_VECTOR(Op, DAG);
1822 return LowerVECTOR_SHUFFLE(Op, DAG);
1823 case ISD::SETCC:
1824 return LowerSETCC(Op, DAG);
1825 case ISD::SHL:
1826 case ISD::SRA:
1827 case ISD::SRL:
1828 return LowerShift(Op, DAG);
1831 return LowerFP_TO_INT_SAT(Op, DAG);
1832 case ISD::FMINNUM:
1833 case ISD::FMINIMUMNUM:
1834 return LowerFMIN(Op, DAG);
1835 case ISD::FMAXNUM:
1836 case ISD::FMAXIMUMNUM:
1837 return LowerFMAX(Op, DAG);
1838 case ISD::LOAD:
1839 return LowerLoad(Op, DAG);
1840 case ISD::STORE:
1841 return LowerStore(Op, DAG);
1842 case ISD::CTPOP:
1843 case ISD::CTLZ:
1844 case ISD::CTTZ:
1845 return DAG.UnrollVectorOp(Op.getNode());
1846 case ISD::CLEAR_CACHE:
1847 // Report this as a diagnostic rather than aborting, like the other
1848 // unsupported features in this target. Pass the chain through so that
1849 // codegen can reach the point where the diagnostic is emitted.
1850 fail(SDLoc(Op), DAG, "llvm.clear_cache is not supported on wasm");
1851 return Op.getOperand(0);
1852 case ISD::SMUL_LOHI:
1853 case ISD::UMUL_LOHI:
1854 return LowerMUL_LOHI(Op, DAG);
1855 case ISD::UADDO:
1856 return LowerUADDO(Op, DAG);
1857 }
1858}
1859
1863
1864 return false;
1865}
1866
1867static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op,
1868 SelectionDAG &DAG) {
1870 if (!FI)
1871 return std::nullopt;
1872
1873 auto &MF = DAG.getMachineFunction();
1875}
1876
1877SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
1878 SelectionDAG &DAG) const {
1879 SDLoc DL(Op);
1880 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
1881 const SDValue &Value = SN->getValue();
1882 const SDValue &Base = SN->getBasePtr();
1883 const SDValue &Offset = SN->getOffset();
1884
1886 if (!Offset->isUndef())
1887 report_fatal_error("unexpected offset when storing to webassembly global",
1888 false);
1889
1890 SDVTList Tys = DAG.getVTList(MVT::Other);
1891 SDValue Ops[] = {SN->getChain(), Value, Base};
1892 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops,
1893 SN->getMemoryVT(), SN->getMemOperand());
1894 }
1895
1896 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1897 if (!Offset->isUndef())
1898 report_fatal_error("unexpected offset when storing to webassembly local",
1899 false);
1900
1901 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1902 SDVTList Tys = DAG.getVTList(MVT::Other); // The chain.
1903 SDValue Ops[] = {SN->getChain(), Idx, Value};
1904 return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops);
1905 }
1906
1909 "Encountered an unlowerable store to the wasm_var address space",
1910 false);
1911
1912 return Op;
1913}
1914
1915SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
1916 SelectionDAG &DAG) const {
1917 SDLoc DL(Op);
1918 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
1919 const SDValue &Base = LN->getBasePtr();
1920 const SDValue &Offset = LN->getOffset();
1921
1923 if (!Offset->isUndef())
1925 "unexpected offset when loading from webassembly global", false);
1926
1927 SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
1928 SDValue Ops[] = {LN->getChain(), Base};
1929 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops,
1930 LN->getMemoryVT(), LN->getMemOperand());
1931 }
1932
1933 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1934 if (!Offset->isUndef())
1936 "unexpected offset when loading from webassembly local", false);
1937
1938 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1939 EVT LocalVT = LN->getValueType(0);
1940 return DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, {LocalVT, MVT::Other},
1941 {LN->getChain(), Idx});
1942 }
1943
1946 "Encountered an unlowerable load from the wasm_var address space",
1947 false);
1948
1949 return Op;
1950}
1951
1952SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
1953 SelectionDAG &DAG) const {
1954 assert(Subtarget->hasWideArithmetic());
1955 assert(Op.getValueType() == MVT::i64);
1956 SDLoc DL(Op);
1957 unsigned Opcode;
1958 switch (Op.getOpcode()) {
1959 case ISD::UMUL_LOHI:
1960 Opcode = WebAssemblyISD::I64_MUL_WIDE_U;
1961 break;
1962 case ISD::SMUL_LOHI:
1963 Opcode = WebAssemblyISD::I64_MUL_WIDE_S;
1964 break;
1965 default:
1966 llvm_unreachable("unexpected opcode");
1967 }
1968 SDValue LHS = Op.getOperand(0);
1969 SDValue RHS = Op.getOperand(1);
1970 SDValue Lo =
1971 DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
1972 SDValue Hi(Lo.getNode(), 1);
1973 SDValue Ops[] = {Lo, Hi};
1974 return DAG.getMergeValues(Ops, DL);
1975}
1976
1977// Lowers `UADDO` intrinsics to an `i64.add128` instruction when it's enabled.
1978//
1979// This enables generating a single wasm instruction for this operation where
1980// the upper half of both operands are constant zeros. The upper half of the
1981// result is then whether the overflow happened.
1982SDValue WebAssemblyTargetLowering::LowerUADDO(SDValue Op,
1983 SelectionDAG &DAG) const {
1984 assert(Subtarget->hasWideArithmetic());
1985 assert(Op.getValueType() == MVT::i64);
1986 assert(Op.getOpcode() == ISD::UADDO);
1987 SDLoc DL(Op);
1988 SDValue LHS = Op.getOperand(0);
1989 SDValue RHS = Op.getOperand(1);
1990 SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
1991 SDValue Result =
1992 DAG.getNode(WebAssemblyISD::I64_ADD128, DL,
1993 DAG.getVTList(MVT::i64, MVT::i64), LHS, Zero, RHS, Zero);
1994 SDValue CarryI64(Result.getNode(), 1);
1995 SDValue CarryI32 = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, CarryI64);
1996 SDValue Ops[] = {Result, CarryI32};
1997 return DAG.getMergeValues(Ops, DL);
1998}
1999
2000SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
2001 SelectionDAG &DAG) const {
2002 assert(Subtarget->hasWideArithmetic());
2003 assert(N->getValueType(0) == MVT::i128);
2004 SDLoc DL(N);
2005 unsigned Opcode;
2006 switch (N->getOpcode()) {
2007 case ISD::ADD:
2008 Opcode = WebAssemblyISD::I64_ADD128;
2009 break;
2010 case ISD::SUB:
2011 Opcode = WebAssemblyISD::I64_SUB128;
2012 break;
2013 default:
2014 llvm_unreachable("unexpected opcode");
2015 }
2016 SDValue LHS = N->getOperand(0);
2017 SDValue RHS = N->getOperand(1);
2018
2019 SDValue C0 = DAG.getConstant(0, DL, MVT::i64);
2020 SDValue C1 = DAG.getConstant(1, DL, MVT::i64);
2021 SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C0);
2022 SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C1);
2023 SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
2024 SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
2025 SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
2026 LHS_0, LHS_1, RHS_0, RHS_1);
2027 SDValue Result_HI(Result_LO.getNode(), 1);
2028 return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
2029}
2030
2031SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
2032 SelectionDAG &DAG) const {
2033 SDValue Src = Op.getOperand(2);
2034 if (isa<FrameIndexSDNode>(Src.getNode())) {
2035 // CopyToReg nodes don't support FrameIndex operands. Other targets select
2036 // the FI to some LEA-like instruction, but since we don't have that, we
2037 // need to insert some kind of instruction that can take an FI operand and
2038 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
2039 // local.copy between Op and its FI operand.
2040 SDValue Chain = Op.getOperand(0);
2041 SDLoc DL(Op);
2042 Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
2043 EVT VT = Src.getValueType();
2044 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
2045 : WebAssembly::COPY_I64,
2046 DL, VT, Src),
2047 0);
2048 return Op.getNode()->getNumValues() == 1
2049 ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
2050 : DAG.getCopyToReg(Chain, DL, Reg, Copy,
2051 Op.getNumOperands() == 4 ? Op.getOperand(3)
2052 : SDValue());
2053 }
2054 return SDValue();
2055}
2056
2057SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
2058 SelectionDAG &DAG) const {
2059 int FI = cast<FrameIndexSDNode>(Op)->getIndex();
2060 return DAG.getTargetFrameIndex(FI, Op.getValueType());
2061}
2062
2063SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
2064 SelectionDAG &DAG) const {
2065 SDLoc DL(Op);
2066
2067 if (!Subtarget->getTargetTriple().isOSEmscripten()) {
2068 fail(DL, DAG,
2069 "Non-Emscripten WebAssembly hasn't implemented "
2070 "__builtin_return_address");
2071 return SDValue();
2072 }
2073
2074 unsigned Depth = Op.getConstantOperandVal(0);
2075 MakeLibCallOptions CallOptions;
2076 return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
2077 {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
2078 .first;
2079}
2080
2081SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
2082 SelectionDAG &DAG) const {
2083 // Non-zero depths are not supported by WebAssembly currently. Use the
2084 // legalizer's default expansion, which is to return 0 (what this function is
2085 // documented to do).
2086 if (Op.getConstantOperandVal(0) > 0)
2087 return SDValue();
2088
2090 EVT VT = Op.getValueType();
2091 Register FP =
2092 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
2093 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
2094}
2095
2096SDValue
2097WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
2098 SelectionDAG &DAG) const {
2099 SDLoc DL(Op);
2100 const auto *GA = cast<GlobalAddressSDNode>(Op);
2101
2103 if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory())
2104 report_fatal_error("cannot use thread-local storage without bulk memory",
2105 false);
2106
2107 const GlobalValue *GV = GA->getGlobal();
2108
2109 // Currently only Emscripten supports dynamic linking with threads. Therefore,
2110 // on other targets, if we have thread-local storage, only the local-exec
2111 // model is possible.
2112 auto model = Subtarget->getTargetTriple().isOSEmscripten()
2113 ? GV->getThreadLocalMode()
2115
2116 // Unsupported TLS modes
2119
2120 if (model == GlobalValue::LocalExecTLSModel ||
2123 getTargetMachine().shouldAssumeDSOLocal(GV))) {
2124 // For DSO-local TLS variables we use offset from __tls_base, or
2125 // __wasm_get_tls_base() if using libcall thread context.
2126
2127 MVT PtrVT = getPointerTy(DAG.getDataLayout());
2128 SDValue BaseAddr(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0);
2129
2130 SDValue TLSOffset = DAG.getTargetGlobalAddress(
2131 GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL);
2132 SDValue SymOffset =
2133 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset);
2134
2135 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset);
2136 }
2137
2139
2140 EVT VT = Op.getValueType();
2141 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2142 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2143 GA->getOffset(),
2145}
2146
2147SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
2148 SelectionDAG &DAG) const {
2149 SDLoc DL(Op);
2150 const auto *GA = cast<GlobalAddressSDNode>(Op);
2151 EVT VT = Op.getValueType();
2152 assert(GA->getTargetFlags() == 0 &&
2153 "Unexpected target flags on generic GlobalAddressSDNode");
2155 fail(DL, DAG, "Invalid address space for WebAssembly target");
2156
2157 unsigned OperandFlags = 0;
2158 const GlobalValue *GV = GA->getGlobal();
2159 // Since WebAssembly tables cannot yet be shared across modules, we don't
2160 // need special treatment for tables in PIC mode.
2161 if (isPositionIndependent() &&
2163 if (getTargetMachine().shouldAssumeDSOLocal(GV)) {
2165 MVT PtrVT = getPointerTy(MF.getDataLayout());
2166 const char *BaseName;
2167 if (GV->getValueType()->isFunctionTy()) {
2168 BaseName = MF.createExternalSymbolName("__table_base");
2170 } else {
2171 BaseName = MF.createExternalSymbolName("__memory_base");
2173 }
2175 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2176 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2177
2178 SDValue SymAddr = DAG.getNode(
2179 WebAssemblyISD::WrapperREL, DL, VT,
2180 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
2181 OperandFlags));
2182
2183 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
2184 }
2186 }
2187
2188 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2189 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2190 GA->getOffset(), OperandFlags));
2191}
2192
2193SDValue
2194WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
2195 SelectionDAG &DAG) const {
2196 SDLoc DL(Op);
2197 const auto *ES = cast<ExternalSymbolSDNode>(Op);
2198 EVT VT = Op.getValueType();
2199 assert(ES->getTargetFlags() == 0 &&
2200 "Unexpected target flags on generic ExternalSymbolSDNode");
2201 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2202 DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
2203}
2204
2205SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
2206 SelectionDAG &DAG) const {
2207 // There's no need for a Wrapper node because we always incorporate a jump
2208 // table operand into a BR_TABLE instruction, rather than ever
2209 // materializing it in a register.
2210 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
2211 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
2212 JT->getTargetFlags());
2213}
2214
2215SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
2216 SelectionDAG &DAG) const {
2217 SDLoc DL(Op);
2218 SDValue Chain = Op.getOperand(0);
2219 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
2220 SDValue Index = Op.getOperand(2);
2221 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
2222
2224 Ops.push_back(Chain);
2225 Ops.push_back(Index);
2226
2227 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
2228 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
2229
2230 // Add an operand for each case.
2231 for (auto *MBB : MBBs)
2232 Ops.push_back(DAG.getBasicBlock(MBB));
2233
2234 // Add the first MBB as a dummy default target for now. This will be replaced
2235 // with the proper default target (and the preceding range check eliminated)
2236 // if possible by WebAssemblyFixBrTableDefaults.
2237 Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
2238 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
2239}
2240
2241SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
2242 SelectionDAG &DAG) const {
2243 SDLoc DL(Op);
2244 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
2245
2246 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
2247 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
2248
2249 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
2250 MFI->getVarargBufferVreg(), PtrVT);
2251 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
2252 MachinePointerInfo(SV));
2253}
2254
2255SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
2256 SelectionDAG &DAG) const {
2258 unsigned IntNo;
2259 switch (Op.getOpcode()) {
2262 IntNo = Op.getConstantOperandVal(1);
2263 break;
2265 IntNo = Op.getConstantOperandVal(0);
2266 break;
2267 default:
2268 llvm_unreachable("Invalid intrinsic");
2269 }
2270 SDLoc DL(Op);
2271
2272 switch (IntNo) {
2273 default:
2274 return SDValue(); // Don't custom lower most intrinsics.
2275
2276 case Intrinsic::wasm_lsda: {
2277 auto PtrVT = getPointerTy(MF.getDataLayout());
2278 const char *SymName = MF.createExternalSymbolName(
2279 "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
2280 if (isPositionIndependent()) {
2282 SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
2283 const char *BaseName = MF.createExternalSymbolName("__memory_base");
2285 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2286 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2287 SDValue SymAddr =
2288 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
2289 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
2290 }
2291 SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
2292 return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
2293 }
2294
2295 case Intrinsic::wasm_shuffle: {
2296 // Drop in-chain and replace undefs, but otherwise pass through unchanged
2297 SDValue Ops[18];
2298 size_t OpIdx = 0;
2299 Ops[OpIdx++] = Op.getOperand(1);
2300 Ops[OpIdx++] = Op.getOperand(2);
2301 while (OpIdx < 18) {
2302 const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
2303 if (MaskIdx.isUndef() || MaskIdx.getNode()->getAsZExtVal() >= 32) {
2304 bool isTarget = MaskIdx.getNode()->getOpcode() == ISD::TargetConstant;
2305 Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32, isTarget);
2306 } else {
2307 Ops[OpIdx++] = MaskIdx;
2308 }
2309 }
2310 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2311 }
2312
2313 case Intrinsic::wasm_funcref_to_ptr: {
2314 // llvm.wasm.funcref.to_ptr only has a defined lowering when its result
2315 // feeds directly into an indirect call. Reaching here means the pointer
2316 // escapes a direct call. We haven't implemented conversion of a funcref
2317 // into a real function pointer so we crash if we get here.
2318 fail(DL, DAG,
2319 "a funcref can only be converted to a pointer to be directly called; "
2320 "the resulting pointer cannot otherwise be used");
2321 return DAG.getPOISON(Op.getValueType());
2322 }
2323
2324 case Intrinsic::thread_pointer: {
2325 return SDValue(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0);
2326 }
2327 }
2328}
2329
2330SDValue
2331WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
2332 SelectionDAG &DAG) const {
2333 SDLoc DL(Op);
2334 // If sign extension operations are disabled, allow sext_inreg only if operand
2335 // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
2336 // extension operations, but allowing sext_inreg in this context lets us have
2337 // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
2338 // everywhere would be simpler in this file, but would necessitate large and
2339 // brittle patterns to undo the expansion and select extract_lane_s
2340 // instructions.
2341 assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
2342 if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2343 return SDValue();
2344
2345 const SDValue &Extract = Op.getOperand(0);
2346 MVT VecT = Extract.getOperand(0).getSimpleValueType();
2347 if (VecT.getVectorElementType().getSizeInBits() > 32)
2348 return SDValue();
2349 MVT ExtractedLaneT =
2350 cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
2351 MVT ExtractedVecT =
2352 MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
2353 if (ExtractedVecT == VecT)
2354 return Op;
2355
2356 // Bitcast vector to appropriate type to ensure ISel pattern coverage
2357 const SDNode *Index = Extract.getOperand(1).getNode();
2358 if (!isa<ConstantSDNode>(Index))
2359 return SDValue();
2360 unsigned IndexVal = Index->getAsZExtVal();
2361 unsigned Scale =
2362 ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
2363 assert(Scale > 1);
2364 SDValue NewIndex =
2365 DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
2366 SDValue NewExtract = DAG.getNode(
2368 DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
2369 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
2370 Op.getOperand(1));
2371}
2372
2373static SDValue GetExtendHigh(SDValue Op, unsigned UserOpc, EVT VT,
2374 SelectionDAG &DAG) {
2375 SDValue Source = peekThroughBitcasts(Op);
2376 if (Source.getOpcode() != ISD::VECTOR_SHUFFLE)
2377 return SDValue();
2378
2379 assert((UserOpc == WebAssemblyISD::EXTEND_LOW_U ||
2380 UserOpc == WebAssemblyISD::EXTEND_LOW_S) &&
2381 "expected extend_low");
2382 auto *Shuffle = cast<ShuffleVectorSDNode>(Source.getNode());
2383
2384 ArrayRef<int> Mask = Shuffle->getMask();
2385 // Look for a shuffle which moves from the high half to the low half.
2386 size_t FirstIdx = Mask.size() / 2;
2387 for (size_t i = 0; i < Mask.size() / 2; ++i) {
2388 if (Mask[i] != static_cast<int>(FirstIdx + i)) {
2389 return SDValue();
2390 }
2391 }
2392
2393 SDLoc DL(Op);
2394 unsigned Opc = UserOpc == WebAssemblyISD::EXTEND_LOW_S
2395 ? WebAssemblyISD::EXTEND_HIGH_S
2396 : WebAssemblyISD::EXTEND_HIGH_U;
2397 SDValue ShuffleSrc = Shuffle->getOperand(0);
2398 if (Op.getOpcode() == ISD::BITCAST)
2399 ShuffleSrc = DAG.getBitcast(Op.getValueType(), ShuffleSrc);
2400
2401 return DAG.getNode(Opc, DL, VT, ShuffleSrc);
2402}
2403
2404SDValue
2405WebAssemblyTargetLowering::LowerEXTEND_VECTOR_INREG(SDValue Op,
2406 SelectionDAG &DAG) const {
2407 SDLoc DL(Op);
2408 EVT VT = Op.getValueType();
2409 SDValue Src = Op.getOperand(0);
2410 EVT SrcVT = Src.getValueType();
2411
2412 if (SrcVT.getVectorElementType() == MVT::i1 ||
2413 SrcVT.getVectorElementType() == MVT::i64)
2414 return SDValue();
2415
2416 assert(VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits() == 0 &&
2417 "Unexpected extension factor.");
2418 unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits();
2419
2420 if (Scale != 2 && Scale != 4 && Scale != 8)
2421 return SDValue();
2422
2423 unsigned Ext;
2424 switch (Op.getOpcode()) {
2425 default:
2426 llvm_unreachable("unexpected opcode");
2429 Ext = WebAssemblyISD::EXTEND_LOW_U;
2430 break;
2432 Ext = WebAssemblyISD::EXTEND_LOW_S;
2433 break;
2434 }
2435
2436 if (Scale == 2) {
2437 // See if we can use EXTEND_HIGH.
2438 if (auto ExtendHigh = GetExtendHigh(Op.getOperand(0), Ext, VT, DAG))
2439 return ExtendHigh;
2440 }
2441
2442 SDValue Ret = Src;
2443 while (Scale != 1) {
2444 Ret = DAG.getNode(Ext, DL,
2445 Ret.getValueType()
2448 Ret);
2449 Scale /= 2;
2450 }
2451 assert(Ret.getValueType() == VT);
2452 return Ret;
2453}
2454
2456 SDLoc DL(Op);
2457 if (Op.getValueType() != MVT::v2f64 && Op.getValueType() != MVT::v4f32)
2458 return SDValue();
2459
2460 auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec,
2461 unsigned &Index) -> bool {
2462 switch (Op.getOpcode()) {
2463 case ISD::SINT_TO_FP:
2464 Opcode = WebAssemblyISD::CONVERT_LOW_S;
2465 break;
2466 case ISD::UINT_TO_FP:
2467 Opcode = WebAssemblyISD::CONVERT_LOW_U;
2468 break;
2469 case ISD::FP_EXTEND:
2470 case ISD::FP16_TO_FP:
2471 Opcode = WebAssemblyISD::PROMOTE_LOW;
2472 break;
2473 default:
2474 return false;
2475 }
2476
2477 auto ExtractVector = Op.getOperand(0);
2478 if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2479 return false;
2480
2481 if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode()))
2482 return false;
2483
2484 SrcVec = ExtractVector.getOperand(0);
2485 Index = ExtractVector.getConstantOperandVal(1);
2486 return true;
2487 };
2488
2489 unsigned NumLanes = Op.getValueType() == MVT::v2f64 ? 2 : 4;
2490 unsigned FirstOpcode = 0, SecondOpcode = 0, ThirdOpcode = 0, FourthOpcode = 0;
2491 unsigned FirstIndex = 0, SecondIndex = 0, ThirdIndex = 0, FourthIndex = 0;
2492 SDValue FirstSrcVec, SecondSrcVec, ThirdSrcVec, FourthSrcVec;
2493
2494 if (!GetConvertedLane(Op.getOperand(0), FirstOpcode, FirstSrcVec,
2495 FirstIndex) ||
2496 !GetConvertedLane(Op.getOperand(1), SecondOpcode, SecondSrcVec,
2497 SecondIndex))
2498 return SDValue();
2499
2500 // If we're converting to v4f32, check the third and fourth lanes, too.
2501 if (NumLanes == 4 && (!GetConvertedLane(Op.getOperand(2), ThirdOpcode,
2502 ThirdSrcVec, ThirdIndex) ||
2503 !GetConvertedLane(Op.getOperand(3), FourthOpcode,
2504 FourthSrcVec, FourthIndex)))
2505 return SDValue();
2506
2507 if (FirstOpcode != SecondOpcode)
2508 return SDValue();
2509
2510 // TODO Add an optimization similar to the v2f64 below for shuffling the
2511 // vectors when the lanes are in the wrong order or come from different src
2512 // vectors.
2513 if (NumLanes == 4 &&
2514 (FirstOpcode != ThirdOpcode || FirstOpcode != FourthOpcode ||
2515 FirstSrcVec != SecondSrcVec || FirstSrcVec != ThirdSrcVec ||
2516 FirstSrcVec != FourthSrcVec || FirstIndex != 0 || SecondIndex != 1 ||
2517 ThirdIndex != 2 || FourthIndex != 3))
2518 return SDValue();
2519
2520 MVT ExpectedSrcVT;
2521 switch (FirstOpcode) {
2522 case WebAssemblyISD::CONVERT_LOW_S:
2523 case WebAssemblyISD::CONVERT_LOW_U:
2524 ExpectedSrcVT = MVT::v4i32;
2525 break;
2526 case WebAssemblyISD::PROMOTE_LOW:
2527 ExpectedSrcVT = NumLanes == 2 ? MVT::v4f32 : MVT::v8i16;
2528 break;
2529 }
2530 if (FirstSrcVec.getValueType() != ExpectedSrcVT)
2531 return SDValue();
2532
2533 auto Src = FirstSrcVec;
2534 if (NumLanes == 2 &&
2535 (FirstIndex != 0 || SecondIndex != 1 || FirstSrcVec != SecondSrcVec)) {
2536 // Shuffle the source vector so that the converted lanes are the low lanes.
2537 Src = DAG.getVectorShuffle(ExpectedSrcVT, DL, FirstSrcVec, SecondSrcVec,
2538 {static_cast<int>(FirstIndex),
2539 static_cast<int>(SecondIndex) + 4, -1, -1});
2540 }
2541 return DAG.getNode(FirstOpcode, DL, NumLanes == 2 ? MVT::v2f64 : MVT::v4f32,
2542 Src);
2543}
2544
2545SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
2546 SelectionDAG &DAG) const {
2547 MVT VT = Op.getSimpleValueType();
2548 if (VT == MVT::v8f16) {
2549 // BUILD_VECTOR can't handle FP16 operands since Wasm doesn't have a scalar
2550 // FP16 type, so cast them to I16s.
2551 MVT IVT = VT.changeVectorElementType(MVT::i16);
2553 for (unsigned I = 0, E = Op.getNumOperands(); I < E; ++I)
2554 NewOps.push_back(DAG.getBitcast(MVT::i16, Op.getOperand(I)));
2555 SDValue Res = DAG.getNode(ISD::BUILD_VECTOR, SDLoc(), IVT, NewOps);
2556 return DAG.getBitcast(VT, Res);
2557 }
2558
2559 if (auto ConvertLow = LowerConvertLow(Op, DAG))
2560 return ConvertLow;
2561
2562 SDLoc DL(Op);
2563 const EVT VecT = Op.getValueType();
2564 const EVT LaneT = Op.getOperand(0).getValueType();
2565 const size_t Lanes = Op.getNumOperands();
2566 bool CanSwizzle = VecT == MVT::v16i8;
2567
2568 // BUILD_VECTORs are lowered to the instruction that initializes the highest
2569 // possible number of lanes at once followed by a sequence of replace_lane
2570 // instructions to individually initialize any remaining lanes.
2571
2572 // TODO: Tune this. For example, lanewise swizzling is very expensive, so
2573 // swizzled lanes should be given greater weight.
2574
2575 // TODO: Investigate looping rather than always extracting/replacing specific
2576 // lanes to fill gaps.
2577
2578 auto IsConstant = [](const SDValue &V) {
2579 return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
2580 };
2581
2582 // Returns the source vector and index vector pair if they exist. Checks for:
2583 // (extract_vector_elt
2584 // $src,
2585 // (sign_extend_inreg (extract_vector_elt $indices, $i))
2586 // )
2587 auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
2588 auto Bail = std::make_pair(SDValue(), SDValue());
2589 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2590 return Bail;
2591 const SDValue &SwizzleSrc = Lane->getOperand(0);
2592 const SDValue &IndexExt = Lane->getOperand(1);
2593 if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
2594 return Bail;
2595 const SDValue &Index = IndexExt->getOperand(0);
2596 if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2597 return Bail;
2598 const SDValue &SwizzleIndices = Index->getOperand(0);
2599 if (SwizzleSrc.getValueType() != MVT::v16i8 ||
2600 SwizzleIndices.getValueType() != MVT::v16i8 ||
2601 Index->getOperand(1)->getOpcode() != ISD::Constant ||
2602 Index->getConstantOperandVal(1) != I)
2603 return Bail;
2604 return std::make_pair(SwizzleSrc, SwizzleIndices);
2605 };
2606
2607 // If the lane is extracted from another vector at a constant index, return
2608 // that vector. The source vector must not have more lanes than the dest
2609 // because the shufflevector indices are in terms of the destination lanes and
2610 // would not be able to address the smaller individual source lanes.
2611 auto GetShuffleSrc = [&](const SDValue &Lane) {
2612 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2613 return SDValue();
2614 if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode()))
2615 return SDValue();
2616 if (Lane->getOperand(0).getValueType().getVectorNumElements() >
2617 VecT.getVectorNumElements())
2618 return SDValue();
2619 return Lane->getOperand(0);
2620 };
2621
2622 using ValueEntry = std::pair<SDValue, size_t>;
2623 SmallVector<ValueEntry, 16> SplatValueCounts;
2624
2625 using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
2626 SmallVector<SwizzleEntry, 16> SwizzleCounts;
2627
2628 using ShuffleEntry = std::pair<SDValue, size_t>;
2629 SmallVector<ShuffleEntry, 16> ShuffleCounts;
2630
2631 auto AddCount = [](auto &Counts, const auto &Val) {
2632 auto CountIt =
2633 llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; });
2634 if (CountIt == Counts.end()) {
2635 Counts.emplace_back(Val, 1);
2636 } else {
2637 CountIt->second++;
2638 }
2639 };
2640
2641 auto GetMostCommon = [](auto &Counts) {
2642 auto CommonIt = llvm::max_element(Counts, llvm::less_second());
2643 assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
2644 return *CommonIt;
2645 };
2646
2647 size_t NumConstantLanes = 0;
2648
2649 // Count eligible lanes for each type of vector creation op
2650 for (size_t I = 0; I < Lanes; ++I) {
2651 const SDValue &Lane = Op->getOperand(I);
2652 if (Lane.isUndef())
2653 continue;
2654
2655 AddCount(SplatValueCounts, Lane);
2656
2657 if (IsConstant(Lane))
2658 NumConstantLanes++;
2659 if (auto ShuffleSrc = GetShuffleSrc(Lane))
2660 AddCount(ShuffleCounts, ShuffleSrc);
2661 if (CanSwizzle) {
2662 auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
2663 if (SwizzleSrcs.first)
2664 AddCount(SwizzleCounts, SwizzleSrcs);
2665 }
2666 }
2667
2668 SDValue SplatValue;
2669 size_t NumSplatLanes;
2670 std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
2671
2672 SDValue SwizzleSrc;
2673 SDValue SwizzleIndices;
2674 size_t NumSwizzleLanes = 0;
2675 if (SwizzleCounts.size())
2676 std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
2677 NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
2678
2679 // Shuffles can draw from up to two vectors, so find the two most common
2680 // sources.
2681 SDValue ShuffleSrc1, ShuffleSrc2;
2682 size_t NumShuffleLanes = 0;
2683 if (ShuffleCounts.size()) {
2684 std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts);
2685 llvm::erase_if(ShuffleCounts,
2686 [&](const auto &Pair) { return Pair.first == ShuffleSrc1; });
2687 }
2688 if (ShuffleCounts.size()) {
2689 size_t AdditionalShuffleLanes;
2690 std::tie(ShuffleSrc2, AdditionalShuffleLanes) =
2691 GetMostCommon(ShuffleCounts);
2692 NumShuffleLanes += AdditionalShuffleLanes;
2693 }
2694
2695 // Predicate returning true if the lane is properly initialized by the
2696 // original instruction
2697 std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
2699 // Prefer swizzles over shuffles over vector consts over splats
2700 if (NumSwizzleLanes >= NumShuffleLanes &&
2701 NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) {
2702 Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
2703 SwizzleIndices);
2704 auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
2705 IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
2706 return Swizzled == GetSwizzleSrcs(I, Lane);
2707 };
2708 } else if (NumShuffleLanes >= NumConstantLanes &&
2709 NumShuffleLanes >= NumSplatLanes) {
2710 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8;
2711 size_t DestLaneCount = VecT.getVectorNumElements();
2712 size_t Scale1 = 1;
2713 size_t Scale2 = 1;
2714 SDValue Src1 = ShuffleSrc1;
2715 SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT);
2716 if (Src1.getValueType() != VecT) {
2717 size_t LaneSize =
2718 Src1.getValueType().getVectorElementType().getFixedSizeInBits() / 8;
2719 assert(LaneSize > DestLaneSize);
2720 Scale1 = LaneSize / DestLaneSize;
2721 Src1 = DAG.getBitcast(VecT, Src1);
2722 }
2723 if (Src2.getValueType() != VecT) {
2724 size_t LaneSize =
2725 Src2.getValueType().getVectorElementType().getFixedSizeInBits() / 8;
2726 assert(LaneSize > DestLaneSize);
2727 Scale2 = LaneSize / DestLaneSize;
2728 Src2 = DAG.getBitcast(VecT, Src2);
2729 }
2730
2731 int Mask[16];
2732 assert(DestLaneCount <= 16);
2733 for (size_t I = 0; I < DestLaneCount; ++I) {
2734 const SDValue &Lane = Op->getOperand(I);
2735 SDValue Src = GetShuffleSrc(Lane);
2736 if (Src == ShuffleSrc1) {
2737 Mask[I] = Lane->getConstantOperandVal(1) * Scale1;
2738 } else if (Src && Src == ShuffleSrc2) {
2739 Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2;
2740 } else {
2741 Mask[I] = -1;
2742 }
2743 }
2744 ArrayRef<int> MaskRef(Mask, DestLaneCount);
2745 Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef);
2746 IsLaneConstructed = [&](size_t, const SDValue &Lane) {
2747 auto Src = GetShuffleSrc(Lane);
2748 return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2);
2749 };
2750 } else if (NumConstantLanes >= NumSplatLanes) {
2751 SmallVector<SDValue, 16> ConstLanes;
2752 for (const SDValue &Lane : Op->op_values()) {
2753 if (IsConstant(Lane)) {
2754 // Values may need to be fixed so that they will sign extend to be
2755 // within the expected range during ISel. Check whether the value is in
2756 // bounds based on the lane bit width and if it is out of bounds, lop
2757 // off the extra bits.
2758 uint64_t LaneBits = 128 / Lanes;
2759 if (auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode())) {
2760 ConstLanes.push_back(DAG.getConstant(
2761 Const->getAPIntValue().trunc(LaneBits).getZExtValue(),
2762 SDLoc(Lane), LaneT));
2763 } else {
2764 ConstLanes.push_back(Lane);
2765 }
2766 } else if (LaneT.isFloatingPoint()) {
2767 ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
2768 } else {
2769 ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
2770 }
2771 }
2772 Result = DAG.getBuildVector(VecT, DL, ConstLanes);
2773 IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) {
2774 return IsConstant(Lane);
2775 };
2776 } else {
2777 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits();
2778 if (NumSplatLanes == 1 && Op->getOperand(0) == SplatValue &&
2779 (DestLaneSize == 32 || DestLaneSize == 64)) {
2780 // Could be selected to load_zero.
2781 Result = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecT, SplatValue);
2782 } else {
2783 // Use a splat (which might be selected as a load splat)
2784 Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
2785 }
2786 IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) {
2787 return Lane == SplatValue;
2788 };
2789 }
2790
2791 assert(Result);
2792 assert(IsLaneConstructed);
2793
2794 // Add replace_lane instructions for any unhandled values
2795 for (size_t I = 0; I < Lanes; ++I) {
2796 const SDValue &Lane = Op->getOperand(I);
2797 if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
2798 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
2799 DAG.getConstant(I, DL, MVT::i32));
2800 }
2801
2802 return Result;
2803}
2804
2805SDValue
2806WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2807 SelectionDAG &DAG) const {
2808 SDLoc DL(Op);
2809 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
2810 MVT VecType = Op.getOperand(0).getSimpleValueType();
2811 assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
2812 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
2813
2814 // Space for two vector args and sixteen mask indices
2815 SDValue Ops[18];
2816 size_t OpIdx = 0;
2817 Ops[OpIdx++] = Op.getOperand(0);
2818 Ops[OpIdx++] = Op.getOperand(1);
2819
2820 // Expand mask indices to byte indices and materialize them as operands
2821 for (int M : Mask) {
2822 for (size_t J = 0; J < LaneBytes; ++J) {
2823 // Lower undefs (represented by -1 in mask) to {0..J}, which use a
2824 // whole lane of vector input, to allow further reduction at VM. E.g.
2825 // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle.
2826 uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J;
2827 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
2828 }
2829 }
2830
2831 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2832}
2833
2834SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
2835 SelectionDAG &DAG) const {
2836 SDLoc DL(Op);
2837 // The legalizer does not know how to expand the unsupported comparison modes
2838 // of i64x2 vectors, so we manually unroll them here.
2839 assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
2841 DAG.ExtractVectorElements(Op->getOperand(0), LHS);
2842 DAG.ExtractVectorElements(Op->getOperand(1), RHS);
2843 const SDValue &CC = Op->getOperand(2);
2844 auto MakeLane = [&](unsigned I) {
2845 return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
2846 DAG.getConstant(uint64_t(-1), DL, MVT::i64),
2847 DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
2848 };
2849 return DAG.getBuildVector(Op->getValueType(0), DL,
2850 {MakeLane(0), MakeLane(1)});
2851}
2852
2853SDValue
2854WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
2855 SelectionDAG &DAG) const {
2856 if (Op.getOpcode() == ISD::INSERT_VECTOR_ELT &&
2857 Op.getValueType() == MVT::v8f16) {
2858 // INSERT_VECTOR_ELT can't handle FP16 operands since Wasm doesn't have a
2859 // scalar FP16 type, so cast them to I16s.
2860 SDLoc DL(Op);
2861 SDValue IntVector = DAG.getBitcast(MVT::v8i16, Op.getOperand(0));
2862 SDValue IntElement = DAG.getBitcast(MVT::i16, Op.getOperand(1));
2864 IntVector, IntElement, Op.getOperand(2));
2865 return DAG.getBitcast(MVT::v8f16, Inserted);
2866 }
2867
2868 // Allow constant lane indices, expand variable lane indices
2869 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
2870 if (isa<ConstantSDNode>(IdxNode)) {
2871 // Ensure the index type is i32 to match the tablegen patterns
2872 uint64_t Idx = IdxNode->getAsZExtVal();
2873 SmallVector<SDValue, 3> Ops(Op.getNode()->ops());
2874 Ops[Op.getNumOperands() - 1] =
2875 DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32);
2876 return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops);
2877 }
2878 // Perform default expansion
2879 return SDValue();
2880}
2881
2883 EVT LaneT = Op.getSimpleValueType().getVectorElementType();
2884 // 32-bit and 64-bit unrolled shifts will have proper semantics
2885 if (LaneT.bitsGE(MVT::i32))
2886 return DAG.UnrollVectorOp(Op.getNode());
2887 // Otherwise mask the shift value to get proper semantics from 32-bit shift
2888 SDLoc DL(Op);
2889 size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
2890 SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
2891 unsigned ShiftOpcode = Op.getOpcode();
2892 SmallVector<SDValue, 16> ShiftedElements;
2893 DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
2894 SmallVector<SDValue, 16> ShiftElements;
2895 DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
2896 SmallVector<SDValue, 16> UnrolledOps;
2897 for (size_t i = 0; i < NumLanes; ++i) {
2898 SDValue MaskedShiftValue =
2899 DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
2900 SDValue ShiftedValue = ShiftedElements[i];
2901 if (ShiftOpcode == ISD::SRA)
2902 ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
2903 ShiftedValue, DAG.getValueType(LaneT));
2904 UnrolledOps.push_back(
2905 DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
2906 }
2907 return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
2908}
2909
2910SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
2911 SelectionDAG &DAG) const {
2912 SDLoc DL(Op);
2913 // Only manually lower vector shifts
2914 assert(Op.getSimpleValueType().isVector());
2915
2916 uint64_t LaneBits = Op.getValueType().getScalarSizeInBits();
2917 auto ShiftVal = Op.getOperand(1);
2918
2919 // Try to skip bitmask operation since it is implied inside shift instruction
2920 auto SkipImpliedMask = [](SDValue MaskOp, uint64_t MaskBits) {
2921 if (MaskOp.getOpcode() != ISD::AND)
2922 return MaskOp;
2923 SDValue LHS = MaskOp.getOperand(0);
2924 SDValue RHS = MaskOp.getOperand(1);
2925 if (MaskOp.getValueType().isVector()) {
2926 APInt MaskVal;
2927 if (!ISD::isConstantSplatVector(RHS.getNode(), MaskVal))
2928 std::swap(LHS, RHS);
2929
2930 if (ISD::isConstantSplatVector(RHS.getNode(), MaskVal) &&
2931 MaskVal == MaskBits)
2932 MaskOp = LHS;
2933 } else {
2934 if (!isa<ConstantSDNode>(RHS.getNode()))
2935 std::swap(LHS, RHS);
2936
2937 auto ConstantRHS = dyn_cast<ConstantSDNode>(RHS.getNode());
2938 if (ConstantRHS && ConstantRHS->getAPIntValue() == MaskBits)
2939 MaskOp = LHS;
2940 }
2941
2942 return MaskOp;
2943 };
2944
2945 // Skip vector and operation
2946 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2947 ShiftVal = DAG.getSplatValue(ShiftVal);
2948 if (!ShiftVal)
2949 return unrollVectorShift(Op, DAG);
2950
2951 // Skip scalar and operation
2952 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2953 // Use anyext because none of the high bits can affect the shift
2954 ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
2955
2956 unsigned Opcode;
2957 switch (Op.getOpcode()) {
2958 case ISD::SHL:
2959 Opcode = WebAssemblyISD::VEC_SHL;
2960 break;
2961 case ISD::SRA:
2962 Opcode = WebAssemblyISD::VEC_SHR_S;
2963 break;
2964 case ISD::SRL:
2965 Opcode = WebAssemblyISD::VEC_SHR_U;
2966 break;
2967 default:
2968 llvm_unreachable("unexpected opcode");
2969 }
2970
2971 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
2972}
2973
2974SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op,
2975 SelectionDAG &DAG) const {
2976 EVT ResT = Op.getValueType();
2977 EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
2978
2979 if ((ResT == MVT::i32 || ResT == MVT::i64) &&
2980 (SatVT == MVT::i32 || SatVT == MVT::i64))
2981 return Op;
2982
2983 if (ResT == MVT::v4i32 && SatVT == MVT::i32)
2984 return Op;
2985
2986 if (ResT == MVT::v8i16 && SatVT == MVT::i16)
2987 return Op;
2988
2989 return SDValue();
2990}
2991
2993 return (Op->getFlags().hasNoNaNs() ||
2994 (DAG.isKnownNeverNaN(Op->getOperand(0)) &&
2995 DAG.isKnownNeverNaN(Op->getOperand(1)))) &&
2996 (Op->getFlags().hasNoSignedZeros() ||
2997 DAG.isKnownNeverLogicalZero(Op->getOperand(0)) ||
2998 DAG.isKnownNeverLogicalZero(Op->getOperand(1)));
2999}
3000
3001SDValue WebAssemblyTargetLowering::LowerFMIN(SDValue Op,
3002 SelectionDAG &DAG) const {
3003 if (Subtarget->hasRelaxedSIMD() && HasNoSignedZerosOrNaNs(Op, DAG)) {
3004 return DAG.getNode(WebAssemblyISD::RELAXED_FMIN, SDLoc(Op),
3005 Op.getValueType(), Op.getOperand(0), Op.getOperand(1));
3006 }
3007 return SDValue();
3008}
3009
3010SDValue WebAssemblyTargetLowering::LowerFMAX(SDValue Op,
3011 SelectionDAG &DAG) const {
3012 if (Subtarget->hasRelaxedSIMD() && HasNoSignedZerosOrNaNs(Op, DAG)) {
3013 return DAG.getNode(WebAssemblyISD::RELAXED_FMAX, SDLoc(Op),
3014 Op.getValueType(), Op.getOperand(0), Op.getOperand(1));
3015 }
3016 return SDValue();
3017}
3018
3019//===----------------------------------------------------------------------===//
3020// Custom DAG combine hooks
3021//===----------------------------------------------------------------------===//
3022static SDValue
3024 auto &DAG = DCI.DAG;
3025 auto Shuffle = cast<ShuffleVectorSDNode>(N);
3026
3027 // Hoist vector bitcasts that don't change the number of lanes out of unary
3028 // shuffles, where they are less likely to get in the way of other combines.
3029 // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
3030 // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
3031 SDValue Bitcast = N->getOperand(0);
3032 if (Bitcast.getOpcode() != ISD::BITCAST)
3033 return SDValue();
3034 if (!N->getOperand(1).isUndef())
3035 return SDValue();
3036 SDValue CastOp = Bitcast.getOperand(0);
3037 EVT SrcType = CastOp.getValueType();
3038 EVT DstType = Bitcast.getValueType();
3039 if (!SrcType.is128BitVector() ||
3040 SrcType.getVectorNumElements() != DstType.getVectorNumElements())
3041 return SDValue();
3042 SDValue NewShuffle = DAG.getVectorShuffle(
3043 SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
3044 return DAG.getBitcast(DstType, NewShuffle);
3045}
3046
3047/// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get
3048/// split up into scalar instructions during legalization, and the vector
3049/// extending instructions are selected in performVectorExtendCombine below.
3050static SDValue
3053 auto &DAG = DCI.DAG;
3054 assert(N->getOpcode() == ISD::UINT_TO_FP ||
3055 N->getOpcode() == ISD::SINT_TO_FP);
3056
3057 EVT InVT = N->getOperand(0)->getValueType(0);
3058 EVT ResVT = N->getValueType(0);
3059 MVT ExtVT;
3060 if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8))
3061 ExtVT = MVT::v4i32;
3062 else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8))
3063 ExtVT = MVT::v2i32;
3064 else if (Subtarget->hasFP16() && ResVT == MVT::v8f16 && InVT == MVT::v8i8)
3065 ExtVT = MVT::v8i16;
3066 else
3067 return SDValue();
3068
3069 unsigned Op =
3071 SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0));
3072 return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv);
3073}
3074
3075static SDValue
3078 auto &DAG = DCI.DAG;
3079
3080 SDNodeFlags Flags = N->getFlags();
3081 SDValue Op0 = N->getOperand(0);
3082 EVT VT = N->getValueType(0);
3083
3084 // Optimize uitofp to sitofp when the sign bit is known to be zero.
3085 // Depending on the target (runtime) backend, this might be performance
3086 // neutral (e.g. AArch64) or a significant improvement (e.g. x86_64).
3087 if (VT.isVector() && (Flags.hasNonNeg() || DAG.SignBitIsZero(Op0))) {
3088 return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, Op0);
3089 }
3090
3091 return SDValue();
3092}
3093
3094static SDValue
3096 auto &DAG = DCI.DAG;
3097 assert(N->getOpcode() == ISD::SIGN_EXTEND ||
3098 N->getOpcode() == ISD::ZERO_EXTEND);
3099
3100 EVT ResVT = N->getValueType(0);
3101 bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND;
3102 SDLoc DL(N);
3103
3104 if (ResVT == MVT::v16i32 && N->getOperand(0)->getValueType(0) == MVT::v16i8) {
3105 // Use a tree of extend low/high to split and extend the input in two
3106 // layers to avoid doing several shuffles and even more extends.
3107 unsigned LowOp =
3108 IsSext ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3109 unsigned HighOp =
3110 IsSext ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
3111 SDValue Input = N->getOperand(0);
3112 SDValue LowHalf = DAG.getNode(LowOp, DL, MVT::v8i16, Input);
3113 SDValue HighHalf = DAG.getNode(HighOp, DL, MVT::v8i16, Input);
3114 SDValue Subvectors[] = {
3115 DAG.getNode(LowOp, DL, MVT::v4i32, LowHalf),
3116 DAG.getNode(HighOp, DL, MVT::v4i32, LowHalf),
3117 DAG.getNode(LowOp, DL, MVT::v4i32, HighHalf),
3118 DAG.getNode(HighOp, DL, MVT::v4i32, HighHalf),
3119 };
3120 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Subvectors);
3121 }
3122
3123 // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if
3124 // possible before the extract_subvector can be expanded.
3125 auto Extract = N->getOperand(0);
3126 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR)
3127 return SDValue();
3128 auto Source = Extract.getOperand(0);
3129 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1));
3130 if (IndexNode == nullptr)
3131 return SDValue();
3132 auto Index = IndexNode->getZExtValue();
3133
3134 // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the
3135 // extracted subvector is the low or high half of its source.
3136 if (ResVT == MVT::v8i16) {
3137 if (Extract.getValueType() != MVT::v8i8 ||
3138 Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8))
3139 return SDValue();
3140 } else if (ResVT == MVT::v4i32) {
3141 if (Extract.getValueType() != MVT::v4i16 ||
3142 Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4))
3143 return SDValue();
3144 } else if (ResVT == MVT::v2i64) {
3145 if (Extract.getValueType() != MVT::v2i32 ||
3146 Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2))
3147 return SDValue();
3148 } else {
3149 return SDValue();
3150 }
3151
3152 bool IsLow = Index == 0;
3153
3154 unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S
3155 : WebAssemblyISD::EXTEND_HIGH_S)
3156 : (IsLow ? WebAssemblyISD::EXTEND_LOW_U
3157 : WebAssemblyISD::EXTEND_HIGH_U);
3158
3159 return DAG.getNode(Op, DL, ResVT, Source);
3160}
3161
3162static SDValue
3164 auto &DAG = DCI.DAG;
3165
3166 auto GetWasmConversionOp = [](unsigned Op) {
3167 switch (Op) {
3169 return WebAssemblyISD::TRUNC_SAT_ZERO_S;
3171 return WebAssemblyISD::TRUNC_SAT_ZERO_U;
3172 case ISD::FP_ROUND:
3173 return WebAssemblyISD::DEMOTE_ZERO;
3174 }
3175 llvm_unreachable("unexpected op");
3176 };
3177
3178 auto IsZeroSplat = [](SDValue SplatVal) {
3179 auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode());
3180 APInt SplatValue, SplatUndef;
3181 unsigned SplatBitSize;
3182 bool HasAnyUndefs;
3183 // Endianness doesn't matter in this context because we are looking for
3184 // an all-zero value.
3185 return Splat &&
3186 Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
3187 HasAnyUndefs) &&
3188 SplatValue == 0;
3189 };
3190
3191 if (N->getOpcode() == ISD::CONCAT_VECTORS) {
3192 // Combine this:
3193 //
3194 // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0)))
3195 //
3196 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3197 //
3198 // Or this:
3199 //
3200 // (concat_vectors ({v2f32, v4f16} (fp_round ({v2f64, v4f32} $x))),
3201 // ({v2f32, v4f16} (splat 0)))
3202 //
3203 // into ({f32x4, f16x8}.demote_zero_{f64x2, f32x4} $x).
3204 EVT ResVT;
3205 EVT ExpectedConversionType;
3206 auto Conversion = N->getOperand(0);
3207 auto ConversionOp = Conversion.getOpcode();
3208 switch (ConversionOp) {
3211 ResVT = MVT::v4i32;
3212 ExpectedConversionType = MVT::v2i32;
3213 break;
3214 case ISD::FP_ROUND:
3215 if (Conversion.getValueType() == MVT::v2f32) {
3216 ResVT = MVT::v4f32;
3217 ExpectedConversionType = MVT::v2f32;
3218 } else if (Conversion.getValueType() == MVT::v4f16) {
3219 ResVT = MVT::v8f16;
3220 ExpectedConversionType = MVT::v4f16;
3221 } else {
3222 return SDValue();
3223 }
3224 break;
3225 default:
3226 return SDValue();
3227 }
3228
3229 if (N->getValueType(0) != ResVT)
3230 return SDValue();
3231
3232 if (Conversion.getValueType() != ExpectedConversionType)
3233 return SDValue();
3234
3235 auto Source = Conversion.getOperand(0);
3236 if (!((Source.getValueType() == MVT::v2f64 && ResVT == MVT::v4f32) ||
3237 (Source.getValueType() == MVT::v2f64 && ResVT == MVT::v4i32) ||
3238 (Source.getValueType() == MVT::v4f32 && ResVT == MVT::v8f16)))
3239 return SDValue();
3240
3241 if (!IsZeroSplat(N->getOperand(1)) ||
3242 N->getOperand(1).getValueType() != ExpectedConversionType)
3243 return SDValue();
3244
3245 unsigned Op = GetWasmConversionOp(ConversionOp);
3246 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
3247 }
3248
3249 // Combine this:
3250 //
3251 // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32)
3252 //
3253 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3254 //
3255 // Or this:
3256 //
3257 // ({v4f32, v8f16} (fp_round (concat_vectors $x,
3258 // ({v2f64, v4f32} (splat 0)))))
3259 //
3260 // into ({f32x4, f16x8}.demote_zero_{f64x2, f32x4} $x).
3261 EVT ResVT;
3262 auto ConversionOp = N->getOpcode();
3263 switch (ConversionOp) {
3266 ResVT = MVT::v4i32;
3267 break;
3268 case ISD::FP_ROUND:
3269 ResVT = N->getValueType(0);
3270 break;
3271 default:
3272 llvm_unreachable("unexpected op");
3273 }
3274
3275 if (N->getValueType(0) != ResVT)
3276 return SDValue();
3277
3278 auto Concat = N->getOperand(0);
3279 if (Concat.getOpcode() != ISD::CONCAT_VECTORS)
3280 return SDValue();
3281 EVT ConcatVT = Concat.getValueType();
3282 EVT SourceVT = Concat.getOperand(0).getValueType();
3283
3284 if (!IsZeroSplat(Concat.getOperand(1)))
3285 return SDValue();
3286
3287 if (ConversionOp == ISD::FP_ROUND) {
3288 bool IsF64ToF32 =
3289 ConcatVT == MVT::v4f64 && SourceVT == MVT::v2f64 && ResVT == MVT::v4f32;
3290 bool IsF32ToF16 =
3291 ConcatVT == MVT::v8f32 && SourceVT == MVT::v4f32 && ResVT == MVT::v8f16;
3292 if (!(IsF64ToF32 || IsF32ToF16))
3293 return SDValue();
3294 } else {
3295 if (ConcatVT != MVT::v4f64 || SourceVT != MVT::v2f64 || ResVT != MVT::v4i32)
3296 return SDValue();
3297 }
3298
3299 unsigned Op = GetWasmConversionOp(ConversionOp);
3300 return DAG.getNode(Op, SDLoc(N), ResVT, Concat.getOperand(0));
3301}
3302
3303// Helper to extract VectorWidth bits from Vec, starting from IdxVal.
3304static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
3305 const SDLoc &DL, unsigned VectorWidth) {
3306 EVT VT = Vec.getValueType();
3307 EVT ElVT = VT.getVectorElementType();
3308 unsigned Factor = VT.getSizeInBits() / VectorWidth;
3309 EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT,
3310 VT.getVectorNumElements() / Factor);
3311
3312 // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR
3313 unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits();
3314 assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2");
3315
3316 // This is the index of the first element of the VectorWidth-bit chunk
3317 // we want. Since ElemsPerChunk is a power of 2 just need to clear bits.
3318 IdxVal &= ~(ElemsPerChunk - 1);
3319
3320 // If the input is a buildvector just emit a smaller one.
3321 if (Vec.getOpcode() == ISD::BUILD_VECTOR)
3322 return DAG.getBuildVector(ResultVT, DL,
3323 Vec->ops().slice(IdxVal, ElemsPerChunk));
3324
3325 SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL);
3326 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx);
3327}
3328
3329// Helper to recursively truncate vector elements in half with NARROW_U. DstVT
3330// is the expected destination value type after recursion. In is the initial
3331// input. Note that the input should have enough leading zero bits to prevent
3332// NARROW_U from saturating results.
3334 SelectionDAG &DAG) {
3335 EVT SrcVT = In.getValueType();
3336
3337 // No truncation required, we might get here due to recursive calls.
3338 if (SrcVT == DstVT)
3339 return In;
3340
3341 unsigned SrcSizeInBits = SrcVT.getSizeInBits();
3342 unsigned NumElems = SrcVT.getVectorNumElements();
3343 if (!isPowerOf2_32(NumElems))
3344 return SDValue();
3345 assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
3346 assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation");
3347
3348 LLVMContext &Ctx = *DAG.getContext();
3349 EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2);
3350
3351 // Narrow to the largest type possible:
3352 // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u.
3353 EVT InVT = MVT::i16, OutVT = MVT::i8;
3354 if (SrcVT.getScalarSizeInBits() > 16) {
3355 InVT = MVT::i32;
3356 OutVT = MVT::i16;
3357 }
3358 unsigned SubSizeInBits = SrcSizeInBits / 2;
3359 InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits());
3360 OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits());
3361
3362 // Split lower/upper subvectors.
3363 SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits);
3364 SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits);
3365
3366 // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors.
3367 if (SrcVT.is256BitVector() && DstVT.is128BitVector()) {
3368 Lo = DAG.getBitcast(InVT, Lo);
3369 Hi = DAG.getBitcast(InVT, Hi);
3370 SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi);
3371 return DAG.getBitcast(DstVT, Res);
3372 }
3373
3374 // Recursively narrow lower/upper subvectors, concat result and narrow again.
3375 EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2);
3376 Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG);
3377 Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG);
3378
3379 PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems);
3380 SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
3381 return truncateVectorWithNARROW(DstVT, Res, DL, DAG);
3382}
3383
3386 auto &DAG = DCI.DAG;
3387
3388 SDValue In = N->getOperand(0);
3389 EVT InVT = In.getValueType();
3390 if (!InVT.isSimple())
3391 return SDValue();
3392
3393 EVT OutVT = N->getValueType(0);
3394 if (!OutVT.isVector())
3395 return SDValue();
3396
3397 EVT OutSVT = OutVT.getVectorElementType();
3398 EVT InSVT = InVT.getVectorElementType();
3399 // Currently only cover truncate to v16i8 or v8i16.
3400 if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) &&
3401 (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector()))
3402 return SDValue();
3403
3404 SDLoc DL(N);
3406 OutVT.getScalarSizeInBits());
3407 In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT));
3408 return truncateVectorWithNARROW(OutVT, In, DL, DAG);
3409}
3410
3413 using namespace llvm::SDPatternMatch;
3414 auto &DAG = DCI.DAG;
3415 SDLoc DL(N);
3416 SDValue Src = N->getOperand(0);
3417 EVT VT = N->getValueType(0);
3418 EVT SrcVT = Src.getValueType();
3419
3420 if (!(DCI.isBeforeLegalize() && VT.isScalarInteger() &&
3421 SrcVT.isFixedLengthVectorOf(MVT::i1)))
3422 return SDValue();
3423
3424 unsigned NumElts = SrcVT.getVectorNumElements();
3425 EVT Width = MVT::getIntegerVT(128 / NumElts);
3426
3427 // bitcast <N x i1> to iN, where N = 2, 4, 8, 16 (legal)
3428 // ==> bitmask
3429 if (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16) {
3430 return DAG.getZExtOrTrunc(
3431 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3432 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32),
3433 DAG.getSExtOrTrunc(N->getOperand(0), DL,
3434 SrcVT.changeVectorElementType(
3435 *DAG.getContext(), Width))}),
3436 DL, VT);
3437 }
3438
3439 // bitcast <N x i1>(setcc ...) to concat iN, where N = 32 and 64 (illegal)
3440 if (NumElts == 32 || NumElts == 64) {
3441 SDValue Concat, SetCCVector;
3442 ISD::CondCode SetCond;
3443
3444 if (!sd_match(N, m_BitCast(m_c_SetCC(SetCond, m_Value(Concat),
3445 m_Value(SetCCVector)))))
3446 return SDValue();
3447 if (Concat.getOpcode() != ISD::CONCAT_VECTORS)
3448 return SDValue();
3449
3450 // Reconstruct the wide bitmask from each CONCAT_VECTORS operand.
3451 // Derive the per-chunk mask/integer types from the actual operand type
3452 // instead of hardcoding v16i1 / i16 for every chunk.
3453 EVT ConcatOperandVT = Concat.getOperand(0).getValueType();
3454 unsigned ConcatOperandNumElts = ConcatOperandVT.getVectorNumElements();
3455
3456 EVT ConcatOperandMaskVT =
3457 EVT::getVectorVT(*DAG.getContext(), MVT::i1,
3458 ElementCount::getFixed(ConcatOperandNumElts));
3459 EVT ConcatOperandBitmaskVT =
3460 EVT::getIntegerVT(*DAG.getContext(), ConcatOperandNumElts);
3461 EVT ReturnVT = N->getValueType(0);
3462 SDValue ReconstructedBitmask = DAG.getConstant(0, DL, ReturnVT);
3463 // Example:
3464 // v32i16 = concat(v8i16, v8i16, v8i16, v8i16)
3465 // -> v8i1 + v8i1 + v8i1 + v8i1
3466 // -> i8 + i8 + i8 + i8
3467 // -> reconstructed i32 bitmask
3468 for (size_t I = 0; I < Concat->ops().size(); ++I) {
3469 SDValue ConcatOperand = Concat.getOperand(I);
3470 assert(ConcatOperand.getValueType() == ConcatOperandVT &&
3471 "concat_vectors operands must have the same type");
3472
3473 SDValue SetCCVectorOperand =
3474 extractSubVector(SetCCVector, I * ConcatOperandNumElts, DAG, DL, 128);
3475 if (!SetCCVectorOperand ||
3476 SetCCVectorOperand.getValueType() != ConcatOperandVT)
3477 return SDValue();
3478
3479 // Build the per-chunk mask using the correct chunk type:
3480 // v16i8 -> v16i1 -> i16
3481 // v8i16 -> v8i1 -> i8
3482 // v4i32 -> v4i1 -> i4
3483 // v2i64 -> v2i1 -> i2
3484 SDValue ConcatOperandMask = DAG.getSetCC(
3485 DL, ConcatOperandMaskVT, ConcatOperand, SetCCVectorOperand, SetCond);
3486 SDValue ConcatOperandBitmask =
3487 DAG.getBitcast(ConcatOperandBitmaskVT, ConcatOperandMask);
3488 SDValue ExtendedConcatOperandBitmask =
3489 DAG.getZExtOrTrunc(ConcatOperandBitmask, DL, ReturnVT);
3490
3491 // Shift each chunk's mask to its original lane position before merging it
3492 // into the result:
3493 // Result bit index = I * ConcatOperandNumElts + local lane index
3494 //
3495 // Example: four chunks, each containing 8 mask bits:
3496 // result = M0 | (M1 << 8) | (M2 << 16) | (M3 << 24)
3497 //
3498 SDValue PositionedChunkBitmask = ExtendedConcatOperandBitmask;
3499 if (I != 0) {
3500 PositionedChunkBitmask = DAG.getNode(
3501 ISD::SHL, DL, ReturnVT, ExtendedConcatOperandBitmask,
3502 DAG.getShiftAmountConstant(I * ConcatOperandNumElts, ReturnVT, DL));
3503 }
3504
3505 ReconstructedBitmask = DAG.getNode(
3506 ISD::OR, DL, ReturnVT, ReconstructedBitmask, PositionedChunkBitmask);
3507 }
3508
3509 return ReconstructedBitmask;
3510 }
3511
3512 return SDValue();
3513}
3514
3516 // bitmask (setcc <X>, 0, setlt) => bitmask X
3517 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
3518 using namespace llvm::SDPatternMatch;
3519
3520 if (N->getConstantOperandVal(0) != Intrinsic::wasm_bitmask)
3521 return SDValue();
3522
3523 SDValue LHS;
3524 if (!sd_match(N->getOperand(1),
3526 return SDValue();
3527
3528 SDLoc DL(N);
3529 return DAG.getNode(
3530 ISD::INTRINSIC_WO_CHAIN, DL, N->getValueType(0),
3531 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32), LHS});
3532}
3533
3535 // any_true (setcc <X>, 0, eq) => (not (all_true X))
3536 // all_true (setcc <X>, 0, eq) => (not (any_true X))
3537 // any_true (setcc <X>, 0, ne) => (any_true X)
3538 // all_true (setcc <X>, 0, ne) => (all_true X)
3539 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
3540 using namespace llvm::SDPatternMatch;
3541
3542 SDValue LHS;
3543 if (N->getNumOperands() < 2 ||
3544 !sd_match(N->getOperand(1), m_c_SetCC(m_Value(LHS), m_Zero())))
3545 return SDValue();
3546 EVT LT = LHS.getValueType();
3547 if (LT.getScalarSizeInBits() > 128 / LT.getVectorNumElements())
3548 return SDValue();
3549
3550 auto CombineSetCC = [&N, &DAG](Intrinsic::WASMIntrinsics InPre,
3551 ISD::CondCode SetType,
3552 Intrinsic::WASMIntrinsics InPost) {
3553 if (N->getConstantOperandVal(0) != InPre)
3554 return SDValue();
3555
3556 SDValue LHS;
3557 if (!sd_match(N->getOperand(1),
3558 m_c_SpecificSetCC(SetType, m_Value(LHS), m_Zero())))
3559 return SDValue();
3560
3561 SDLoc DL(N);
3562 SDValue Ret = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3563 {DAG.getConstant(InPost, DL, MVT::i32), LHS});
3564 if (SetType == ISD::SETEQ)
3565 Ret = DAG.getNode(ISD::XOR, DL, MVT::i32, Ret,
3566 DAG.getConstant(1, DL, MVT::i32));
3567 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3568 };
3569
3570 if (SDValue AnyTrueEQ = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETEQ,
3571 Intrinsic::wasm_alltrue))
3572 return AnyTrueEQ;
3573 if (SDValue AllTrueEQ = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETEQ,
3574 Intrinsic::wasm_anytrue))
3575 return AllTrueEQ;
3576 if (SDValue AnyTrueNE = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETNE,
3577 Intrinsic::wasm_anytrue))
3578 return AnyTrueNE;
3579 if (SDValue AllTrueNE = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETNE,
3580 Intrinsic::wasm_alltrue))
3581 return AllTrueNE;
3582
3583 return SDValue();
3584}
3585
3591
3593 unsigned NumElts,
3594 const MaskReduceInfo &Info,
3595 SelectionDAG &DAG) {
3596 EVT VecVT = FromVT.changeVectorElementType(*DAG.getContext(),
3597 MVT::getIntegerVT(128 / NumElts));
3598 assert(VecVT.getSizeInBits() == 128 &&
3599 "mask reduction should be widened to a 128-bit vector");
3600
3601 SDLoc DL(N);
3602 SDValue Mask = N->getOperand(0)->getOperand(0);
3603 SDValue Ret = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3604 {DAG.getConstant(Info.IID, DL, MVT::i32),
3605 DAG.getSExtOrTrunc(Mask, DL, VecVT)});
3606 if (Info.Invert)
3607 Ret = DAG.getNode(ISD::XOR, DL, MVT::i32, Ret,
3608 DAG.getConstant(1, DL, MVT::i32));
3609 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3610}
3611
3613 unsigned NumElts,
3614 const MaskReduceInfo &Info,
3615 SelectionDAG &DAG) {
3616 assert((NumElts == 32 || NumElts == 64) &&
3617 "combineWideMaskReduction is only for wide masks");
3618 assert(MaskVT.isFixedLengthVector() &&
3619 MaskVT.getVectorElementType() == MVT::i1);
3620 SDLoc DL(N);
3621 unsigned ChunkElts = 16;
3622 EVT ChunkMaskVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
3623 ElementCount::getFixed(ChunkElts));
3624 EVT LegalVecVT = ChunkMaskVT.changeVectorElementType(
3625 *DAG.getContext(), MVT::getIntegerVT(128 / ChunkElts));
3626
3627 SmallVector<SDValue, 4> ChunkResults;
3628 // Split the wide mask into v16i1 chunks and reduce each chunk separately.
3629 // For example:
3630 // v32i1: [0..15] [16..31]
3631 // | |
3632 // v v
3633 // chunk0 chunk1
3634 //
3635 // v64i1: [0..15] [16..31] [32..47] [48..63]
3636 // | | | |
3637 // v v v v
3638 // chunk0 chunk1 chunk2 chunk3
3639 //
3640 // each chunk:
3641 // v16i1 -> v16i8 -> wasm_anytrue/alltrue -> i32 0/1
3642 for (unsigned I = 0; I < NumElts; I += ChunkElts) {
3643 SDValue ChunkMask = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ChunkMaskVT,
3644 Mask, DAG.getVectorIdxConstant(I, DL));
3645 SDValue LegalMask = DAG.getSExtOrTrunc(ChunkMask, DL, LegalVecVT);
3646 SDValue Reduced =
3647 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3648 DAG.getConstant(Info.IID, DL, MVT::i32), LegalMask);
3649 ChunkResults.push_back(Reduced);
3650 }
3651
3652 SDValue Acc = ChunkResults[0];
3653 for (unsigned I = 1; I < ChunkResults.size(); ++I)
3654 Acc =
3655 DAG.getNode(Info.WideCombineOpcode, DL, MVT::i32, Acc, ChunkResults[I]);
3656
3657 if (Info.Invert)
3658 Acc = DAG.getNode(ISD::XOR, DL, MVT::i32, Acc,
3659 DAG.getConstant(1, DL, MVT::i32));
3660
3661 return DAG.getZExtOrTrunc(Acc, DL, N->getValueType(0));
3662}
3663
3664static std::optional<MaskReduceInfo> classifyMaskReduction(SDNode *N) {
3665 auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
3666 if (!C)
3667 return std::nullopt;
3668
3669 ISD::CondCode CC = N->getOperandCondCode(2);
3670
3671 // setcc (bitcast mask), 0, ne -> any_true(mask)
3672 if (C->isZero() && CC == ISD::SETNE)
3673 return MaskReduceInfo{Intrinsic::wasm_anytrue, ISD::OR, false};
3674
3675 // setcc (bitcast mask), 0, eq -> !any_true(mask)
3676 if (C->isZero() && CC == ISD::SETEQ)
3677 return MaskReduceInfo{Intrinsic::wasm_anytrue, ISD::OR, true};
3678
3679 // setcc (bitcast mask), -1, eq -> all_true(mask)
3680 if (C->isAllOnes() && CC == ISD::SETEQ)
3681 return MaskReduceInfo{Intrinsic::wasm_alltrue, ISD::AND, false};
3682
3683 // setcc (bitcast mask), -1, ne -> !all_true(mask)
3684 if (C->isAllOnes() && CC == ISD::SETNE)
3685 return MaskReduceInfo{Intrinsic::wasm_alltrue, ISD::AND, true};
3686
3687 return std::nullopt;
3688}
3689
3690/// Try to convert a i128 comparison to a v16i8 comparison before type
3691/// legalization splits it up into chunks
3692static SDValue
3695
3696 SDLoc DL(N);
3697 SDValue X = N->getOperand(0);
3698 SDValue Y = N->getOperand(1);
3699 EVT VT = N->getValueType(0);
3700 EVT OpVT = X.getValueType();
3701
3702 SelectionDAG &DAG = DCI.DAG;
3704 Attribute::NoImplicitFloat))
3705 return SDValue();
3706
3707 ISD::CondCode CC = N->getOperandCondCode(2);
3708 // We're looking for an oversized integer equality comparison with SIMD
3709 if (!OpVT.isScalarInteger() || !OpVT.isByteSized() || OpVT != MVT::i128 ||
3710 !Subtarget->hasSIMD128() || !isIntEqualitySetCC(CC))
3711 return SDValue();
3712
3713 // Don't perform this combine if constructing the vector will be expensive.
3714 auto IsVectorBitCastCheap = [](SDValue X) {
3716 return isa<ConstantSDNode>(X) || X.getOpcode() == ISD::LOAD;
3717 };
3718
3719 if (!IsVectorBitCastCheap(X) || !IsVectorBitCastCheap(Y))
3720 return SDValue();
3721
3722 SDValue VecX = DAG.getBitcast(MVT::v16i8, X);
3723 SDValue VecY = DAG.getBitcast(MVT::v16i8, Y);
3724 SDValue Cmp = DAG.getSetCC(DL, MVT::v16i8, VecX, VecY, CC);
3725
3726 SDValue Intr =
3727 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3728 {DAG.getConstant(CC == ISD::SETEQ ? Intrinsic::wasm_alltrue
3729 : Intrinsic::wasm_anytrue,
3730 DL, MVT::i32),
3731 Cmp});
3732
3733 return DAG.getSetCC(DL, VT, Intr, DAG.getConstant(0, DL, MVT::i32),
3734 ISD::SETNE);
3735}
3736
3740 if (!DCI.isBeforeLegalize())
3741 return SDValue();
3742
3743 EVT VT = N->getValueType(0);
3744 if (!VT.isScalarInteger())
3745 return SDValue();
3746
3748 return V;
3749
3750 SDValue LHS = N->getOperand(0);
3751 if (LHS->getOpcode() != ISD::BITCAST)
3752 return SDValue();
3753
3754 EVT FromVT = LHS->getOperand(0).getValueType();
3755 if (!FromVT.isFixedLengthVectorOf(MVT::i1))
3756 return SDValue();
3757
3758 unsigned NumElts = FromVT.getVectorNumElements();
3759 auto Info = classifyMaskReduction(N);
3760 if (!Info)
3761 return SDValue();
3762
3763 auto &DAG = DCI.DAG;
3764 if (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16)
3765 return combineSmallMaskReduction(N, FromVT, NumElts, *Info, DAG);
3766
3767 if (NumElts == 32 || NumElts == 64)
3768 return combineWideMaskReduction(N, LHS.getOperand(0), FromVT, NumElts,
3769 *Info, DAG);
3770
3771 return SDValue();
3772}
3773
3774SDValue DoubleVectorWidth(SDValue In, unsigned RequiredNumElems,
3775 SelectionDAG &DAG) {
3776 SDLoc DL(In);
3777 LLVMContext &Ctx = *DAG.getContext();
3778 EVT InVT = In.getValueType();
3779 unsigned NumElems = InVT.getVectorNumElements() * 2;
3780 EVT OutVT = EVT::getVectorVT(Ctx, InVT.getVectorElementType(), NumElems);
3781 SDValue Concat =
3782 DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, In, DAG.getPOISON(InVT));
3783 if (NumElems < RequiredNumElems) {
3784 return DoubleVectorWidth(Concat, RequiredNumElems, DAG);
3785 }
3786 return Concat;
3787}
3788
3790 EVT VT = N->getValueType(0);
3791 if (VT != MVT::v4i32 && VT != MVT::v8i32 && VT != MVT::v16i32)
3792 return SDValue();
3793
3794 // Mul with extending inputs.
3795 SDValue LHS = N->getOperand(0);
3796 SDValue RHS = N->getOperand(1);
3797 if (LHS.getOpcode() != RHS.getOpcode())
3798 return SDValue();
3799
3800 if (LHS.getOpcode() != ISD::SIGN_EXTEND &&
3801 LHS.getOpcode() != ISD::ZERO_EXTEND)
3802 return SDValue();
3803
3804 if (LHS->getOperand(0).getValueType() != RHS->getOperand(0).getValueType())
3805 return SDValue();
3806
3807 EVT FromVT = LHS->getOperand(0).getValueType();
3808 EVT EltTy = FromVT.getVectorElementType();
3809 if (EltTy != MVT::i8)
3810 return SDValue();
3811
3812 // For an input DAG that looks like this
3813 // %a = input_type
3814 // %b = input_type
3815 // %lhs = extend %a to output_type
3816 // %rhs = extend %b to output_type
3817 // %mul = mul %lhs, %rhs
3818
3819 // input_type | output_type | instructions
3820 // v16i8 | v16i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3821 // | | %high = i16x8.extmul_high_i8x16_, %a, %b
3822 // | | %low_low = i32x4.ext_low_i16x8_ %low
3823 // | | %low_high = i32x4.ext_high_i16x8_ %low
3824 // | | %high_low = i32x4.ext_low_i16x8_ %high
3825 // | | %high_high = i32x4.ext_high_i16x8_ %high
3826 // | | %res = concat_vector(...)
3827 // v8i8 | v8i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3828 // | | %low_low = i32x4.ext_low_i16x8_ %low
3829 // | | %low_high = i32x4.ext_high_i16x8_ %low
3830 // | | %res = concat_vector(%low_low, %low_high)
3831 // v4i8 | v4i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3832 // | %res = i32x4.ext_low_i16x8_ %low
3833
3834 SDLoc DL(N);
3835 unsigned NumElts = VT.getVectorNumElements();
3836 SDValue ExtendInLHS = LHS->getOperand(0);
3837 SDValue ExtendInRHS = RHS->getOperand(0);
3838 bool IsSigned = LHS->getOpcode() == ISD::SIGN_EXTEND;
3839 unsigned ExtendLowOpc =
3840 IsSigned ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3841 unsigned ExtendHighOpc =
3842 IsSigned ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
3843
3844 auto GetExtendLow = [&DAG, &DL, &ExtendLowOpc](EVT VT, SDValue Op) {
3845 return DAG.getNode(ExtendLowOpc, DL, VT, Op);
3846 };
3847 auto GetExtendHigh = [&DAG, &DL, &ExtendHighOpc](EVT VT, SDValue Op) {
3848 return DAG.getNode(ExtendHighOpc, DL, VT, Op);
3849 };
3850
3851 if (NumElts == 16) {
3852 SDValue LowLHS = GetExtendLow(MVT::v8i16, ExtendInLHS);
3853 SDValue LowRHS = GetExtendLow(MVT::v8i16, ExtendInRHS);
3854 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3855 SDValue HighLHS = GetExtendHigh(MVT::v8i16, ExtendInLHS);
3856 SDValue HighRHS = GetExtendHigh(MVT::v8i16, ExtendInRHS);
3857 SDValue MulHigh = DAG.getNode(ISD::MUL, DL, MVT::v8i16, HighLHS, HighRHS);
3858 SDValue SubVectors[] = {
3859 GetExtendLow(MVT::v4i32, MulLow),
3860 GetExtendHigh(MVT::v4i32, MulLow),
3861 GetExtendLow(MVT::v4i32, MulHigh),
3862 GetExtendHigh(MVT::v4i32, MulHigh),
3863 };
3864 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, SubVectors);
3865 } else if (NumElts == 8) {
3866 SDValue LowLHS = DAG.getNode(LHS->getOpcode(), DL, MVT::v8i16, ExtendInLHS);
3867 SDValue LowRHS = DAG.getNode(RHS->getOpcode(), DL, MVT::v8i16, ExtendInRHS);
3868 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3869 SDValue Lo = GetExtendLow(MVT::v4i32, MulLow);
3870 SDValue Hi = GetExtendHigh(MVT::v4i32, MulLow);
3871 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
3872 } else {
3873 assert(NumElts == 4);
3874 SDValue LowLHS =
3875 GetExtendLow(MVT::v8i16, DoubleVectorWidth(ExtendInLHS, 16, DAG));
3876 SDValue LowRHS =
3877 GetExtendLow(MVT::v8i16, DoubleVectorWidth(ExtendInRHS, 16, DAG));
3878 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3879 return GetExtendLow(MVT::v4i32, MulLow);
3880 }
3881 return SDValue();
3882}
3883
3886 assert(N->getOpcode() == ISD::MUL);
3887 EVT VT = N->getValueType(0);
3888 if (!VT.isVector())
3889 return SDValue();
3890
3891 if (auto Res = TryWideExtMulCombine(N, DCI.DAG))
3892 return Res;
3893
3894 // We don't natively support v16i8 or v8i8 mul, but we do support v8i16. So,
3895 // extend them to v8i16.
3896 if (VT != MVT::v8i8 && VT != MVT::v16i8)
3897 return SDValue();
3898
3899 SDLoc DL(N);
3900 SelectionDAG &DAG = DCI.DAG;
3901 SDValue LHS = N->getOperand(0);
3902 SDValue RHS = N->getOperand(1);
3903 EVT MulVT = MVT::v8i16;
3904
3905 if (VT == MVT::v8i8) {
3906 SDValue PromotedLHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, LHS,
3907 DAG.getUNDEF(MVT::v8i8));
3908 SDValue PromotedRHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, RHS,
3909 DAG.getUNDEF(MVT::v8i8));
3910 SDValue LowLHS =
3911 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedLHS);
3912 SDValue LowRHS =
3913 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedRHS);
3914 SDValue MulLow = DAG.getBitcast(
3915 MVT::v16i8, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3916 // Take the low byte of each lane.
3917 SDValue Shuffle = DAG.getVectorShuffle(
3918 MVT::v16i8, DL, MulLow, DAG.getUNDEF(MVT::v16i8),
3919 {0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1});
3920 return extractSubVector(Shuffle, 0, DAG, DL, 64);
3921 } else {
3922 assert(VT == MVT::v16i8 && "Expected v16i8");
3923 SDValue LowLHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, LHS);
3924 SDValue LowRHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, RHS);
3925 SDValue HighLHS =
3926 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, LHS);
3927 SDValue HighRHS =
3928 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, RHS);
3929
3930 SDValue MulLow =
3931 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3932 SDValue MulHigh =
3933 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, HighLHS, HighRHS));
3934
3935 // Take the low byte of each lane.
3936 return DAG.getVectorShuffle(
3937 VT, DL, MulLow, MulHigh,
3938 {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30});
3939 }
3940}
3941
3943 EVT OutVT = N->getValueType(0);
3944 if (!OutVT.isVector())
3945 return SDValue();
3946
3947 EVT OutElTy = OutVT.getVectorElementType();
3948 if (OutElTy != MVT::i8 && OutElTy != MVT::i16)
3949 return SDValue();
3950
3951 unsigned NumElems = OutVT.getVectorNumElements();
3952 if (!isPowerOf2_32(NumElems))
3953 return SDValue();
3954
3955 EVT FPVT = N->getOperand(0)->getValueType(0);
3956 if (FPVT.getVectorElementType() != MVT::f32)
3957 return SDValue();
3958
3959 SDLoc DL(N);
3960
3961 // First, convert to i32.
3962 LLVMContext &Ctx = *DAG.getContext();
3963 EVT IntVT = EVT::getVectorVT(Ctx, MVT::i32, NumElems);
3964 SDValue ToInt = DAG.getNode(N->getOpcode(), DL, IntVT, N->getOperand(0));
3966 OutVT.getScalarSizeInBits());
3967 // Mask out the top MSBs.
3968 SDValue Masked =
3969 DAG.getNode(ISD::AND, DL, IntVT, ToInt, DAG.getConstant(Mask, DL, IntVT));
3970
3971 if (OutVT.getSizeInBits() < 128) {
3972 // Create a wide enough vector that we can use narrow.
3973 EVT NarrowedVT = OutElTy == MVT::i8 ? MVT::v16i8 : MVT::v8i16;
3974 unsigned NumRequiredElems = NarrowedVT.getVectorNumElements();
3975 SDValue WideVector = DoubleVectorWidth(Masked, NumRequiredElems, DAG);
3976 SDValue Trunc = truncateVectorWithNARROW(NarrowedVT, WideVector, DL, DAG);
3977 return DAG.getBitcast(
3978 OutVT, extractSubVector(Trunc, 0, DAG, DL, OutVT.getSizeInBits()));
3979 } else {
3980 return truncateVectorWithNARROW(OutVT, Masked, DL, DAG);
3981 }
3982 return SDValue();
3983}
3984
3985// Wide vector shift operations such as v8i32 with sign-extended
3986// operands cause Type Legalizer crashes because the target-specific
3987// extension nodes cannot be directly mapped to the 256-bit size.
3988//
3989// To resolve the crash and optimize performance, we intercept the
3990// illegal v8i32 shift in DAGCombine. We convert the shift amounts
3991// into multipliers and manually split the vector into two v4i32 halves.
3992//
3993// Before: t1: v8i32 = shl (sign_extend v8i16), const_vec
3994// After : t2: v4i32 = mul (ext_low_s v8i16), (ext_low_s narrow_vec)
3995// t3: v4i32 = mul (ext_high_s v8i16), (ext_high_s narrow_vec)
3996// t4: v8i32 = concat_vectors t2, t3
3999 SelectionDAG &DAG = DCI.DAG;
4000 assert(N->getOpcode() == ISD::SHL);
4001 EVT VT = N->getValueType(0);
4002 if (VT != MVT::v8i32)
4003 return SDValue();
4004
4005 SDValue LHS = N->getOperand(0);
4006 SDValue RHS = N->getOperand(1);
4007 unsigned ExtOpc = LHS.getOpcode();
4008 if (ExtOpc != ISD::SIGN_EXTEND && ExtOpc != ISD::ZERO_EXTEND)
4009 return SDValue();
4010
4011 if (RHS.getOpcode() != ISD::BUILD_VECTOR)
4012 return SDValue();
4013
4014 SDLoc DL(N);
4015 SDValue ExtendIn = LHS.getOperand(0);
4016 EVT FromVT = ExtendIn.getValueType();
4017 if (FromVT != MVT::v8i16)
4018 return SDValue();
4019
4020 unsigned NumElts = VT.getVectorNumElements();
4021 unsigned BitWidth = FromVT.getScalarSizeInBits();
4022 bool IsSigned = (ExtOpc == ISD::SIGN_EXTEND);
4023 unsigned MaxValidShift = IsSigned ? (BitWidth - 1) : BitWidth;
4024 SmallVector<SDValue, 16> MulConsts;
4025 for (unsigned I = 0; I < NumElts; ++I) {
4026 auto *C = dyn_cast<ConstantSDNode>(RHS.getOperand(I));
4027 if (!C)
4028 return SDValue();
4029
4030 const APInt &ShiftAmt = C->getAPIntValue();
4031 if (ShiftAmt.uge(MaxValidShift))
4032 return SDValue();
4033
4034 APInt MulAmt = APInt::getOneBitSet(BitWidth, ShiftAmt.getZExtValue());
4035 MulConsts.push_back(DAG.getConstant(MulAmt, DL, FromVT.getScalarType(),
4036 /*isTarget=*/false, /*isOpaque=*/true));
4037 }
4038
4039 SDValue NarrowConst = DAG.getBuildVector(FromVT, DL, MulConsts);
4040 unsigned ExtLowOpc =
4041 IsSigned ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
4042 unsigned ExtHighOpc =
4043 IsSigned ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
4044
4045 EVT HalfVT = MVT::v4i32;
4046 SDValue LHSLo = DAG.getNode(ExtLowOpc, DL, HalfVT, ExtendIn);
4047 SDValue LHSHi = DAG.getNode(ExtHighOpc, DL, HalfVT, ExtendIn);
4048 SDValue RHSLo = DAG.getNode(ExtLowOpc, DL, HalfVT, NarrowConst);
4049 SDValue RHSHi = DAG.getNode(ExtHighOpc, DL, HalfVT, NarrowConst);
4050 SDValue MulLo = DAG.getNode(ISD::MUL, DL, HalfVT, LHSLo, RHSLo);
4051 SDValue MulHi = DAG.getNode(ISD::MUL, DL, HalfVT, LHSHi, RHSHi);
4052 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, MulLo, MulHi);
4053}
4054
4056 if (N->getValueType(0) != MVT::f128)
4057 return SDValue();
4058
4060 switch (N->getOpcode()) {
4061 // wasi-libc and emscripten do not currently define fminimuml and fmaximuml.
4062 case ISD::FMINIMUM:
4063 case ISD::FMAXIMUM:
4064 return TLI.expandFMINIMUM_FMAXIMUM(N, DAG);
4065
4066 // wasi-libc and emscripten do not currently define fminimum_numl and
4067 // fmaximum_numl.
4068 case ISD::FMINIMUMNUM:
4069 case ISD::FMAXIMUMNUM:
4070 return TLI.expandFMINIMUMNUM_FMAXIMUMNUM(N, DAG);
4071
4072 default:
4073 return SDValue();
4074 }
4075}
4076
4077SDValue
4078WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
4079 DAGCombinerInfo &DCI) const {
4080 switch (N->getOpcode()) {
4081 default:
4082 return SDValue();
4083 case ISD::BITCAST:
4084 return performBitcastCombine(N, DCI);
4085 case ISD::SETCC:
4086 return performSETCCCombine(N, DCI, Subtarget);
4088 return performVECTOR_SHUFFLECombine(N, DCI);
4089 case ISD::SIGN_EXTEND:
4090 case ISD::ZERO_EXTEND:
4091 return performVectorExtendCombine(N, DCI);
4092 case ISD::UINT_TO_FP:
4093 if (auto ExtCombine = performVectorExtendToFPCombine(N, DCI, Subtarget))
4094 return ExtCombine;
4095 return performVectorNonNegToFPCombine(N, DCI);
4096 case ISD::SINT_TO_FP:
4097 return performVectorExtendToFPCombine(N, DCI, Subtarget);
4100 case ISD::FP_ROUND:
4102 return performVectorTruncZeroCombine(N, DCI);
4103 case ISD::FP_TO_SINT:
4104 case ISD::FP_TO_UINT:
4105 return performConvertFPCombine(N, DCI.DAG);
4106 case ISD::TRUNCATE:
4107 return performTruncateCombine(N, DCI);
4109 if (SDValue V = performBitmaskCombine(N, DCI.DAG))
4110 return V;
4111 return performAnyAllCombine(N, DCI.DAG);
4112 }
4113 case ISD::MUL:
4114 return performMulCombine(N, DCI);
4115 case ISD::SHL:
4116 return performShiftCombine(N, DCI);
4117 case ISD::FMINIMUM:
4118 case ISD::FMAXIMUM:
4119 case ISD::FMINIMUMNUM:
4120 case ISD::FMAXIMUMNUM:
4121 return performMinMaxF128Combine(N, DCI.DAG);
4122 }
4123}
static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const AArch64Subtarget *Subtarget)
static SDValue performTruncateCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
return SDValue()
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
const AArch64Subtarget & Subtarget
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
Function Alias Analysis Results
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Hexagon Common GEP
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static SDValue performVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget, const RISCVTargetLowering &TLI)
static SDValue combineVectorSizedSetCCEquality(EVT VT, SDValue X, SDValue Y, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
Try to map an integer comparison with size > XLEN to vector instructions before type legalization spl...
int64_t C1
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
int64_t C0
MachineInstr *& Lo
Contains matchers for matching SelectionDAG nodes and values.
const char * Msg
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool callingConvSupported(CallingConv::ID CallConv)
static MachineBasicBlock * LowerFPToInt(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool IsUnsigned, bool Int64, bool Float64, unsigned LoweredOpcode)
static SDValue TryWideExtMulCombine(SDNode *N, SelectionDAG &DAG)
static MachineBasicBlock * LowerMemcpy(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool Int64)
static SDValue performVectorExtendToFPCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const WebAssemblySubtarget *Subtarget)
Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get split up into scalar instr...
static std::optional< unsigned > IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG)
static SDValue performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performVectorNonNegToFPCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG)
static SDValue performAnyAllCombine(SDNode *N, SelectionDAG &DAG)
static MachineBasicBlock * LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, const WebAssemblySubtarget *Subtarget, const TargetInstrInfo &TII)
static std::optional< MaskReduceInfo > classifyMaskReduction(SDNode *N)
static SDValue GetExtendHigh(SDValue Op, unsigned UserOpc, EVT VT, SelectionDAG &DAG)
SDValue performConvertFPCombine(SDNode *N, SelectionDAG &DAG)
static SDValue performBitmaskCombine(SDNode *N, SelectionDAG &DAG)
static SDValue performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static bool IsWebAssemblyGlobal(SDValue Op)
static SDValue combineSmallMaskReduction(SDNode *N, EVT FromVT, unsigned NumElts, const MaskReduceInfo &Info, SelectionDAG &DAG)
static MachineBasicBlock * LowerMemset(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool Int64)
static bool HasNoSignedZerosOrNaNs(SDValue Op, SelectionDAG &DAG)
SDValue DoubleVectorWidth(SDValue In, unsigned RequiredNumElems, SelectionDAG &DAG)
static SDValue performShiftCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue LowerConvertLow(SDValue Op, SelectionDAG &DAG)
static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG, const SDLoc &DL, unsigned VectorWidth)
static SDValue performBitcastCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue truncateVectorWithNARROW(EVT DstVT, SDValue In, const SDLoc &DL, SelectionDAG &DAG)
static SDValue performMinMaxF128Combine(SDNode *N, SelectionDAG &DAG)
static SDValue combineWideMaskReduction(SDNode *N, SDValue Mask, EVT MaskVT, unsigned NumElts, const MaskReduceInfo &Info, SelectionDAG &DAG)
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 WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
X86 cmov Conversion
static constexpr int Concat[]
Value * RHS
Value * LHS
The Input class is used to parse a yaml document into in-memory structs and vectors.
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition APInt.h:292
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:235
bool uge(const APInt &RHS) const
Unsigned greater or equal comparison.
Definition APInt.h:1225
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
an instruction that atomically reads a memory location, combines it with another value,...
@ Add
*p = old + v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
BinOp getOperation() const
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
A debug info location.
Definition DebugLoc.h:126
Diagnostic information for unsupported feature in backend.
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:306
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
Definition FastISel.h:67
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
LLVM_ABI unsigned getAddressSpace() const
const GlobalValue * getGlobal() const
ThreadLocalMode getThreadLocalMode() const
Type * getValueType() const
unsigned getTargetFlags() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
Tracks which library functions to use for a particular subtarget or function.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
Describe properties that are true of each instruction in the target description file.
Machine Value Type.
bool is128BitVector() const
Return true if this is a 128-bit vector type.
@ INVALID_SIMPLE_VALUE_TYPE
static auto integer_fixedlen_vector_valuetypes()
SimpleValueType SimpleTy
MVT changeVectorElementType(MVT EltVT) const
Return a VT for a vector type whose attributes match ourselves with the exception of the element type...
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
static auto integer_valuetypes()
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool isFixedLengthVector() const
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
unsigned getFunctionNumber() const
getFunctionNumber - Return a unique ID for the current function.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
const char * createExternalSymbolName(StringRef Name)
Allocate a string and populate it with the given external symbol name.
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFPImm(const ConstantFP *Val) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
mop_range defs()
Returns all explicit operands that are register definitions.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
mop_range explicit_uses()
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const std::vector< MachineJumpTableEntry > & getJumpTables() const
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void addLiveIn(MCRegister Reg, Register vreg=Register())
addLiveIn - Add the specified register as a live-in.
unsigned getAddressSpace() const
Return the address space for the associated pointer.
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
static PointerType * getUnqual(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
ArrayRef< SDUse > ops() const
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
const SDValue & getOperand(unsigned Num) const
uint64_t getConstantOperandVal(unsigned Num) const
Helper method returns the integer value of a ConstantSDNode operand.
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
MVT getSimpleValueType() const
Return the simple ValueType of the referenced return value.
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI bool isKnownNeverLogicalZero(SDValue Op, const APInt &DemandedElts, unsigned Depth=0) const
Test whether the given floating point SDValue (or all elements of it, if it is a vector) is known to ...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getSplatValue(SDValue V, bool LegalTypes=false)
If V is a splat vector, return its scalar source operand by extracting that element from the source v...
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI void ExtractVectorElements(SDValue Op, SmallVectorImpl< SDValue > &Args, unsigned Start=0, unsigned Count=0, EVT EltVT=EVT())
Append the extracted elements from Start to Count out of the vector Op in Args.
LLVM_ABI SDValue UnrollVectorOp(SDNode *N, unsigned ResNE=0)
Utility function used by legalize and lowering to "unroll" a vector operation by splitting out the sc...
LLVM_ABI SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget=false)
Create a ConstantFPSDNode wrapping a constant value.
LLVM_ABI SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align DstAlign, Align SrcAlign, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
const TargetLowering & getTargetLoweringInfo() const
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
const DataLayout & getDataLayout() const
SDValue getTargetFrameIndex(int FI, EVT VT)
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
LLVM_ABI SDValue getBasicBlock(MachineBasicBlock *MBB)
LLVM_ABI SDValue getSExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either sign-extending or trunca...
const TargetMachine & getTarget() const
LLVM_ABI SDValue getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either any-extending or truncat...
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
LLVM_ABI bool isKnownNeverNaN(SDValue Op, const APInt &DemandedElts, bool SNaN=false, unsigned Depth=0) const
Test whether the given SDValue (or all elements of it, if it is a vector) is known to never be NaN in...
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI SDValue getVectorIdxConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
MachineFunction & getMachineFunction() const
SDValue getPOISON(EVT VT)
Return a POISON node. POISON does not have a useful SDLoc.
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
LLVM_ABI SDValue getMCSymbol(MCSymbol *Sym, EVT VT)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
const SDValue & getValue() const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
TargetInstrInfo - Interface to description of machine instruction set.
Provides information about what library functions are available for the current target.
void setBooleanVectorContents(BooleanContent Ty)
Specify how the target extends the result of a vector boolean value from a vector of i1 to a wider ty...
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
const TargetMachine & getTargetMachine() const
unsigned MaxLoadsPerMemcmp
Specify maximum number of load instructions per memcmp call.
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
virtual TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const
Return the preferred vector type legalization action.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setMinimumJumpTableEntries(unsigned Val)
Indicate the minimum number of blocks to generate jump tables.
void setPartialReduceMLAAction(unsigned Opc, MVT AccVT, MVT InputVT, LegalizeAction Action)
Indicate how a PARTIAL_REDUCE_U/SMLA node with Acc type AccVT and Input type InputVT should be treate...
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
unsigned MaxLoadsPerMemcmpOptSize
Likewise for functions with the OptSize attribute.
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
void setSchedulingPreference(Sched::Preference Pref)
Specify the target scheduling preference.
bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
bool isPositionIndependent() const
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
TargetLowering(const TargetLowering &)=delete
virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const
Return true if folding a constant offset with the given GlobalAddress is legal.
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::LibcallImpl LibcallImpl, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
Primary interface to the complete machine description for the target machine.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isFunctionTy() const
True if this is an instance of FunctionType.
Definition Type.h:268
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:277
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM_ABI const Value * stripPointerCastsAndAliases() const
Strip off pointer casts, all-zero GEPs, address space casts, and aliases.
Definition Value.cpp:712
static std::optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)
WebAssemblyTargetLowering(const TargetMachine &TM, const WebAssemblySubtarget &STI)
self_iterator getIterator()
Definition ilist_node.h:123
#define INT64_MIN
Definition DataTypes.h:74
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Swift
Calling convention for Swift.
Definition CallingConv.h:69
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ CXX_FAST_TLS
Used for access functions.
Definition CallingConv.h:72
@ WASM_EmscriptenInvoke
For emscripten __invoke_* functions.
@ Cold
Attempts to make code in the caller as efficient as possible under the assumption that the call is no...
Definition CallingConv.h:47
@ PreserveAll
Used for runtime calls that preserves (almost) all registers.
Definition CallingConv.h:66
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ SwiftTail
This follows the Swift calling convention in how arguments are passed but guarantees tail calls will ...
Definition CallingConv.h:87
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:845
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
@ PARTIAL_REDUCE_SMLA
PARTIAL_REDUCE_[U|S]MLA(Accumulator, Input1, Input2) The partial reduction nodes sign or zero extend ...
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:277
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:805
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:296
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:523
@ PSEUDO_FMIN
PSEUDO_FMIN is strictly equivalent to op0 olt op1 ?
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ GlobalAddress
Definition ISDOpcodes.h:90
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:906
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:589
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:765
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition ISDOpcodes.h:936
@ SDIVREM
SDIVREM/UDIVREM - Divide two integers and produce both a quotient and remainder result.
Definition ISDOpcodes.h:282
@ FP16_TO_FP
FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions and truncation for half-preci...
@ FMULADD
FMULADD - Performs a * b + c, with, or without, intermediate rounding.
Definition ISDOpcodes.h:533
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:256
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:91
@ PARTIAL_REDUCE_UMLA
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:870
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:675
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
@ BR_CC
BR_CC - Conditional branch.
@ BRIND
BRIND - Indirect branch.
@ BR_JT
BR_JT - Jumptable branch.
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:377
@ EXTRACT_ELEMENT
EXTRACT_ELEMENT - This is used to get the lower or upper (determined by a Constant,...
Definition ISDOpcodes.h:249
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition ISDOpcodes.h:682
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:714
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:787
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:659
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:619
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:581
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:226
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:876
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition ISDOpcodes.h:837
@ FMINNUM
FMINNUM/FMAXNUM - Same semantics as the llvm.minnum/maxnum intrinsics.
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
@ ANY_EXTEND_VECTOR_INREG
ANY_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register any-extension of the low la...
Definition ISDOpcodes.h:925
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:914
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:745
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:112
@ FMINIMUM
FMINIMUM/FMAXIMUM - Same semantics as the llvm.minimum/maximum intrinsics.
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:952
@ TargetConstant
TargetConstant* - Like Constant*, but the DAG does not do any folding, simplification,...
Definition ISDOpcodes.h:181
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:757
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:306
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:570
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:55
@ ExternalSymbol
Definition ISDOpcodes.h:95
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:985
@ CLEAR_CACHE
llvm.clear_cache intrinsic Operands: Input Chain, Start Addres, End Address Outputs: Output Chain
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:947
@ FP_TO_SINT_SAT
FP_TO_[US]INT_SAT - Convert floating point value in operand 0 to a signed or unsigned scalar integer ...
Definition ISDOpcodes.h:971
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:882
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition ISDOpcodes.h:859
@ FCOPYSIGN
FCOPYSIGN(X, Y) - Return the value of X with the sign of Y.
Definition ISDOpcodes.h:539
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:368
@ FMINIMUMNUM
FMINIMUMNUM/FMAXIMUMNUM - Same semantics as the llvm.minimumnum/maximumnum intrinsics.
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
LLVM_ABI bool isConstantSplatVector(const SDNode *N, APInt &SplatValue)
Node predicates.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
OperandFlags
These are flags set on operands, but should be considered private, all access should go through the M...
Definition MCInstrDesc.h:51
auto m_Value()
Match an arbitrary value and ignore it.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
TernaryOpc_match< T0_P, T1_P, CondCode_match, true, false > m_c_SetCC(const T0_P &LHS, const T1_P &RHS)
Match a SETCC with any condition code, allowing the operands to be commuted.
TernaryOpc_match< T0_P, T1_P, CondCode_match, true, false > m_c_SpecificSetCC(ISD::CondCode CC, const T0_P &LHS, const T1_P &RHS)
Match a SETCC with a specific condition code, allowing the operands to be commuted.
bool sd_match(SDValue N, Pattern &&P)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
void moveToFront(RangeT &Range, size_t Idx)
Moves the element at Idx of Range to the front, keeping the order of the other elements.
bool isWebAssemblyTableType(const Type *Ty)
Return true if the table represents a WebAssembly table type.
MCSymbolWasm * getOrCreateFuncrefCallTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __funcref_call_table, for use in funcref calls when lowered to table.set + call_indirect.
bool isValidAddressSpace(unsigned AS)
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo, const LibcallLoweringInfo *libcallLowering)
bool canLowerReturn(size_t ResultSize, const WebAssemblySubtarget *Subtarget)
Returns true if the function's return value(s) can be lowered directly, i.e., not indirectly via a po...
MachineSDNode * getTLSBase(SelectionDAG &DAG, const SDLoc &DL, const WebAssemblySubtarget *Subtarget, const SDValue Chain=SDValue())
bool isWasmVarAddressSpace(unsigned AS)
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition MathExtras.h:339
@ Offset
Definition DWP.cpp:577
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
SDValue peekThroughFreeze(SDValue V)
Return the non-frozen source operand of V if it exists.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Known
Known to have no common set bits.
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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
@ Add
Sum of integers.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2104
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition STLExtras.h:2208
void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, LLVMContext &Ctx, const DataLayout &DL, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
Extended Value Type.
Definition ValueTypes.h:35
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition ValueTypes.h:90
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:160
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:170
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:411
bool isByteSized() const
Return true if the bit size is a multiple of 8.
Definition ValueTypes.h:281
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:423
EVT changeVectorElementType(LLVMContext &Context, EVT EltVT) const
Return a VT for a vector type whose attributes match ourselves with the exception of the element type...
Definition ValueTypes.h:98
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:354
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:245
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:419
EVT widenIntegerVectorElementType(LLVMContext &Context) const
Return a VT for an integer vector type with the size of the elements doubled.
Definition ValueTypes.h:490
bool isFixedLengthVector() const
Definition ValueTypes.h:214
bool isFixedLengthVectorOf(EVT EltVT) const
Return true if this is a fixed length vector with matching element type.
Definition ValueTypes.h:220
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:191
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:361
bool bitsGE(EVT VT) const
Return true if this has no less bits than VT.
Definition ValueTypes.h:330
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:250
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:366
EVT changeElementType(LLVMContext &Context, EVT EltVT) const
Return a VT for a type whose attributes match ourselves with the exception of the element type that i...
Definition ValueTypes.h:136
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:180
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:374
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:499
Matching combinators.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
These are IR-level optimization flags that may be propagated to SDNodes.
This structure is used to pass arguments to makeLibCall function.