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.
135 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
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 *
788 const WebAssemblySubtarget *Subtarget,
789 const TargetInstrInfo &TII) {
790 MachineInstr &CallParams = *CallResults.getPrevNode();
791 assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
792 assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
793 CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
794
795 bool IsIndirect =
796 CallParams.getOperand(0).isReg() || CallParams.getOperand(0).isFI();
797 bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
798
799 bool IsFuncrefCall = false;
800 if (IsIndirect && CallParams.getOperand(0).isReg()) {
801 Register Reg = CallParams.getOperand(0).getReg();
802 const MachineFunction *MF = BB->getParent();
803 const MachineRegisterInfo &MRI = MF->getRegInfo();
804 const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
805 IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
806 assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
807 }
808
809 unsigned CallOp;
810 if (IsIndirect && IsRetCall) {
811 CallOp = WebAssembly::RET_CALL_INDIRECT;
812 } else if (IsIndirect) {
813 CallOp = WebAssembly::CALL_INDIRECT;
814 } else if (IsRetCall) {
815 CallOp = WebAssembly::RET_CALL;
816 } else {
817 CallOp = WebAssembly::CALL;
818 }
819
820 MachineFunction &MF = *BB->getParent();
821 const MCInstrDesc &MCID = TII.get(CallOp);
822 MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
823
824 // Move the function pointer to the end of the arguments for indirect calls
825 if (IsIndirect) {
826 auto FnPtr = CallParams.getOperand(0);
827 CallParams.removeOperand(0);
828
829 // For funcrefs, call_indirect is done through __funcref_call_table and the
830 // funcref is always installed in slot 0 of the table, therefore instead of
831 // having the function pointer added at the end of the params list, a zero
832 // (the index in
833 // __funcref_call_table is added).
834 if (IsFuncrefCall) {
835 Register RegZero =
836 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
837 MachineInstrBuilder MIBC0 =
838 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
839
840 BB->insert(CallResults.getIterator(), MIBC0);
841 MachineInstrBuilder(MF, CallParams).addReg(RegZero);
842 } else
843 CallParams.addOperand(FnPtr);
844 }
845
846 for (auto Def : CallResults.defs())
847 MIB.add(Def);
848
849 if (IsIndirect) {
850 // Placeholder for the type index.
851 // This gets replaced with the correct value in WebAssemblyMCInstLower.cpp
852 MIB.addImm(0);
853 // The table into which this call_indirect indexes.
854 MCSymbolWasm *Table = IsFuncrefCall
856 MF.getContext(), Subtarget)
858 MF.getContext(), Subtarget);
859 if (Subtarget->hasCallIndirectOverlong()) {
860 MIB.addSym(Table);
861 } else {
862 // For the MVP there is at most one table whose number is 0, but we can't
863 // write a table symbol or issue relocations. Instead we just ensure the
864 // table is live and write a zero.
865 Table->setNoStrip();
866 MIB.addImm(0);
867 }
868 }
869
870 for (auto Use : CallParams.uses())
871 MIB.add(Use);
872
873 BB->insert(CallResults.getIterator(), MIB);
874 CallParams.eraseFromParent();
875 CallResults.eraseFromParent();
876
877 // If this is a funcref call, to avoid hidden GC roots, we need to clear the
878 // table slot with ref.null upon call_indirect return.
879 //
880 // This generates the following code, which comes right after a call_indirect
881 // of a funcref:
882 //
883 // i32.const 0
884 // ref.null func
885 // table.set __funcref_call_table
886 if (IsIndirect && IsFuncrefCall) {
888 MF.getContext(), Subtarget);
889 Register RegZero =
890 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
891 MachineInstr *Const0 =
892 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
893 BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
894
895 Register RegFuncref =
896 MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
897 MachineInstr *RefNull =
898 BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref);
899 BB->insertAfter(Const0->getIterator(), RefNull);
900
901 MachineInstr *TableSet =
902 BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
903 .addSym(Table)
904 .addReg(RegZero)
905 .addReg(RegFuncref);
906 BB->insertAfter(RefNull->getIterator(), TableSet);
907 }
908
909 return BB;
910}
911
912MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
913 MachineInstr &MI, MachineBasicBlock *BB) const {
914 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
915 DebugLoc DL = MI.getDebugLoc();
916
917 switch (MI.getOpcode()) {
918 default:
919 llvm_unreachable("Unexpected instr type to insert");
920 case WebAssembly::FP_TO_SINT_I32_F32:
921 return LowerFPToInt(MI, DL, BB, TII, false, false, false,
922 WebAssembly::I32_TRUNC_S_F32);
923 case WebAssembly::FP_TO_UINT_I32_F32:
924 return LowerFPToInt(MI, DL, BB, TII, true, false, false,
925 WebAssembly::I32_TRUNC_U_F32);
926 case WebAssembly::FP_TO_SINT_I64_F32:
927 return LowerFPToInt(MI, DL, BB, TII, false, true, false,
928 WebAssembly::I64_TRUNC_S_F32);
929 case WebAssembly::FP_TO_UINT_I64_F32:
930 return LowerFPToInt(MI, DL, BB, TII, true, true, false,
931 WebAssembly::I64_TRUNC_U_F32);
932 case WebAssembly::FP_TO_SINT_I32_F64:
933 return LowerFPToInt(MI, DL, BB, TII, false, false, true,
934 WebAssembly::I32_TRUNC_S_F64);
935 case WebAssembly::FP_TO_UINT_I32_F64:
936 return LowerFPToInt(MI, DL, BB, TII, true, false, true,
937 WebAssembly::I32_TRUNC_U_F64);
938 case WebAssembly::FP_TO_SINT_I64_F64:
939 return LowerFPToInt(MI, DL, BB, TII, false, true, true,
940 WebAssembly::I64_TRUNC_S_F64);
941 case WebAssembly::FP_TO_UINT_I64_F64:
942 return LowerFPToInt(MI, DL, BB, TII, true, true, true,
943 WebAssembly::I64_TRUNC_U_F64);
944 case WebAssembly::MEMCPY_A32:
945 return LowerMemcpy(MI, DL, BB, TII, false);
946 case WebAssembly::MEMCPY_A64:
947 return LowerMemcpy(MI, DL, BB, TII, true);
948 case WebAssembly::MEMSET_A32:
949 return LowerMemset(MI, DL, BB, TII, false);
950 case WebAssembly::MEMSET_A64:
951 return LowerMemset(MI, DL, BB, TII, true);
952 case WebAssembly::CALL_RESULTS:
953 case WebAssembly::RET_CALL_RESULTS:
954 return LowerCallResults(MI, DL, BB, Subtarget, TII);
955 }
956}
957
958std::pair<unsigned, const TargetRegisterClass *>
959WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
960 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
961 // First, see if this is a constraint that directly corresponds to a
962 // WebAssembly register class.
963 if (Constraint.size() == 1) {
964 switch (Constraint[0]) {
965 case 'r':
966 assert(VT != MVT::iPTR && "Pointer MVT not expected here");
967 if (Subtarget->hasSIMD128() && VT.isVector()) {
968 if (VT.getSizeInBits() == 128)
969 return std::make_pair(0U, &WebAssembly::V128RegClass);
970 }
971 if (VT.isInteger() && !VT.isVector()) {
972 if (VT.getSizeInBits() <= 32)
973 return std::make_pair(0U, &WebAssembly::I32RegClass);
974 if (VT.getSizeInBits() <= 64)
975 return std::make_pair(0U, &WebAssembly::I64RegClass);
976 }
977 if (VT.isFloatingPoint() && !VT.isVector()) {
978 switch (VT.getSizeInBits()) {
979 case 32:
980 return std::make_pair(0U, &WebAssembly::F32RegClass);
981 case 64:
982 return std::make_pair(0U, &WebAssembly::F64RegClass);
983 default:
984 break;
985 }
986 }
987 break;
988 default:
989 break;
990 }
991 }
992
994}
995
996bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const {
997 // Assume ctz is a relatively cheap operation.
998 return true;
999}
1000
1001bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
1002 // Assume clz is a relatively cheap operation.
1003 return true;
1004}
1005
1006bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
1007 const AddrMode &AM,
1008 Type *Ty, unsigned AS,
1009 Instruction *I) const {
1010 // WebAssembly offsets are added as unsigned without wrapping. The
1011 // isLegalAddressingMode gives us no way to determine if wrapping could be
1012 // happening, so we approximate this by accepting only non-negative offsets.
1013 if (AM.BaseOffs < 0)
1014 return false;
1015
1016 // WebAssembly has no scale register operands.
1017 if (AM.Scale != 0)
1018 return false;
1019
1020 // Everything else is legal.
1021 return true;
1022}
1023
1024bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
1025 EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/,
1026 MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const {
1027 // WebAssembly supports unaligned accesses, though it should be declared
1028 // with the p2align attribute on loads and stores which do so, and there
1029 // may be a performance impact. We tell LLVM they're "fast" because
1030 // for the kinds of things that LLVM uses this for (merging adjacent stores
1031 // of constants, etc.), WebAssembly implementations will either want the
1032 // unaligned access or they'll split anyway.
1033 if (Fast)
1034 *Fast = 1;
1035 return true;
1036}
1037
1038bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
1039 AttributeList Attr) const {
1040 // The current thinking is that wasm engines will perform this optimization,
1041 // so we can save on code size.
1042 return true;
1043}
1044
1045bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
1046 EVT ExtT = ExtVal.getValueType();
1047 SDValue N0 = peekThroughFreeze(ExtVal->getOperand(0));
1048 auto *Load = dyn_cast<LoadSDNode>(N0);
1049 if (!Load)
1050 return false;
1051 EVT MemT = Load->getValueType(0);
1052 return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
1053 (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
1054 (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
1055}
1056
1057bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
1058 const GlobalAddressSDNode *GA) const {
1059 // Wasm doesn't support function addresses with offsets
1060 const GlobalValue *GV = GA->getGlobal();
1062}
1063
1064EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
1065 LLVMContext &C,
1066 EVT VT) const {
1067 if (VT.isVector()) {
1068 if (VT.getVectorElementType() == MVT::f16 && !Subtarget->hasFP16())
1069 return VT.changeElementType(C, MVT::i1);
1070
1072 }
1073
1074 // So far, all branch instructions in Wasm take an I32 condition.
1075 // The default TargetLowering::getSetCCResultType returns the pointer size,
1076 // which would be useful to reduce instruction counts when testing
1077 // against 64-bit pointers/values if at some point Wasm supports that.
1078 return EVT::getIntegerVT(C, 32);
1079}
1080
1081void WebAssemblyTargetLowering::getTgtMemIntrinsic(
1083 MachineFunction &MF, unsigned Intrinsic) const {
1085 switch (Intrinsic) {
1086 case Intrinsic::wasm_memory_atomic_notify:
1088 Info.memVT = MVT::i32;
1089 Info.ptrVal = I.getArgOperand(0);
1090 Info.offset = 0;
1091 Info.align = Align(4);
1092 // atomic.notify instruction does not really load the memory specified with
1093 // this argument, but MachineMemOperand should either be load or store, so
1094 // we set this to a load.
1095 // FIXME Volatile isn't really correct, but currently all LLVM atomic
1096 // instructions are treated as volatiles in the backend, so we should be
1097 // consistent. The same applies for wasm_atomic_wait intrinsics too.
1099 Infos.push_back(Info);
1100 return;
1101 case Intrinsic::wasm_memory_atomic_wait32:
1103 Info.memVT = MVT::i32;
1104 Info.ptrVal = I.getArgOperand(0);
1105 Info.offset = 0;
1106 Info.align = Align(4);
1108 Infos.push_back(Info);
1109 return;
1110 case Intrinsic::wasm_memory_atomic_wait64:
1112 Info.memVT = MVT::i64;
1113 Info.ptrVal = I.getArgOperand(0);
1114 Info.offset = 0;
1115 Info.align = Align(8);
1117 Infos.push_back(Info);
1118 return;
1119 case Intrinsic::wasm_loadf16_f32:
1121 Info.memVT = MVT::f16;
1122 Info.ptrVal = I.getArgOperand(0);
1123 Info.offset = 0;
1124 Info.align = Align(2);
1126 Infos.push_back(Info);
1127 return;
1128 case Intrinsic::wasm_storef16_f32:
1130 Info.memVT = MVT::f16;
1131 Info.ptrVal = I.getArgOperand(1);
1132 Info.offset = 0;
1133 Info.align = Align(2);
1135 Infos.push_back(Info);
1136 return;
1137 default:
1138 return;
1139 }
1140}
1141
1142void WebAssemblyTargetLowering::computeKnownBitsForTargetNode(
1143 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
1144 const SelectionDAG &DAG, unsigned Depth) const {
1145 switch (Op.getOpcode()) {
1146 default:
1147 break;
1149 unsigned IntNo = Op.getConstantOperandVal(0);
1150 switch (IntNo) {
1151 default:
1152 break;
1153 case Intrinsic::wasm_bitmask: {
1154 unsigned BitWidth = Known.getBitWidth();
1155 EVT VT = Op.getOperand(1).getSimpleValueType();
1156 unsigned PossibleBits = VT.getVectorNumElements();
1157 APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits);
1158 Known.Zero |= ZeroMask;
1159 break;
1160 }
1161 }
1162 break;
1163 }
1164 case WebAssemblyISD::EXTEND_LOW_U:
1165 case WebAssemblyISD::EXTEND_HIGH_U: {
1166 // We know the high half, of each destination vector element, will be zero.
1167 SDValue SrcOp = Op.getOperand(0);
1168 EVT VT = SrcOp.getSimpleValueType();
1169 unsigned BitWidth = Known.getBitWidth();
1170 if (VT == MVT::v8i8 || VT == MVT::v16i8) {
1171 assert(BitWidth >= 8 && "Unexpected width!");
1173 Known.Zero |= Mask;
1174 } else if (VT == MVT::v4i16 || VT == MVT::v8i16) {
1175 assert(BitWidth >= 16 && "Unexpected width!");
1177 Known.Zero |= Mask;
1178 } else if (VT == MVT::v2i32 || VT == MVT::v4i32) {
1179 assert(BitWidth >= 32 && "Unexpected width!");
1181 Known.Zero |= Mask;
1182 }
1183 break;
1184 }
1185 // For 128-bit addition if the upper bits are all zero then it's known that
1186 // the upper bits of the result will have all bits guaranteed zero except the
1187 // first.
1188 case WebAssemblyISD::I64_ADD128:
1189 if (Op.getResNo() == 1) {
1190 SDValue LHS_HI = Op.getOperand(1);
1191 SDValue RHS_HI = Op.getOperand(3);
1192 if (isNullConstant(LHS_HI) && isNullConstant(RHS_HI))
1193 Known.Zero.setBitsFrom(1);
1194 }
1195 break;
1196 }
1197}
1198
1200WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
1201 if (VT.isFixedLengthVector()) {
1202 MVT EltVT = VT.getVectorElementType();
1203 // We have legal vector types with these lane types, so widening the
1204 // vector would let us use some of the lanes directly without having to
1205 // extend or truncate values.
1206 if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
1207 EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64)
1208 return TypeWidenVector;
1209 }
1210
1212}
1213
1214bool WebAssemblyTargetLowering::isFMAFasterThanFMulAndFAdd(
1215 const MachineFunction &MF, EVT VT) const {
1216 if (!Subtarget->hasFP16() || !VT.isVector())
1217 return false;
1218
1219 EVT ScalarVT = VT.getScalarType();
1220 if (!ScalarVT.isSimple())
1221 return false;
1222
1223 return ScalarVT.getSimpleVT().SimpleTy == MVT::f16;
1224}
1225
1226bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
1227 SDValue Op, const TargetLoweringOpt &TLO) const {
1228 // ISel process runs DAGCombiner after legalization; this step is called
1229 // SelectionDAG optimization phase. This post-legalization combining process
1230 // runs DAGCombiner on each node, and if there was a change to be made,
1231 // re-runs legalization again on it and its user nodes to make sure
1232 // everythiing is in a legalized state.
1233 //
1234 // The legalization calls lowering routines, and we do our custom lowering for
1235 // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
1236 // into zeros. But there is a set of routines in DAGCombiner that turns unused
1237 // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
1238 // turns unused vector elements into undefs. But this routine does not work
1239 // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
1240 // combination can result in a infinite loop, in which undefs are converted to
1241 // zeros in legalization and back to undefs in combining.
1242 //
1243 // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
1244 // running for build_vectors.
1245 if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
1246 return false;
1247 return true;
1248}
1249
1250//===----------------------------------------------------------------------===//
1251// WebAssembly Lowering private implementation.
1252//===----------------------------------------------------------------------===//
1253
1254//===----------------------------------------------------------------------===//
1255// Lowering Code
1256//===----------------------------------------------------------------------===//
1257
1258static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
1260 DAG.getContext()->diagnose(
1261 DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
1262}
1263
1264// Test whether the given calling convention is supported.
1266 // We currently support the language-independent target-independent
1267 // conventions. We don't yet have a way to annotate calls with properties like
1268 // "cold", and we don't have any call-clobbered registers, so these are mostly
1269 // all handled the same.
1270 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
1271 CallConv == CallingConv::Cold ||
1272 CallConv == CallingConv::PreserveMost ||
1273 CallConv == CallingConv::PreserveAll ||
1274 CallConv == CallingConv::CXX_FAST_TLS ||
1276 CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail;
1277}
1278
1279SDValue
1280WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
1281 SmallVectorImpl<SDValue> &InVals) const {
1282 SelectionDAG &DAG = CLI.DAG;
1283 SDLoc DL = CLI.DL;
1284 SDValue Chain = CLI.Chain;
1285 SDValue Callee = CLI.Callee;
1287 auto Layout = MF.getDataLayout();
1288
1289 // A call through a funcref is expressed in IR as a call through the pointer
1290 // produced by the llvm.wasm.funcref.to_ptr intrinsic. Detect this here and
1291 // recover the underlying funcref value so the call can be lowered to a
1292 // table.set + call_indirect through the dedicated __funcref_call_table.
1293 bool IsFuncrefCall = false;
1294 if (Callee.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
1295 Callee.getConstantOperandVal(0) == Intrinsic::wasm_funcref_to_ptr) {
1296 Callee = Callee.getOperand(1);
1297 IsFuncrefCall = true;
1298 }
1299
1300 CallingConv::ID CallConv = CLI.CallConv;
1301 if (!callingConvSupported(CallConv))
1302 fail(DL, DAG,
1303 "WebAssembly doesn't support language-specific or target-specific "
1304 "calling conventions yet");
1305 if (CLI.IsPatchPoint)
1306 fail(DL, DAG, "WebAssembly doesn't support patch point yet");
1307
1308 if (CLI.IsTailCall) {
1309 auto NoTail = [&](const char *Msg) {
1310 if (CLI.CB && CLI.CB->isMustTailCall())
1311 fail(DL, DAG, Msg);
1312 CLI.IsTailCall = false;
1313 };
1314
1315 if (!Subtarget->hasTailCall())
1316 NoTail("WebAssembly 'tail-call' feature not enabled");
1317
1318 // Varargs calls cannot be tail calls because the buffer is on the stack
1319 if (CLI.IsVarArg)
1320 NoTail("WebAssembly does not support varargs tail calls");
1321
1322 // Do not tail call unless caller and callee return types match
1323 const Function &F = MF.getFunction();
1324 const TargetMachine &TM = getTargetMachine();
1325 Type *RetTy = F.getReturnType();
1326 SmallVector<MVT, 4> CallerRetTys;
1327 SmallVector<MVT, 4> CalleeRetTys;
1328 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1329 computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
1330 bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
1331 std::equal(CallerRetTys.begin(), CallerRetTys.end(),
1332 CalleeRetTys.begin());
1333 if (!TypesMatch)
1334 NoTail("WebAssembly tail call requires caller and callee return types to "
1335 "match");
1336
1337 // If pointers to local stack values are passed, we cannot tail call
1338 if (CLI.CB) {
1339 for (auto &Arg : CLI.CB->args()) {
1340 Value *Val = Arg.get();
1341 // Trace the value back through pointer operations
1342 while (true) {
1343 Value *Src = Val->stripPointerCastsAndAliases();
1344 if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
1345 Src = GEP->getPointerOperand();
1346 if (Val == Src)
1347 break;
1348 Val = Src;
1349 }
1350 if (isa<AllocaInst>(Val)) {
1351 NoTail(
1352 "WebAssembly does not support tail calling with stack arguments");
1353 break;
1354 }
1355 }
1356 }
1357 }
1358
1359 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
1360 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
1361 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
1362
1363 // The generic code may have added an sret argument. If we're lowering an
1364 // invoke function, the ABI requires that the function pointer be the first
1365 // argument, so we may have to swap the arguments.
1366 if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
1367 Outs[0].Flags.isSRet()) {
1368 std::swap(Outs[0], Outs[1]);
1369 std::swap(OutVals[0], OutVals[1]);
1370 }
1371
1372 bool HasSwiftSelfArg = false;
1373 bool HasSwiftErrorArg = false;
1374 bool HasSwiftAsyncArg = false;
1375 unsigned NumFixedArgs = 0;
1376 for (unsigned I = 0; I < Outs.size(); ++I) {
1377 const ISD::OutputArg &Out = Outs[I];
1378 SDValue &OutVal = OutVals[I];
1379 HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
1380 HasSwiftErrorArg |= Out.Flags.isSwiftError();
1381 HasSwiftAsyncArg |= Out.Flags.isSwiftAsync();
1382 if (Out.Flags.isNest())
1383 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1384 if (Out.Flags.isInAlloca())
1385 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1386 if (Out.Flags.isInConsecutiveRegs())
1387 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1388 if (Out.Flags.isInConsecutiveRegsLast())
1389 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1390 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
1391 auto &MFI = MF.getFrameInfo();
1392 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
1393 Out.Flags.getNonZeroByValAlign(),
1394 /*isSS=*/false);
1395 SDValue SizeNode =
1396 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
1397 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1398 Align Alignment = Out.Flags.getNonZeroByValAlign();
1399 Chain = DAG.getMemcpy(Chain, DL, FINode, OutVal, SizeNode, Alignment,
1400 Alignment,
1401 /*isVolatile*/ false, /*AlwaysInline=*/false,
1402 /*CI=*/nullptr, std::nullopt, MachinePointerInfo(),
1403 MachinePointerInfo());
1404 OutVal = FINode;
1405 }
1406 // Count the number of fixed args *after* legalization.
1407 NumFixedArgs += !Out.Flags.isVarArg();
1408 }
1409
1410 bool IsVarArg = CLI.IsVarArg;
1411 auto PtrVT = getPointerTy(Layout);
1412
1413 // For swiftcc and swifttailcc, emit additional swiftself, swifterror, and
1414 // (for swifttailcc) swiftasync arguments if there aren't. These additional
1415 // arguments are also added for callee signature. They are necessary to match
1416 // callee and caller signature for indirect call.
1417 if (CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail) {
1418 Type *PtrTy = PointerType::getUnqual(*DAG.getContext());
1419 if (!HasSwiftSelfArg) {
1420 NumFixedArgs++;
1421 ISD::ArgFlagsTy Flags;
1422 Flags.setSwiftSelf();
1423 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1424 CLI.Outs.push_back(Arg);
1425 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1426 CLI.OutVals.push_back(ArgVal);
1427 }
1428 if (!HasSwiftErrorArg) {
1429 NumFixedArgs++;
1430 ISD::ArgFlagsTy Flags;
1431 Flags.setSwiftError();
1432 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1433 CLI.Outs.push_back(Arg);
1434 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1435 CLI.OutVals.push_back(ArgVal);
1436 }
1437 if (CallConv == CallingConv::SwiftTail && !HasSwiftAsyncArg) {
1438 NumFixedArgs++;
1439 ISD::ArgFlagsTy Flags;
1440 Flags.setSwiftAsync();
1441 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1442 CLI.Outs.push_back(Arg);
1443 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1444 CLI.OutVals.push_back(ArgVal);
1445 }
1446 }
1447
1448 // Analyze operands of the call, assigning locations to each operand.
1450 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1451
1452 if (IsVarArg) {
1453 // Outgoing non-fixed arguments are placed in a buffer. First
1454 // compute their offsets and the total amount of buffer space needed.
1455 for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
1456 const ISD::OutputArg &Out = Outs[I];
1457 SDValue &Arg = OutVals[I];
1458 EVT VT = Arg.getValueType();
1459 assert(VT != MVT::iPTR && "Legalized args should be concrete");
1460 Type *Ty = VT.getTypeForEVT(*DAG.getContext());
1462 std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
1463 unsigned Offset =
1464 CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
1465 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
1466 Offset, VT.getSimpleVT(),
1468 }
1469 }
1470
1471 unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
1472
1473 SDValue FINode;
1474 if (IsVarArg && NumBytes) {
1475 // For non-fixed arguments, next emit stores to store the argument values
1476 // to the stack buffer at the offsets computed above.
1477 MaybeAlign StackAlign = Layout.getStackAlignment();
1478 assert(StackAlign && "data layout string is missing stack alignment");
1479 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, *StackAlign,
1480 /*isSS=*/false);
1481 unsigned ValNo = 0;
1483 for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) {
1484 assert(ArgLocs[ValNo].getValNo() == ValNo &&
1485 "ArgLocs should remain in order and only hold varargs args");
1486 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
1487 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1488 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
1489 DAG.getConstant(Offset, DL, PtrVT));
1490 Chains.push_back(
1491 DAG.getStore(Chain, DL, Arg, Add,
1493 }
1494 if (!Chains.empty())
1495 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
1496 } else if (IsVarArg) {
1497 FINode = DAG.getIntPtrConstant(0, DL);
1498 }
1499
1500 if (Callee->getOpcode() == ISD::GlobalAddress) {
1501 // If the callee is a GlobalAddress node (quite common, every direct call
1502 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
1503 // doesn't at MO_GOT which is not needed for direct calls.
1504 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
1507 GA->getOffset());
1508 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
1509 getPointerTy(DAG.getDataLayout()), Callee);
1510 }
1511
1512 // Compute the operands for the CALLn node.
1514 Ops.push_back(Chain);
1515 Ops.push_back(Callee);
1516
1517 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
1518 // isn't reliable.
1519 Ops.append(OutVals.begin(),
1520 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
1521 // Add a pointer to the vararg buffer.
1522 if (IsVarArg)
1523 Ops.push_back(FINode);
1524
1525 SmallVector<EVT, 8> InTys;
1526 for (const auto &In : Ins) {
1527 assert(!In.Flags.isByVal() && "byval is not valid for return values");
1528 assert(!In.Flags.isNest() && "nest is not valid for return values");
1529 if (In.Flags.isInAlloca())
1530 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
1531 if (In.Flags.isInConsecutiveRegs())
1532 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
1533 if (In.Flags.isInConsecutiveRegsLast())
1534 fail(DL, DAG,
1535 "WebAssembly hasn't implemented cons regs last return values");
1536 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1537 // registers.
1538 InTys.push_back(In.VT);
1539 }
1540
1541 // Lastly, if this is a call to a funcref we need to add an instruction
1542 // table.set to the chain and transform the call.
1543 if (IsFuncrefCall) {
1544 // In the absence of function references proposal where a funcref call is
1545 // lowered to call_ref, using reference types we generate a table.set to set
1546 // the funcref to a special table used solely for this purpose, followed by
1547 // a call_indirect. Here we just generate the table set, and return the
1548 // SDValue of the table.set so that LowerCall can finalize the lowering by
1549 // generating the call_indirect.
1550 SDValue Chain = Ops[0];
1551
1553 MF.getContext(), Subtarget);
1554 SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
1555 SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
1556 SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
1557 SDValue TableSet = DAG.getMemIntrinsicNode(
1558 WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
1559 MVT::funcref, MachinePointerInfo(), Align(1),
1561
1562 Ops[0] = TableSet; // The new chain is the TableSet itself
1563 }
1564
1565 if (CLI.IsTailCall) {
1566 // ret_calls do not return values to the current frame
1567 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1568 return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
1569 }
1570
1571 InTys.push_back(MVT::Other);
1572 SDVTList InTyList = DAG.getVTList(InTys);
1573 SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
1574
1575 for (size_t I = 0; I < Ins.size(); ++I)
1576 InVals.push_back(Res.getValue(I));
1577
1578 // Return the chain
1579 return Res.getValue(Ins.size());
1580}
1581
1582bool WebAssemblyTargetLowering::CanLowerReturn(
1583 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
1584 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext & /*Context*/,
1585 const Type *RetTy) const {
1586 // WebAssembly can only handle returning tuples with multivalue enabled
1587 return WebAssembly::canLowerReturn(Outs.size(), Subtarget);
1588}
1589
1590SDValue WebAssemblyTargetLowering::LowerReturn(
1591 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
1593 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
1594 SelectionDAG &DAG) const {
1595 assert(WebAssembly::canLowerReturn(Outs.size(), Subtarget) &&
1596 "MVP WebAssembly can only return up to one value");
1597 if (!callingConvSupported(CallConv))
1598 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1599
1600 SmallVector<SDValue, 4> RetOps(1, Chain);
1601 RetOps.append(OutVals.begin(), OutVals.end());
1602 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
1603
1604 // Record the number and types of the return values.
1605 for (const ISD::OutputArg &Out : Outs) {
1606 assert(!Out.Flags.isByVal() && "byval is not valid for return values");
1607 assert(!Out.Flags.isNest() && "nest is not valid for return values");
1608 assert(!Out.Flags.isVarArg() && "non-fixed return value is not valid");
1609 if (Out.Flags.isInAlloca())
1610 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
1611 if (Out.Flags.isInConsecutiveRegs())
1612 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
1613 if (Out.Flags.isInConsecutiveRegsLast())
1614 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
1615 }
1616
1617 return Chain;
1618}
1619
1620SDValue WebAssemblyTargetLowering::LowerFormalArguments(
1621 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
1622 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
1623 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
1624 if (!callingConvSupported(CallConv))
1625 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1626
1628 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
1629
1630 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
1631 // of the incoming values before they're represented by virtual registers.
1632 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
1633
1634 bool HasSwiftErrorArg = false;
1635 bool HasSwiftSelfArg = false;
1636 bool HasSwiftAsyncArg = false;
1637 for (const ISD::InputArg &In : Ins) {
1638 HasSwiftSelfArg |= In.Flags.isSwiftSelf();
1639 HasSwiftErrorArg |= In.Flags.isSwiftError();
1640 HasSwiftAsyncArg |= In.Flags.isSwiftAsync();
1641 if (In.Flags.isInAlloca())
1642 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1643 if (In.Flags.isNest())
1644 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1645 if (In.Flags.isInConsecutiveRegs())
1646 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1647 if (In.Flags.isInConsecutiveRegsLast())
1648 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1649 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1650 // registers.
1651 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
1652 DAG.getTargetConstant(InVals.size(),
1653 DL, MVT::i32))
1654 : DAG.getUNDEF(In.VT));
1655
1656 // Record the number and types of arguments.
1657 MFI->addParam(In.VT);
1658 }
1659
1660 // For swiftcc and swifttailcc, emit additional swiftself, swifterror, and
1661 // (for swifttailcc) swiftasync arguments if there aren't. These additional
1662 // arguments are also added for callee signature. They are necessary to match
1663 // callee and caller signature for indirect call.
1664 auto PtrVT = getPointerTy(MF.getDataLayout());
1665 if (CallConv == CallingConv::Swift || CallConv == CallingConv::SwiftTail) {
1666 if (!HasSwiftSelfArg) {
1667 MFI->addParam(PtrVT);
1668 }
1669 if (!HasSwiftErrorArg) {
1670 MFI->addParam(PtrVT);
1671 }
1672 if (CallConv == CallingConv::SwiftTail && !HasSwiftAsyncArg) {
1673 MFI->addParam(PtrVT);
1674 }
1675 }
1676 // Varargs are copied into a buffer allocated by the caller, and a pointer to
1677 // the buffer is passed as an argument.
1678 if (IsVarArg) {
1679 MVT PtrVT = getPointerTy(MF.getDataLayout());
1680 Register VarargVreg =
1682 MFI->setVarargBufferVreg(VarargVreg);
1683 Chain = DAG.getCopyToReg(
1684 Chain, DL, VarargVreg,
1685 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
1686 DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
1687 MFI->addParam(PtrVT);
1688 }
1689
1690 // Record the number and types of arguments and results.
1691 SmallVector<MVT, 4> Params;
1694 MF.getFunction(), DAG.getTarget(), Params, Results);
1695 for (MVT VT : Results)
1696 MFI->addResult(VT);
1697 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
1698 // the param logic here with ComputeSignatureVTs
1699 assert(MFI->getParams().size() == Params.size() &&
1700 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
1701 Params.begin()));
1702
1703 return Chain;
1704}
1705
1706void WebAssemblyTargetLowering::ReplaceNodeResults(
1708 switch (N->getOpcode()) {
1710 // Do not add any results, signifying that N should not be custom lowered
1711 // after all. This happens because simd128 turns on custom lowering for
1712 // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1713 // illegal type.
1714 break;
1718 // Do not add any results, signifying that N should not be custom lowered.
1719 // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
1720 break;
1721 case ISD::FP_ROUND: {
1722 EVT VT = N->getValueType(0);
1723 SDValue Src = N->getOperand(0);
1724 if (VT == MVT::v4f16 && Src.getValueType() == MVT::v4f32) {
1725 Results.push_back(
1726 DAG.getNode(WebAssemblyISD::DEMOTE_ZERO, SDLoc(N), MVT::v8f16, Src));
1727 }
1728 break;
1729 }
1730 case ISD::ADD:
1731 case ISD::SUB:
1732 Results.push_back(Replace128Op(N, DAG));
1733 break;
1734 default:
1736 "ReplaceNodeResults not implemented for this op for WebAssembly!");
1737 }
1738}
1739
1740//===----------------------------------------------------------------------===//
1741// Custom lowering hooks.
1742//===----------------------------------------------------------------------===//
1743
1744SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1745 SelectionDAG &DAG) const {
1746 SDLoc DL(Op);
1747 switch (Op.getOpcode()) {
1748 default:
1749 llvm_unreachable("unimplemented operation lowering");
1750 return SDValue();
1751 case ISD::FrameIndex:
1752 return LowerFrameIndex(Op, DAG);
1753 case ISD::GlobalAddress:
1754 return LowerGlobalAddress(Op, DAG);
1756 return LowerGlobalTLSAddress(Op, DAG);
1758 return LowerExternalSymbol(Op, DAG);
1759 case ISD::JumpTable:
1760 return LowerJumpTable(Op, DAG);
1761 case ISD::BR_JT:
1762 return LowerBR_JT(Op, DAG);
1763 case ISD::VASTART:
1764 return LowerVASTART(Op, DAG);
1765 case ISD::BlockAddress:
1766 case ISD::BRIND:
1767 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
1768 return SDValue();
1769 case ISD::RETURNADDR:
1770 return LowerRETURNADDR(Op, DAG);
1771 case ISD::FRAMEADDR:
1772 return LowerFRAMEADDR(Op, DAG);
1773 case ISD::CopyToReg:
1774 return LowerCopyToReg(Op, DAG);
1777 return LowerAccessVectorElement(Op, DAG);
1781 return LowerIntrinsic(Op, DAG);
1783 return LowerSIGN_EXTEND_INREG(Op, DAG);
1787 return LowerEXTEND_VECTOR_INREG(Op, DAG);
1788 case ISD::BUILD_VECTOR:
1789 return LowerBUILD_VECTOR(Op, DAG);
1791 return LowerVECTOR_SHUFFLE(Op, DAG);
1792 case ISD::SETCC:
1793 return LowerSETCC(Op, DAG);
1794 case ISD::SHL:
1795 case ISD::SRA:
1796 case ISD::SRL:
1797 return LowerShift(Op, DAG);
1800 return LowerFP_TO_INT_SAT(Op, DAG);
1801 case ISD::FMINNUM:
1802 case ISD::FMINIMUMNUM:
1803 return LowerFMIN(Op, DAG);
1804 case ISD::FMAXNUM:
1805 case ISD::FMAXIMUMNUM:
1806 return LowerFMAX(Op, DAG);
1807 case ISD::LOAD:
1808 return LowerLoad(Op, DAG);
1809 case ISD::STORE:
1810 return LowerStore(Op, DAG);
1811 case ISD::CTPOP:
1812 case ISD::CTLZ:
1813 case ISD::CTTZ:
1814 return DAG.UnrollVectorOp(Op.getNode());
1815 case ISD::CLEAR_CACHE:
1816 // Report this as a diagnostic rather than aborting, like the other
1817 // unsupported features in this target. Pass the chain through so that
1818 // codegen can reach the point where the diagnostic is emitted.
1819 fail(SDLoc(Op), DAG, "llvm.clear_cache is not supported on wasm");
1820 return Op.getOperand(0);
1821 case ISD::SMUL_LOHI:
1822 case ISD::UMUL_LOHI:
1823 return LowerMUL_LOHI(Op, DAG);
1824 case ISD::UADDO:
1825 return LowerUADDO(Op, DAG);
1826 }
1827}
1828
1832
1833 return false;
1834}
1835
1836static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op,
1837 SelectionDAG &DAG) {
1839 if (!FI)
1840 return std::nullopt;
1841
1842 auto &MF = DAG.getMachineFunction();
1844}
1845
1846SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
1847 SelectionDAG &DAG) const {
1848 SDLoc DL(Op);
1849 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
1850 const SDValue &Value = SN->getValue();
1851 const SDValue &Base = SN->getBasePtr();
1852 const SDValue &Offset = SN->getOffset();
1853
1855 if (!Offset->isUndef())
1856 report_fatal_error("unexpected offset when storing to webassembly global",
1857 false);
1858
1859 SDVTList Tys = DAG.getVTList(MVT::Other);
1860 SDValue Ops[] = {SN->getChain(), Value, Base};
1861 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops,
1862 SN->getMemoryVT(), SN->getMemOperand());
1863 }
1864
1865 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1866 if (!Offset->isUndef())
1867 report_fatal_error("unexpected offset when storing to webassembly local",
1868 false);
1869
1870 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1871 SDVTList Tys = DAG.getVTList(MVT::Other); // The chain.
1872 SDValue Ops[] = {SN->getChain(), Idx, Value};
1873 return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops);
1874 }
1875
1878 "Encountered an unlowerable store to the wasm_var address space",
1879 false);
1880
1881 return Op;
1882}
1883
1884SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
1885 SelectionDAG &DAG) const {
1886 SDLoc DL(Op);
1887 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
1888 const SDValue &Base = LN->getBasePtr();
1889 const SDValue &Offset = LN->getOffset();
1890
1892 if (!Offset->isUndef())
1894 "unexpected offset when loading from webassembly global", false);
1895
1896 SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
1897 SDValue Ops[] = {LN->getChain(), Base};
1898 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops,
1899 LN->getMemoryVT(), LN->getMemOperand());
1900 }
1901
1902 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1903 if (!Offset->isUndef())
1905 "unexpected offset when loading from webassembly local", false);
1906
1907 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1908 EVT LocalVT = LN->getValueType(0);
1909 return DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, {LocalVT, MVT::Other},
1910 {LN->getChain(), Idx});
1911 }
1912
1915 "Encountered an unlowerable load from the wasm_var address space",
1916 false);
1917
1918 return Op;
1919}
1920
1921SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
1922 SelectionDAG &DAG) const {
1923 assert(Subtarget->hasWideArithmetic());
1924 assert(Op.getValueType() == MVT::i64);
1925 SDLoc DL(Op);
1926 unsigned Opcode;
1927 switch (Op.getOpcode()) {
1928 case ISD::UMUL_LOHI:
1929 Opcode = WebAssemblyISD::I64_MUL_WIDE_U;
1930 break;
1931 case ISD::SMUL_LOHI:
1932 Opcode = WebAssemblyISD::I64_MUL_WIDE_S;
1933 break;
1934 default:
1935 llvm_unreachable("unexpected opcode");
1936 }
1937 SDValue LHS = Op.getOperand(0);
1938 SDValue RHS = Op.getOperand(1);
1939 SDValue Lo =
1940 DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
1941 SDValue Hi(Lo.getNode(), 1);
1942 SDValue Ops[] = {Lo, Hi};
1943 return DAG.getMergeValues(Ops, DL);
1944}
1945
1946// Lowers `UADDO` intrinsics to an `i64.add128` instruction when it's enabled.
1947//
1948// This enables generating a single wasm instruction for this operation where
1949// the upper half of both operands are constant zeros. The upper half of the
1950// result is then whether the overflow happened.
1951SDValue WebAssemblyTargetLowering::LowerUADDO(SDValue Op,
1952 SelectionDAG &DAG) const {
1953 assert(Subtarget->hasWideArithmetic());
1954 assert(Op.getValueType() == MVT::i64);
1955 assert(Op.getOpcode() == ISD::UADDO);
1956 SDLoc DL(Op);
1957 SDValue LHS = Op.getOperand(0);
1958 SDValue RHS = Op.getOperand(1);
1959 SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
1960 SDValue Result =
1961 DAG.getNode(WebAssemblyISD::I64_ADD128, DL,
1962 DAG.getVTList(MVT::i64, MVT::i64), LHS, Zero, RHS, Zero);
1963 SDValue CarryI64(Result.getNode(), 1);
1964 SDValue CarryI32 = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, CarryI64);
1965 SDValue Ops[] = {Result, CarryI32};
1966 return DAG.getMergeValues(Ops, DL);
1967}
1968
1969SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
1970 SelectionDAG &DAG) const {
1971 assert(Subtarget->hasWideArithmetic());
1972 assert(N->getValueType(0) == MVT::i128);
1973 SDLoc DL(N);
1974 unsigned Opcode;
1975 switch (N->getOpcode()) {
1976 case ISD::ADD:
1977 Opcode = WebAssemblyISD::I64_ADD128;
1978 break;
1979 case ISD::SUB:
1980 Opcode = WebAssemblyISD::I64_SUB128;
1981 break;
1982 default:
1983 llvm_unreachable("unexpected opcode");
1984 }
1985 SDValue LHS = N->getOperand(0);
1986 SDValue RHS = N->getOperand(1);
1987
1988 SDValue C0 = DAG.getConstant(0, DL, MVT::i64);
1989 SDValue C1 = DAG.getConstant(1, DL, MVT::i64);
1990 SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C0);
1991 SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C1);
1992 SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
1993 SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
1994 SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
1995 LHS_0, LHS_1, RHS_0, RHS_1);
1996 SDValue Result_HI(Result_LO.getNode(), 1);
1997 return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
1998}
1999
2000SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
2001 SelectionDAG &DAG) const {
2002 SDValue Src = Op.getOperand(2);
2003 if (isa<FrameIndexSDNode>(Src.getNode())) {
2004 // CopyToReg nodes don't support FrameIndex operands. Other targets select
2005 // the FI to some LEA-like instruction, but since we don't have that, we
2006 // need to insert some kind of instruction that can take an FI operand and
2007 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
2008 // local.copy between Op and its FI operand.
2009 SDValue Chain = Op.getOperand(0);
2010 SDLoc DL(Op);
2011 Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
2012 EVT VT = Src.getValueType();
2013 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
2014 : WebAssembly::COPY_I64,
2015 DL, VT, Src),
2016 0);
2017 return Op.getNode()->getNumValues() == 1
2018 ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
2019 : DAG.getCopyToReg(Chain, DL, Reg, Copy,
2020 Op.getNumOperands() == 4 ? Op.getOperand(3)
2021 : SDValue());
2022 }
2023 return SDValue();
2024}
2025
2026SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
2027 SelectionDAG &DAG) const {
2028 int FI = cast<FrameIndexSDNode>(Op)->getIndex();
2029 return DAG.getTargetFrameIndex(FI, Op.getValueType());
2030}
2031
2032SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
2033 SelectionDAG &DAG) const {
2034 SDLoc DL(Op);
2035
2036 if (!Subtarget->getTargetTriple().isOSEmscripten()) {
2037 fail(DL, DAG,
2038 "Non-Emscripten WebAssembly hasn't implemented "
2039 "__builtin_return_address");
2040 return SDValue();
2041 }
2042
2043 unsigned Depth = Op.getConstantOperandVal(0);
2044 MakeLibCallOptions CallOptions;
2045 return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
2046 {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
2047 .first;
2048}
2049
2050SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
2051 SelectionDAG &DAG) const {
2052 // Non-zero depths are not supported by WebAssembly currently. Use the
2053 // legalizer's default expansion, which is to return 0 (what this function is
2054 // documented to do).
2055 if (Op.getConstantOperandVal(0) > 0)
2056 return SDValue();
2057
2059 EVT VT = Op.getValueType();
2060 Register FP =
2061 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
2062 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
2063}
2064
2065SDValue
2066WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
2067 SelectionDAG &DAG) const {
2068 SDLoc DL(Op);
2069 const auto *GA = cast<GlobalAddressSDNode>(Op);
2070
2072 if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory())
2073 report_fatal_error("cannot use thread-local storage without bulk memory",
2074 false);
2075
2076 const GlobalValue *GV = GA->getGlobal();
2077
2078 // Currently only Emscripten supports dynamic linking with threads. Therefore,
2079 // on other targets, if we have thread-local storage, only the local-exec
2080 // model is possible.
2081 auto model = Subtarget->getTargetTriple().isOSEmscripten()
2082 ? GV->getThreadLocalMode()
2084
2085 // Unsupported TLS modes
2088
2089 if (model == GlobalValue::LocalExecTLSModel ||
2092 getTargetMachine().shouldAssumeDSOLocal(GV))) {
2093 // For DSO-local TLS variables we use offset from __tls_base, or
2094 // __wasm_get_tls_base() if using libcall thread context.
2095
2096 MVT PtrVT = getPointerTy(DAG.getDataLayout());
2097 SDValue BaseAddr(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0);
2098
2099 SDValue TLSOffset = DAG.getTargetGlobalAddress(
2100 GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL);
2101 SDValue SymOffset =
2102 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset);
2103
2104 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset);
2105 }
2106
2108
2109 EVT VT = Op.getValueType();
2110 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2111 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2112 GA->getOffset(),
2114}
2115
2116SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
2117 SelectionDAG &DAG) const {
2118 SDLoc DL(Op);
2119 const auto *GA = cast<GlobalAddressSDNode>(Op);
2120 EVT VT = Op.getValueType();
2121 assert(GA->getTargetFlags() == 0 &&
2122 "Unexpected target flags on generic GlobalAddressSDNode");
2124 fail(DL, DAG, "Invalid address space for WebAssembly target");
2125
2126 unsigned OperandFlags = 0;
2127 const GlobalValue *GV = GA->getGlobal();
2128 // Since WebAssembly tables cannot yet be shared across modules, we don't
2129 // need special treatment for tables in PIC mode.
2130 if (isPositionIndependent() &&
2132 if (getTargetMachine().shouldAssumeDSOLocal(GV)) {
2134 MVT PtrVT = getPointerTy(MF.getDataLayout());
2135 const char *BaseName;
2136 if (GV->getValueType()->isFunctionTy()) {
2137 BaseName = MF.createExternalSymbolName("__table_base");
2139 } else {
2140 BaseName = MF.createExternalSymbolName("__memory_base");
2142 }
2143 SDValue BaseAddr =
2144 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2145 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2146
2147 SDValue SymAddr = DAG.getNode(
2148 WebAssemblyISD::WrapperREL, DL, VT,
2149 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
2150 OperandFlags));
2151
2152 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
2153 }
2155 }
2156
2157 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2158 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2159 GA->getOffset(), OperandFlags));
2160}
2161
2162SDValue
2163WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
2164 SelectionDAG &DAG) const {
2165 SDLoc DL(Op);
2166 const auto *ES = cast<ExternalSymbolSDNode>(Op);
2167 EVT VT = Op.getValueType();
2168 assert(ES->getTargetFlags() == 0 &&
2169 "Unexpected target flags on generic ExternalSymbolSDNode");
2170 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2171 DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
2172}
2173
2174SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
2175 SelectionDAG &DAG) const {
2176 // There's no need for a Wrapper node because we always incorporate a jump
2177 // table operand into a BR_TABLE instruction, rather than ever
2178 // materializing it in a register.
2179 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
2180 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
2181 JT->getTargetFlags());
2182}
2183
2184SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
2185 SelectionDAG &DAG) const {
2186 SDLoc DL(Op);
2187 SDValue Chain = Op.getOperand(0);
2188 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
2189 SDValue Index = Op.getOperand(2);
2190 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
2191
2193 Ops.push_back(Chain);
2194 Ops.push_back(Index);
2195
2196 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
2197 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
2198
2199 // Add an operand for each case.
2200 for (auto *MBB : MBBs)
2201 Ops.push_back(DAG.getBasicBlock(MBB));
2202
2203 // Add the first MBB as a dummy default target for now. This will be replaced
2204 // with the proper default target (and the preceding range check eliminated)
2205 // if possible by WebAssemblyFixBrTableDefaults.
2206 Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
2207 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
2208}
2209
2210SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
2211 SelectionDAG &DAG) const {
2212 SDLoc DL(Op);
2213 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
2214
2215 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
2216 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
2217
2218 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
2219 MFI->getVarargBufferVreg(), PtrVT);
2220 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
2221 MachinePointerInfo(SV));
2222}
2223
2224SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
2225 SelectionDAG &DAG) const {
2227 unsigned IntNo;
2228 switch (Op.getOpcode()) {
2231 IntNo = Op.getConstantOperandVal(1);
2232 break;
2234 IntNo = Op.getConstantOperandVal(0);
2235 break;
2236 default:
2237 llvm_unreachable("Invalid intrinsic");
2238 }
2239 SDLoc DL(Op);
2240
2241 switch (IntNo) {
2242 default:
2243 return SDValue(); // Don't custom lower most intrinsics.
2244
2245 case Intrinsic::wasm_lsda: {
2246 auto PtrVT = getPointerTy(MF.getDataLayout());
2247 const char *SymName = MF.createExternalSymbolName(
2248 "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
2249 if (isPositionIndependent()) {
2250 SDValue Node = DAG.getTargetExternalSymbol(
2251 SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
2252 const char *BaseName = MF.createExternalSymbolName("__memory_base");
2253 SDValue BaseAddr =
2254 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2255 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2256 SDValue SymAddr =
2257 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
2258 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
2259 }
2260 SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
2261 return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
2262 }
2263
2264 case Intrinsic::wasm_shuffle: {
2265 // Drop in-chain and replace undefs, but otherwise pass through unchanged
2266 SDValue Ops[18];
2267 size_t OpIdx = 0;
2268 Ops[OpIdx++] = Op.getOperand(1);
2269 Ops[OpIdx++] = Op.getOperand(2);
2270 while (OpIdx < 18) {
2271 const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
2272 if (MaskIdx.isUndef() || MaskIdx.getNode()->getAsZExtVal() >= 32) {
2273 bool isTarget = MaskIdx.getNode()->getOpcode() == ISD::TargetConstant;
2274 Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32, isTarget);
2275 } else {
2276 Ops[OpIdx++] = MaskIdx;
2277 }
2278 }
2279 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2280 }
2281
2282 case Intrinsic::wasm_funcref_to_ptr: {
2283 // llvm.wasm.funcref.to_ptr only has a defined lowering when its result
2284 // feeds directly into an indirect call. Reaching here means the pointer
2285 // escapes a direct call. We haven't implemented conversion of a funcref
2286 // into a real function pointer so we crash if we get here.
2287 fail(DL, DAG,
2288 "a funcref can only be converted to a pointer to be directly called; "
2289 "the resulting pointer cannot otherwise be used");
2290 return DAG.getPOISON(Op.getValueType());
2291 }
2292
2293 case Intrinsic::thread_pointer: {
2294 return SDValue(WebAssembly::getTLSBase(DAG, DL, Subtarget), 0);
2295 }
2296 }
2297}
2298
2299SDValue
2300WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
2301 SelectionDAG &DAG) const {
2302 SDLoc DL(Op);
2303 // If sign extension operations are disabled, allow sext_inreg only if operand
2304 // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
2305 // extension operations, but allowing sext_inreg in this context lets us have
2306 // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
2307 // everywhere would be simpler in this file, but would necessitate large and
2308 // brittle patterns to undo the expansion and select extract_lane_s
2309 // instructions.
2310 assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
2311 if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2312 return SDValue();
2313
2314 const SDValue &Extract = Op.getOperand(0);
2315 MVT VecT = Extract.getOperand(0).getSimpleValueType();
2316 if (VecT.getVectorElementType().getSizeInBits() > 32)
2317 return SDValue();
2318 MVT ExtractedLaneT =
2319 cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
2320 MVT ExtractedVecT =
2321 MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
2322 if (ExtractedVecT == VecT)
2323 return Op;
2324
2325 // Bitcast vector to appropriate type to ensure ISel pattern coverage
2326 const SDNode *Index = Extract.getOperand(1).getNode();
2327 if (!isa<ConstantSDNode>(Index))
2328 return SDValue();
2329 unsigned IndexVal = Index->getAsZExtVal();
2330 unsigned Scale =
2331 ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
2332 assert(Scale > 1);
2333 SDValue NewIndex =
2334 DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
2335 SDValue NewExtract = DAG.getNode(
2337 DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
2338 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
2339 Op.getOperand(1));
2340}
2341
2342static SDValue GetExtendHigh(SDValue Op, unsigned UserOpc, EVT VT,
2343 SelectionDAG &DAG) {
2344 SDValue Source = peekThroughBitcasts(Op);
2345 if (Source.getOpcode() != ISD::VECTOR_SHUFFLE)
2346 return SDValue();
2347
2348 assert((UserOpc == WebAssemblyISD::EXTEND_LOW_U ||
2349 UserOpc == WebAssemblyISD::EXTEND_LOW_S) &&
2350 "expected extend_low");
2351 auto *Shuffle = cast<ShuffleVectorSDNode>(Source.getNode());
2352
2353 ArrayRef<int> Mask = Shuffle->getMask();
2354 // Look for a shuffle which moves from the high half to the low half.
2355 size_t FirstIdx = Mask.size() / 2;
2356 for (size_t i = 0; i < Mask.size() / 2; ++i) {
2357 if (Mask[i] != static_cast<int>(FirstIdx + i)) {
2358 return SDValue();
2359 }
2360 }
2361
2362 SDLoc DL(Op);
2363 unsigned Opc = UserOpc == WebAssemblyISD::EXTEND_LOW_S
2364 ? WebAssemblyISD::EXTEND_HIGH_S
2365 : WebAssemblyISD::EXTEND_HIGH_U;
2366 SDValue ShuffleSrc = Shuffle->getOperand(0);
2367 if (Op.getOpcode() == ISD::BITCAST)
2368 ShuffleSrc = DAG.getBitcast(Op.getValueType(), ShuffleSrc);
2369
2370 return DAG.getNode(Opc, DL, VT, ShuffleSrc);
2371}
2372
2373SDValue
2374WebAssemblyTargetLowering::LowerEXTEND_VECTOR_INREG(SDValue Op,
2375 SelectionDAG &DAG) const {
2376 SDLoc DL(Op);
2377 EVT VT = Op.getValueType();
2378 SDValue Src = Op.getOperand(0);
2379 EVT SrcVT = Src.getValueType();
2380
2381 if (SrcVT.getVectorElementType() == MVT::i1 ||
2382 SrcVT.getVectorElementType() == MVT::i64)
2383 return SDValue();
2384
2385 assert(VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits() == 0 &&
2386 "Unexpected extension factor.");
2387 unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits();
2388
2389 if (Scale != 2 && Scale != 4 && Scale != 8)
2390 return SDValue();
2391
2392 unsigned Ext;
2393 switch (Op.getOpcode()) {
2394 default:
2395 llvm_unreachable("unexpected opcode");
2398 Ext = WebAssemblyISD::EXTEND_LOW_U;
2399 break;
2401 Ext = WebAssemblyISD::EXTEND_LOW_S;
2402 break;
2403 }
2404
2405 if (Scale == 2) {
2406 // See if we can use EXTEND_HIGH.
2407 if (auto ExtendHigh = GetExtendHigh(Op.getOperand(0), Ext, VT, DAG))
2408 return ExtendHigh;
2409 }
2410
2411 SDValue Ret = Src;
2412 while (Scale != 1) {
2413 Ret = DAG.getNode(Ext, DL,
2414 Ret.getValueType()
2417 Ret);
2418 Scale /= 2;
2419 }
2420 assert(Ret.getValueType() == VT);
2421 return Ret;
2422}
2423
2425 SDLoc DL(Op);
2426 if (Op.getValueType() != MVT::v2f64 && Op.getValueType() != MVT::v4f32)
2427 return SDValue();
2428
2429 auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec,
2430 unsigned &Index) -> bool {
2431 switch (Op.getOpcode()) {
2432 case ISD::SINT_TO_FP:
2433 Opcode = WebAssemblyISD::CONVERT_LOW_S;
2434 break;
2435 case ISD::UINT_TO_FP:
2436 Opcode = WebAssemblyISD::CONVERT_LOW_U;
2437 break;
2438 case ISD::FP_EXTEND:
2439 case ISD::FP16_TO_FP:
2440 Opcode = WebAssemblyISD::PROMOTE_LOW;
2441 break;
2442 default:
2443 return false;
2444 }
2445
2446 auto ExtractVector = Op.getOperand(0);
2447 if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2448 return false;
2449
2450 if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode()))
2451 return false;
2452
2453 SrcVec = ExtractVector.getOperand(0);
2454 Index = ExtractVector.getConstantOperandVal(1);
2455 return true;
2456 };
2457
2458 unsigned NumLanes = Op.getValueType() == MVT::v2f64 ? 2 : 4;
2459 unsigned FirstOpcode = 0, SecondOpcode = 0, ThirdOpcode = 0, FourthOpcode = 0;
2460 unsigned FirstIndex = 0, SecondIndex = 0, ThirdIndex = 0, FourthIndex = 0;
2461 SDValue FirstSrcVec, SecondSrcVec, ThirdSrcVec, FourthSrcVec;
2462
2463 if (!GetConvertedLane(Op.getOperand(0), FirstOpcode, FirstSrcVec,
2464 FirstIndex) ||
2465 !GetConvertedLane(Op.getOperand(1), SecondOpcode, SecondSrcVec,
2466 SecondIndex))
2467 return SDValue();
2468
2469 // If we're converting to v4f32, check the third and fourth lanes, too.
2470 if (NumLanes == 4 && (!GetConvertedLane(Op.getOperand(2), ThirdOpcode,
2471 ThirdSrcVec, ThirdIndex) ||
2472 !GetConvertedLane(Op.getOperand(3), FourthOpcode,
2473 FourthSrcVec, FourthIndex)))
2474 return SDValue();
2475
2476 if (FirstOpcode != SecondOpcode)
2477 return SDValue();
2478
2479 // TODO Add an optimization similar to the v2f64 below for shuffling the
2480 // vectors when the lanes are in the wrong order or come from different src
2481 // vectors.
2482 if (NumLanes == 4 &&
2483 (FirstOpcode != ThirdOpcode || FirstOpcode != FourthOpcode ||
2484 FirstSrcVec != SecondSrcVec || FirstSrcVec != ThirdSrcVec ||
2485 FirstSrcVec != FourthSrcVec || FirstIndex != 0 || SecondIndex != 1 ||
2486 ThirdIndex != 2 || FourthIndex != 3))
2487 return SDValue();
2488
2489 MVT ExpectedSrcVT;
2490 switch (FirstOpcode) {
2491 case WebAssemblyISD::CONVERT_LOW_S:
2492 case WebAssemblyISD::CONVERT_LOW_U:
2493 ExpectedSrcVT = MVT::v4i32;
2494 break;
2495 case WebAssemblyISD::PROMOTE_LOW:
2496 ExpectedSrcVT = NumLanes == 2 ? MVT::v4f32 : MVT::v8i16;
2497 break;
2498 }
2499 if (FirstSrcVec.getValueType() != ExpectedSrcVT)
2500 return SDValue();
2501
2502 auto Src = FirstSrcVec;
2503 if (NumLanes == 2 &&
2504 (FirstIndex != 0 || SecondIndex != 1 || FirstSrcVec != SecondSrcVec)) {
2505 // Shuffle the source vector so that the converted lanes are the low lanes.
2506 Src = DAG.getVectorShuffle(ExpectedSrcVT, DL, FirstSrcVec, SecondSrcVec,
2507 {static_cast<int>(FirstIndex),
2508 static_cast<int>(SecondIndex) + 4, -1, -1});
2509 }
2510 return DAG.getNode(FirstOpcode, DL, NumLanes == 2 ? MVT::v2f64 : MVT::v4f32,
2511 Src);
2512}
2513
2514SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
2515 SelectionDAG &DAG) const {
2516 MVT VT = Op.getSimpleValueType();
2517 if (VT == MVT::v8f16) {
2518 // BUILD_VECTOR can't handle FP16 operands since Wasm doesn't have a scalar
2519 // FP16 type, so cast them to I16s.
2520 MVT IVT = VT.changeVectorElementType(MVT::i16);
2522 for (unsigned I = 0, E = Op.getNumOperands(); I < E; ++I)
2523 NewOps.push_back(DAG.getBitcast(MVT::i16, Op.getOperand(I)));
2524 SDValue Res = DAG.getNode(ISD::BUILD_VECTOR, SDLoc(), IVT, NewOps);
2525 return DAG.getBitcast(VT, Res);
2526 }
2527
2528 if (auto ConvertLow = LowerConvertLow(Op, DAG))
2529 return ConvertLow;
2530
2531 SDLoc DL(Op);
2532 const EVT VecT = Op.getValueType();
2533 const EVT LaneT = Op.getOperand(0).getValueType();
2534 const size_t Lanes = Op.getNumOperands();
2535 bool CanSwizzle = VecT == MVT::v16i8;
2536
2537 // BUILD_VECTORs are lowered to the instruction that initializes the highest
2538 // possible number of lanes at once followed by a sequence of replace_lane
2539 // instructions to individually initialize any remaining lanes.
2540
2541 // TODO: Tune this. For example, lanewise swizzling is very expensive, so
2542 // swizzled lanes should be given greater weight.
2543
2544 // TODO: Investigate looping rather than always extracting/replacing specific
2545 // lanes to fill gaps.
2546
2547 auto IsConstant = [](const SDValue &V) {
2548 return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
2549 };
2550
2551 // Returns the source vector and index vector pair if they exist. Checks for:
2552 // (extract_vector_elt
2553 // $src,
2554 // (sign_extend_inreg (extract_vector_elt $indices, $i))
2555 // )
2556 auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
2557 auto Bail = std::make_pair(SDValue(), SDValue());
2558 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2559 return Bail;
2560 const SDValue &SwizzleSrc = Lane->getOperand(0);
2561 const SDValue &IndexExt = Lane->getOperand(1);
2562 if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
2563 return Bail;
2564 const SDValue &Index = IndexExt->getOperand(0);
2565 if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2566 return Bail;
2567 const SDValue &SwizzleIndices = Index->getOperand(0);
2568 if (SwizzleSrc.getValueType() != MVT::v16i8 ||
2569 SwizzleIndices.getValueType() != MVT::v16i8 ||
2570 Index->getOperand(1)->getOpcode() != ISD::Constant ||
2571 Index->getConstantOperandVal(1) != I)
2572 return Bail;
2573 return std::make_pair(SwizzleSrc, SwizzleIndices);
2574 };
2575
2576 // If the lane is extracted from another vector at a constant index, return
2577 // that vector. The source vector must not have more lanes than the dest
2578 // because the shufflevector indices are in terms of the destination lanes and
2579 // would not be able to address the smaller individual source lanes.
2580 auto GetShuffleSrc = [&](const SDValue &Lane) {
2581 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2582 return SDValue();
2583 if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode()))
2584 return SDValue();
2585 if (Lane->getOperand(0).getValueType().getVectorNumElements() >
2586 VecT.getVectorNumElements())
2587 return SDValue();
2588 return Lane->getOperand(0);
2589 };
2590
2591 using ValueEntry = std::pair<SDValue, size_t>;
2592 SmallVector<ValueEntry, 16> SplatValueCounts;
2593
2594 using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
2595 SmallVector<SwizzleEntry, 16> SwizzleCounts;
2596
2597 using ShuffleEntry = std::pair<SDValue, size_t>;
2598 SmallVector<ShuffleEntry, 16> ShuffleCounts;
2599
2600 auto AddCount = [](auto &Counts, const auto &Val) {
2601 auto CountIt =
2602 llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; });
2603 if (CountIt == Counts.end()) {
2604 Counts.emplace_back(Val, 1);
2605 } else {
2606 CountIt->second++;
2607 }
2608 };
2609
2610 auto GetMostCommon = [](auto &Counts) {
2611 auto CommonIt = llvm::max_element(Counts, llvm::less_second());
2612 assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
2613 return *CommonIt;
2614 };
2615
2616 size_t NumConstantLanes = 0;
2617
2618 // Count eligible lanes for each type of vector creation op
2619 for (size_t I = 0; I < Lanes; ++I) {
2620 const SDValue &Lane = Op->getOperand(I);
2621 if (Lane.isUndef())
2622 continue;
2623
2624 AddCount(SplatValueCounts, Lane);
2625
2626 if (IsConstant(Lane))
2627 NumConstantLanes++;
2628 if (auto ShuffleSrc = GetShuffleSrc(Lane))
2629 AddCount(ShuffleCounts, ShuffleSrc);
2630 if (CanSwizzle) {
2631 auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
2632 if (SwizzleSrcs.first)
2633 AddCount(SwizzleCounts, SwizzleSrcs);
2634 }
2635 }
2636
2637 SDValue SplatValue;
2638 size_t NumSplatLanes;
2639 std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
2640
2641 SDValue SwizzleSrc;
2642 SDValue SwizzleIndices;
2643 size_t NumSwizzleLanes = 0;
2644 if (SwizzleCounts.size())
2645 std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
2646 NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
2647
2648 // Shuffles can draw from up to two vectors, so find the two most common
2649 // sources.
2650 SDValue ShuffleSrc1, ShuffleSrc2;
2651 size_t NumShuffleLanes = 0;
2652 if (ShuffleCounts.size()) {
2653 std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts);
2654 llvm::erase_if(ShuffleCounts,
2655 [&](const auto &Pair) { return Pair.first == ShuffleSrc1; });
2656 }
2657 if (ShuffleCounts.size()) {
2658 size_t AdditionalShuffleLanes;
2659 std::tie(ShuffleSrc2, AdditionalShuffleLanes) =
2660 GetMostCommon(ShuffleCounts);
2661 NumShuffleLanes += AdditionalShuffleLanes;
2662 }
2663
2664 // Predicate returning true if the lane is properly initialized by the
2665 // original instruction
2666 std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
2667 SDValue Result;
2668 // Prefer swizzles over shuffles over vector consts over splats
2669 if (NumSwizzleLanes >= NumShuffleLanes &&
2670 NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) {
2671 Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
2672 SwizzleIndices);
2673 auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
2674 IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
2675 return Swizzled == GetSwizzleSrcs(I, Lane);
2676 };
2677 } else if (NumShuffleLanes >= NumConstantLanes &&
2678 NumShuffleLanes >= NumSplatLanes) {
2679 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8;
2680 size_t DestLaneCount = VecT.getVectorNumElements();
2681 size_t Scale1 = 1;
2682 size_t Scale2 = 1;
2683 SDValue Src1 = ShuffleSrc1;
2684 SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT);
2685 if (Src1.getValueType() != VecT) {
2686 size_t LaneSize =
2688 assert(LaneSize > DestLaneSize);
2689 Scale1 = LaneSize / DestLaneSize;
2690 Src1 = DAG.getBitcast(VecT, Src1);
2691 }
2692 if (Src2.getValueType() != VecT) {
2693 size_t LaneSize =
2695 assert(LaneSize > DestLaneSize);
2696 Scale2 = LaneSize / DestLaneSize;
2697 Src2 = DAG.getBitcast(VecT, Src2);
2698 }
2699
2700 int Mask[16];
2701 assert(DestLaneCount <= 16);
2702 for (size_t I = 0; I < DestLaneCount; ++I) {
2703 const SDValue &Lane = Op->getOperand(I);
2704 SDValue Src = GetShuffleSrc(Lane);
2705 if (Src == ShuffleSrc1) {
2706 Mask[I] = Lane->getConstantOperandVal(1) * Scale1;
2707 } else if (Src && Src == ShuffleSrc2) {
2708 Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2;
2709 } else {
2710 Mask[I] = -1;
2711 }
2712 }
2713 ArrayRef<int> MaskRef(Mask, DestLaneCount);
2714 Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef);
2715 IsLaneConstructed = [&](size_t, const SDValue &Lane) {
2716 auto Src = GetShuffleSrc(Lane);
2717 return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2);
2718 };
2719 } else if (NumConstantLanes >= NumSplatLanes) {
2720 SmallVector<SDValue, 16> ConstLanes;
2721 for (const SDValue &Lane : Op->op_values()) {
2722 if (IsConstant(Lane)) {
2723 // Values may need to be fixed so that they will sign extend to be
2724 // within the expected range during ISel. Check whether the value is in
2725 // bounds based on the lane bit width and if it is out of bounds, lop
2726 // off the extra bits.
2727 uint64_t LaneBits = 128 / Lanes;
2728 if (auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode())) {
2729 ConstLanes.push_back(DAG.getConstant(
2730 Const->getAPIntValue().trunc(LaneBits).getZExtValue(),
2731 SDLoc(Lane), LaneT));
2732 } else {
2733 ConstLanes.push_back(Lane);
2734 }
2735 } else if (LaneT.isFloatingPoint()) {
2736 ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
2737 } else {
2738 ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
2739 }
2740 }
2741 Result = DAG.getBuildVector(VecT, DL, ConstLanes);
2742 IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) {
2743 return IsConstant(Lane);
2744 };
2745 } else {
2746 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits();
2747 if (NumSplatLanes == 1 && Op->getOperand(0) == SplatValue &&
2748 (DestLaneSize == 32 || DestLaneSize == 64)) {
2749 // Could be selected to load_zero.
2750 Result = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecT, SplatValue);
2751 } else {
2752 // Use a splat (which might be selected as a load splat)
2753 Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
2754 }
2755 IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) {
2756 return Lane == SplatValue;
2757 };
2758 }
2759
2760 assert(Result);
2761 assert(IsLaneConstructed);
2762
2763 // Add replace_lane instructions for any unhandled values
2764 for (size_t I = 0; I < Lanes; ++I) {
2765 const SDValue &Lane = Op->getOperand(I);
2766 if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
2767 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
2768 DAG.getConstant(I, DL, MVT::i32));
2769 }
2770
2771 return Result;
2772}
2773
2774SDValue
2775WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2776 SelectionDAG &DAG) const {
2777 SDLoc DL(Op);
2778 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
2779 MVT VecType = Op.getOperand(0).getSimpleValueType();
2780 assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
2781 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
2782
2783 // Space for two vector args and sixteen mask indices
2784 SDValue Ops[18];
2785 size_t OpIdx = 0;
2786 Ops[OpIdx++] = Op.getOperand(0);
2787 Ops[OpIdx++] = Op.getOperand(1);
2788
2789 // Expand mask indices to byte indices and materialize them as operands
2790 for (int M : Mask) {
2791 for (size_t J = 0; J < LaneBytes; ++J) {
2792 // Lower undefs (represented by -1 in mask) to {0..J}, which use a
2793 // whole lane of vector input, to allow further reduction at VM. E.g.
2794 // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle.
2795 uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J;
2796 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
2797 }
2798 }
2799
2800 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2801}
2802
2803SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
2804 SelectionDAG &DAG) const {
2805 SDLoc DL(Op);
2806 // The legalizer does not know how to expand the unsupported comparison modes
2807 // of i64x2 vectors, so we manually unroll them here.
2808 assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
2810 DAG.ExtractVectorElements(Op->getOperand(0), LHS);
2811 DAG.ExtractVectorElements(Op->getOperand(1), RHS);
2812 const SDValue &CC = Op->getOperand(2);
2813 auto MakeLane = [&](unsigned I) {
2814 return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
2815 DAG.getConstant(uint64_t(-1), DL, MVT::i64),
2816 DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
2817 };
2818 return DAG.getBuildVector(Op->getValueType(0), DL,
2819 {MakeLane(0), MakeLane(1)});
2820}
2821
2822SDValue
2823WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
2824 SelectionDAG &DAG) const {
2825 if (Op.getOpcode() == ISD::INSERT_VECTOR_ELT &&
2826 Op.getValueType() == MVT::v8f16) {
2827 // INSERT_VECTOR_ELT can't handle FP16 operands since Wasm doesn't have a
2828 // scalar FP16 type, so cast them to I16s.
2829 SDLoc DL(Op);
2830 SDValue IntVector = DAG.getBitcast(MVT::v8i16, Op.getOperand(0));
2831 SDValue IntElement = DAG.getBitcast(MVT::i16, Op.getOperand(1));
2832 SDValue Inserted = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, MVT::v8i16,
2833 IntVector, IntElement, Op.getOperand(2));
2834 return DAG.getBitcast(MVT::v8f16, Inserted);
2835 }
2836
2837 // Allow constant lane indices, expand variable lane indices
2838 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
2839 if (isa<ConstantSDNode>(IdxNode)) {
2840 // Ensure the index type is i32 to match the tablegen patterns
2841 uint64_t Idx = IdxNode->getAsZExtVal();
2842 SmallVector<SDValue, 3> Ops(Op.getNode()->ops());
2843 Ops[Op.getNumOperands() - 1] =
2844 DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32);
2845 return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops);
2846 }
2847 // Perform default expansion
2848 return SDValue();
2849}
2850
2852 EVT LaneT = Op.getSimpleValueType().getVectorElementType();
2853 // 32-bit and 64-bit unrolled shifts will have proper semantics
2854 if (LaneT.bitsGE(MVT::i32))
2855 return DAG.UnrollVectorOp(Op.getNode());
2856 // Otherwise mask the shift value to get proper semantics from 32-bit shift
2857 SDLoc DL(Op);
2858 size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
2859 SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
2860 unsigned ShiftOpcode = Op.getOpcode();
2861 SmallVector<SDValue, 16> ShiftedElements;
2862 DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
2863 SmallVector<SDValue, 16> ShiftElements;
2864 DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
2865 SmallVector<SDValue, 16> UnrolledOps;
2866 for (size_t i = 0; i < NumLanes; ++i) {
2867 SDValue MaskedShiftValue =
2868 DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
2869 SDValue ShiftedValue = ShiftedElements[i];
2870 if (ShiftOpcode == ISD::SRA)
2871 ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
2872 ShiftedValue, DAG.getValueType(LaneT));
2873 UnrolledOps.push_back(
2874 DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
2875 }
2876 return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
2877}
2878
2879SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
2880 SelectionDAG &DAG) const {
2881 SDLoc DL(Op);
2882 // Only manually lower vector shifts
2883 assert(Op.getSimpleValueType().isVector());
2884
2885 uint64_t LaneBits = Op.getValueType().getScalarSizeInBits();
2886 auto ShiftVal = Op.getOperand(1);
2887
2888 // Try to skip bitmask operation since it is implied inside shift instruction
2889 auto SkipImpliedMask = [](SDValue MaskOp, uint64_t MaskBits) {
2890 if (MaskOp.getOpcode() != ISD::AND)
2891 return MaskOp;
2892 SDValue LHS = MaskOp.getOperand(0);
2893 SDValue RHS = MaskOp.getOperand(1);
2894 if (MaskOp.getValueType().isVector()) {
2895 APInt MaskVal;
2896 if (!ISD::isConstantSplatVector(RHS.getNode(), MaskVal))
2897 std::swap(LHS, RHS);
2898
2899 if (ISD::isConstantSplatVector(RHS.getNode(), MaskVal) &&
2900 MaskVal == MaskBits)
2901 MaskOp = LHS;
2902 } else {
2903 if (!isa<ConstantSDNode>(RHS.getNode()))
2904 std::swap(LHS, RHS);
2905
2906 auto ConstantRHS = dyn_cast<ConstantSDNode>(RHS.getNode());
2907 if (ConstantRHS && ConstantRHS->getAPIntValue() == MaskBits)
2908 MaskOp = LHS;
2909 }
2910
2911 return MaskOp;
2912 };
2913
2914 // Skip vector and operation
2915 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2916 ShiftVal = DAG.getSplatValue(ShiftVal);
2917 if (!ShiftVal)
2918 return unrollVectorShift(Op, DAG);
2919
2920 // Skip scalar and operation
2921 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2922 // Use anyext because none of the high bits can affect the shift
2923 ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
2924
2925 unsigned Opcode;
2926 switch (Op.getOpcode()) {
2927 case ISD::SHL:
2928 Opcode = WebAssemblyISD::VEC_SHL;
2929 break;
2930 case ISD::SRA:
2931 Opcode = WebAssemblyISD::VEC_SHR_S;
2932 break;
2933 case ISD::SRL:
2934 Opcode = WebAssemblyISD::VEC_SHR_U;
2935 break;
2936 default:
2937 llvm_unreachable("unexpected opcode");
2938 }
2939
2940 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
2941}
2942
2943SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op,
2944 SelectionDAG &DAG) const {
2945 EVT ResT = Op.getValueType();
2946 EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
2947
2948 if ((ResT == MVT::i32 || ResT == MVT::i64) &&
2949 (SatVT == MVT::i32 || SatVT == MVT::i64))
2950 return Op;
2951
2952 if (ResT == MVT::v4i32 && SatVT == MVT::i32)
2953 return Op;
2954
2955 if (ResT == MVT::v8i16 && SatVT == MVT::i16)
2956 return Op;
2957
2958 return SDValue();
2959}
2960
2962 return (Op->getFlags().hasNoNaNs() ||
2963 (DAG.isKnownNeverNaN(Op->getOperand(0)) &&
2964 DAG.isKnownNeverNaN(Op->getOperand(1)))) &&
2965 (Op->getFlags().hasNoSignedZeros() ||
2966 DAG.isKnownNeverLogicalZero(Op->getOperand(0)) ||
2967 DAG.isKnownNeverLogicalZero(Op->getOperand(1)));
2968}
2969
2970SDValue WebAssemblyTargetLowering::LowerFMIN(SDValue Op,
2971 SelectionDAG &DAG) const {
2972 if (Subtarget->hasRelaxedSIMD() && HasNoSignedZerosOrNaNs(Op, DAG)) {
2973 return DAG.getNode(WebAssemblyISD::RELAXED_FMIN, SDLoc(Op),
2974 Op.getValueType(), Op.getOperand(0), Op.getOperand(1));
2975 }
2976 return SDValue();
2977}
2978
2979SDValue WebAssemblyTargetLowering::LowerFMAX(SDValue Op,
2980 SelectionDAG &DAG) const {
2981 if (Subtarget->hasRelaxedSIMD() && HasNoSignedZerosOrNaNs(Op, DAG)) {
2982 return DAG.getNode(WebAssemblyISD::RELAXED_FMAX, SDLoc(Op),
2983 Op.getValueType(), Op.getOperand(0), Op.getOperand(1));
2984 }
2985 return SDValue();
2986}
2987
2988//===----------------------------------------------------------------------===//
2989// Custom DAG combine hooks
2990//===----------------------------------------------------------------------===//
2991static SDValue
2993 auto &DAG = DCI.DAG;
2994 auto Shuffle = cast<ShuffleVectorSDNode>(N);
2995
2996 // Hoist vector bitcasts that don't change the number of lanes out of unary
2997 // shuffles, where they are less likely to get in the way of other combines.
2998 // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
2999 // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
3000 SDValue Bitcast = N->getOperand(0);
3001 if (Bitcast.getOpcode() != ISD::BITCAST)
3002 return SDValue();
3003 if (!N->getOperand(1).isUndef())
3004 return SDValue();
3005 SDValue CastOp = Bitcast.getOperand(0);
3006 EVT SrcType = CastOp.getValueType();
3007 EVT DstType = Bitcast.getValueType();
3008 if (!SrcType.is128BitVector() ||
3009 SrcType.getVectorNumElements() != DstType.getVectorNumElements())
3010 return SDValue();
3011 SDValue NewShuffle = DAG.getVectorShuffle(
3012 SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
3013 return DAG.getBitcast(DstType, NewShuffle);
3014}
3015
3016/// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get
3017/// split up into scalar instructions during legalization, and the vector
3018/// extending instructions are selected in performVectorExtendCombine below.
3019static SDValue
3021 const WebAssemblySubtarget *Subtarget) {
3022 auto &DAG = DCI.DAG;
3023 assert(N->getOpcode() == ISD::UINT_TO_FP ||
3024 N->getOpcode() == ISD::SINT_TO_FP);
3025
3026 EVT InVT = N->getOperand(0)->getValueType(0);
3027 EVT ResVT = N->getValueType(0);
3028 MVT ExtVT;
3029 if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8))
3030 ExtVT = MVT::v4i32;
3031 else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8))
3032 ExtVT = MVT::v2i32;
3033 else if (Subtarget->hasFP16() && ResVT == MVT::v8f16 && InVT == MVT::v8i8)
3034 ExtVT = MVT::v8i16;
3035 else
3036 return SDValue();
3037
3038 unsigned Op =
3040 SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0));
3041 return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv);
3042}
3043
3044static SDValue
3047 auto &DAG = DCI.DAG;
3048
3049 SDNodeFlags Flags = N->getFlags();
3050 SDValue Op0 = N->getOperand(0);
3051 EVT VT = N->getValueType(0);
3052
3053 // Optimize uitofp to sitofp when the sign bit is known to be zero.
3054 // Depending on the target (runtime) backend, this might be performance
3055 // neutral (e.g. AArch64) or a significant improvement (e.g. x86_64).
3056 if (VT.isVector() && (Flags.hasNonNeg() || DAG.SignBitIsZero(Op0))) {
3057 return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, Op0);
3058 }
3059
3060 return SDValue();
3061}
3062
3063static SDValue
3065 auto &DAG = DCI.DAG;
3066 assert(N->getOpcode() == ISD::SIGN_EXTEND ||
3067 N->getOpcode() == ISD::ZERO_EXTEND);
3068
3069 EVT ResVT = N->getValueType(0);
3070 bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND;
3071 SDLoc DL(N);
3072
3073 if (ResVT == MVT::v16i32 && N->getOperand(0)->getValueType(0) == MVT::v16i8) {
3074 // Use a tree of extend low/high to split and extend the input in two
3075 // layers to avoid doing several shuffles and even more extends.
3076 unsigned LowOp =
3077 IsSext ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3078 unsigned HighOp =
3079 IsSext ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
3080 SDValue Input = N->getOperand(0);
3081 SDValue LowHalf = DAG.getNode(LowOp, DL, MVT::v8i16, Input);
3082 SDValue HighHalf = DAG.getNode(HighOp, DL, MVT::v8i16, Input);
3083 SDValue Subvectors[] = {
3084 DAG.getNode(LowOp, DL, MVT::v4i32, LowHalf),
3085 DAG.getNode(HighOp, DL, MVT::v4i32, LowHalf),
3086 DAG.getNode(LowOp, DL, MVT::v4i32, HighHalf),
3087 DAG.getNode(HighOp, DL, MVT::v4i32, HighHalf),
3088 };
3089 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Subvectors);
3090 }
3091
3092 // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if
3093 // possible before the extract_subvector can be expanded.
3094 auto Extract = N->getOperand(0);
3095 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR)
3096 return SDValue();
3097 auto Source = Extract.getOperand(0);
3098 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1));
3099 if (IndexNode == nullptr)
3100 return SDValue();
3101 auto Index = IndexNode->getZExtValue();
3102
3103 // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the
3104 // extracted subvector is the low or high half of its source.
3105 if (ResVT == MVT::v8i16) {
3106 if (Extract.getValueType() != MVT::v8i8 ||
3107 Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8))
3108 return SDValue();
3109 } else if (ResVT == MVT::v4i32) {
3110 if (Extract.getValueType() != MVT::v4i16 ||
3111 Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4))
3112 return SDValue();
3113 } else if (ResVT == MVT::v2i64) {
3114 if (Extract.getValueType() != MVT::v2i32 ||
3115 Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2))
3116 return SDValue();
3117 } else {
3118 return SDValue();
3119 }
3120
3121 bool IsLow = Index == 0;
3122
3123 unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S
3124 : WebAssemblyISD::EXTEND_HIGH_S)
3125 : (IsLow ? WebAssemblyISD::EXTEND_LOW_U
3126 : WebAssemblyISD::EXTEND_HIGH_U);
3127
3128 return DAG.getNode(Op, DL, ResVT, Source);
3129}
3130
3131static SDValue
3133 auto &DAG = DCI.DAG;
3134
3135 auto GetWasmConversionOp = [](unsigned Op) {
3136 switch (Op) {
3138 return WebAssemblyISD::TRUNC_SAT_ZERO_S;
3140 return WebAssemblyISD::TRUNC_SAT_ZERO_U;
3141 case ISD::FP_ROUND:
3142 return WebAssemblyISD::DEMOTE_ZERO;
3143 }
3144 llvm_unreachable("unexpected op");
3145 };
3146
3147 auto IsZeroSplat = [](SDValue SplatVal) {
3148 auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode());
3149 APInt SplatValue, SplatUndef;
3150 unsigned SplatBitSize;
3151 bool HasAnyUndefs;
3152 // Endianness doesn't matter in this context because we are looking for
3153 // an all-zero value.
3154 return Splat &&
3155 Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
3156 HasAnyUndefs) &&
3157 SplatValue == 0;
3158 };
3159
3160 if (N->getOpcode() == ISD::CONCAT_VECTORS) {
3161 // Combine this:
3162 //
3163 // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0)))
3164 //
3165 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3166 //
3167 // Or this:
3168 //
3169 // (concat_vectors ({v2f32, v4f16} (fp_round ({v2f64, v4f32} $x))),
3170 // ({v2f32, v4f16} (splat 0)))
3171 //
3172 // into ({f32x4, f16x8}.demote_zero_{f64x2, f32x4} $x).
3173 EVT ResVT;
3174 EVT ExpectedConversionType;
3175 auto Conversion = N->getOperand(0);
3176 auto ConversionOp = Conversion.getOpcode();
3177 switch (ConversionOp) {
3180 ResVT = MVT::v4i32;
3181 ExpectedConversionType = MVT::v2i32;
3182 break;
3183 case ISD::FP_ROUND:
3184 if (Conversion.getValueType() == MVT::v2f32) {
3185 ResVT = MVT::v4f32;
3186 ExpectedConversionType = MVT::v2f32;
3187 } else if (Conversion.getValueType() == MVT::v4f16) {
3188 ResVT = MVT::v8f16;
3189 ExpectedConversionType = MVT::v4f16;
3190 } else {
3191 return SDValue();
3192 }
3193 break;
3194 default:
3195 return SDValue();
3196 }
3197
3198 if (N->getValueType(0) != ResVT)
3199 return SDValue();
3200
3201 if (Conversion.getValueType() != ExpectedConversionType)
3202 return SDValue();
3203
3204 auto Source = Conversion.getOperand(0);
3205 if (!((Source.getValueType() == MVT::v2f64 && ResVT == MVT::v4f32) ||
3206 (Source.getValueType() == MVT::v2f64 && ResVT == MVT::v4i32) ||
3207 (Source.getValueType() == MVT::v4f32 && ResVT == MVT::v8f16)))
3208 return SDValue();
3209
3210 if (!IsZeroSplat(N->getOperand(1)) ||
3211 N->getOperand(1).getValueType() != ExpectedConversionType)
3212 return SDValue();
3213
3214 unsigned Op = GetWasmConversionOp(ConversionOp);
3215 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
3216 }
3217
3218 // Combine this:
3219 //
3220 // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32)
3221 //
3222 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3223 //
3224 // Or this:
3225 //
3226 // ({v4f32, v8f16} (fp_round (concat_vectors $x,
3227 // ({v2f64, v4f32} (splat 0)))))
3228 //
3229 // into ({f32x4, f16x8}.demote_zero_{f64x2, f32x4} $x).
3230 EVT ResVT;
3231 auto ConversionOp = N->getOpcode();
3232 switch (ConversionOp) {
3235 ResVT = MVT::v4i32;
3236 break;
3237 case ISD::FP_ROUND:
3238 ResVT = N->getValueType(0);
3239 break;
3240 default:
3241 llvm_unreachable("unexpected op");
3242 }
3243
3244 if (N->getValueType(0) != ResVT)
3245 return SDValue();
3246
3247 auto Concat = N->getOperand(0);
3248 if (Concat.getOpcode() != ISD::CONCAT_VECTORS)
3249 return SDValue();
3250 EVT ConcatVT = Concat.getValueType();
3251 EVT SourceVT = Concat.getOperand(0).getValueType();
3252
3253 if (!IsZeroSplat(Concat.getOperand(1)))
3254 return SDValue();
3255
3256 if (ConversionOp == ISD::FP_ROUND) {
3257 bool IsF64ToF32 =
3258 ConcatVT == MVT::v4f64 && SourceVT == MVT::v2f64 && ResVT == MVT::v4f32;
3259 bool IsF32ToF16 =
3260 ConcatVT == MVT::v8f32 && SourceVT == MVT::v4f32 && ResVT == MVT::v8f16;
3261 if (!(IsF64ToF32 || IsF32ToF16))
3262 return SDValue();
3263 } else {
3264 if (ConcatVT != MVT::v4f64 || SourceVT != MVT::v2f64 || ResVT != MVT::v4i32)
3265 return SDValue();
3266 }
3267
3268 unsigned Op = GetWasmConversionOp(ConversionOp);
3269 return DAG.getNode(Op, SDLoc(N), ResVT, Concat.getOperand(0));
3270}
3271
3272// Helper to extract VectorWidth bits from Vec, starting from IdxVal.
3273static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
3274 const SDLoc &DL, unsigned VectorWidth) {
3275 EVT VT = Vec.getValueType();
3276 EVT ElVT = VT.getVectorElementType();
3277 unsigned Factor = VT.getSizeInBits() / VectorWidth;
3278 EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT,
3279 VT.getVectorNumElements() / Factor);
3280
3281 // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR
3282 unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits();
3283 assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2");
3284
3285 // This is the index of the first element of the VectorWidth-bit chunk
3286 // we want. Since ElemsPerChunk is a power of 2 just need to clear bits.
3287 IdxVal &= ~(ElemsPerChunk - 1);
3288
3289 // If the input is a buildvector just emit a smaller one.
3290 if (Vec.getOpcode() == ISD::BUILD_VECTOR)
3291 return DAG.getBuildVector(ResultVT, DL,
3292 Vec->ops().slice(IdxVal, ElemsPerChunk));
3293
3294 SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL);
3295 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx);
3296}
3297
3298// Helper to recursively truncate vector elements in half with NARROW_U. DstVT
3299// is the expected destination value type after recursion. In is the initial
3300// input. Note that the input should have enough leading zero bits to prevent
3301// NARROW_U from saturating results.
3303 SelectionDAG &DAG) {
3304 EVT SrcVT = In.getValueType();
3305
3306 // No truncation required, we might get here due to recursive calls.
3307 if (SrcVT == DstVT)
3308 return In;
3309
3310 unsigned SrcSizeInBits = SrcVT.getSizeInBits();
3311 unsigned NumElems = SrcVT.getVectorNumElements();
3312 if (!isPowerOf2_32(NumElems))
3313 return SDValue();
3314 assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
3315 assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation");
3316
3317 LLVMContext &Ctx = *DAG.getContext();
3318 EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2);
3319
3320 // Narrow to the largest type possible:
3321 // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u.
3322 EVT InVT = MVT::i16, OutVT = MVT::i8;
3323 if (SrcVT.getScalarSizeInBits() > 16) {
3324 InVT = MVT::i32;
3325 OutVT = MVT::i16;
3326 }
3327 unsigned SubSizeInBits = SrcSizeInBits / 2;
3328 InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits());
3329 OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits());
3330
3331 // Split lower/upper subvectors.
3332 SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits);
3333 SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits);
3334
3335 // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors.
3336 if (SrcVT.is256BitVector() && DstVT.is128BitVector()) {
3337 Lo = DAG.getBitcast(InVT, Lo);
3338 Hi = DAG.getBitcast(InVT, Hi);
3339 SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi);
3340 return DAG.getBitcast(DstVT, Res);
3341 }
3342
3343 // Recursively narrow lower/upper subvectors, concat result and narrow again.
3344 EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2);
3345 Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG);
3346 Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG);
3347
3348 PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems);
3349 SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
3350 return truncateVectorWithNARROW(DstVT, Res, DL, DAG);
3351}
3352
3355 auto &DAG = DCI.DAG;
3356
3357 SDValue In = N->getOperand(0);
3358 EVT InVT = In.getValueType();
3359 if (!InVT.isSimple())
3360 return SDValue();
3361
3362 EVT OutVT = N->getValueType(0);
3363 if (!OutVT.isVector())
3364 return SDValue();
3365
3366 EVT OutSVT = OutVT.getVectorElementType();
3367 EVT InSVT = InVT.getVectorElementType();
3368 // Currently only cover truncate to v16i8 or v8i16.
3369 if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) &&
3370 (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector()))
3371 return SDValue();
3372
3373 SDLoc DL(N);
3375 OutVT.getScalarSizeInBits());
3376 In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT));
3377 return truncateVectorWithNARROW(OutVT, In, DL, DAG);
3378}
3379
3382 using namespace llvm::SDPatternMatch;
3383 auto &DAG = DCI.DAG;
3384 SDLoc DL(N);
3385 SDValue Src = N->getOperand(0);
3386 EVT VT = N->getValueType(0);
3387 EVT SrcVT = Src.getValueType();
3388
3389 if (!(DCI.isBeforeLegalize() && VT.isScalarInteger() &&
3390 SrcVT.isFixedLengthVectorOf(MVT::i1)))
3391 return SDValue();
3392
3393 unsigned NumElts = SrcVT.getVectorNumElements();
3394 EVT Width = MVT::getIntegerVT(128 / NumElts);
3395
3396 // bitcast <N x i1> to iN, where N = 2, 4, 8, 16 (legal)
3397 // ==> bitmask
3398 if (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16) {
3399 return DAG.getZExtOrTrunc(
3400 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3401 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32),
3402 DAG.getSExtOrTrunc(N->getOperand(0), DL,
3403 SrcVT.changeVectorElementType(
3404 *DAG.getContext(), Width))}),
3405 DL, VT);
3406 }
3407
3408 // bitcast <N x i1>(setcc ...) to concat iN, where N = 32 and 64 (illegal)
3409 if (NumElts == 32 || NumElts == 64) {
3410 SDValue Concat, SetCCVector;
3411 ISD::CondCode SetCond;
3412
3413 if (!sd_match(N, m_BitCast(m_c_SetCC(m_Value(Concat), m_Value(SetCCVector),
3414 m_CondCode(SetCond)))))
3415 return SDValue();
3416 if (Concat.getOpcode() != ISD::CONCAT_VECTORS)
3417 return SDValue();
3418
3419 // Reconstruct the wide bitmask from each CONCAT_VECTORS operand.
3420 // Derive the per-chunk mask/integer types from the actual operand type
3421 // instead of hardcoding v16i1 / i16 for every chunk.
3422 EVT ConcatOperandVT = Concat.getOperand(0).getValueType();
3423 unsigned ConcatOperandNumElts = ConcatOperandVT.getVectorNumElements();
3424
3425 EVT ConcatOperandMaskVT =
3426 EVT::getVectorVT(*DAG.getContext(), MVT::i1,
3427 ElementCount::getFixed(ConcatOperandNumElts));
3428 EVT ConcatOperandBitmaskVT =
3429 EVT::getIntegerVT(*DAG.getContext(), ConcatOperandNumElts);
3430 EVT ReturnVT = N->getValueType(0);
3431 SDValue ReconstructedBitmask = DAG.getConstant(0, DL, ReturnVT);
3432 // Example:
3433 // v32i16 = concat(v8i16, v8i16, v8i16, v8i16)
3434 // -> v8i1 + v8i1 + v8i1 + v8i1
3435 // -> i8 + i8 + i8 + i8
3436 // -> reconstructed i32 bitmask
3437 for (size_t I = 0; I < Concat->ops().size(); ++I) {
3438 SDValue ConcatOperand = Concat.getOperand(I);
3439 assert(ConcatOperand.getValueType() == ConcatOperandVT &&
3440 "concat_vectors operands must have the same type");
3441
3442 SDValue SetCCVectorOperand =
3443 extractSubVector(SetCCVector, I * ConcatOperandNumElts, DAG, DL, 128);
3444 if (!SetCCVectorOperand ||
3445 SetCCVectorOperand.getValueType() != ConcatOperandVT)
3446 return SDValue();
3447
3448 // Build the per-chunk mask using the correct chunk type:
3449 // v16i8 -> v16i1 -> i16
3450 // v8i16 -> v8i1 -> i8
3451 // v4i32 -> v4i1 -> i4
3452 // v2i64 -> v2i1 -> i2
3453 SDValue ConcatOperandMask = DAG.getSetCC(
3454 DL, ConcatOperandMaskVT, ConcatOperand, SetCCVectorOperand, SetCond);
3455 SDValue ConcatOperandBitmask =
3456 DAG.getBitcast(ConcatOperandBitmaskVT, ConcatOperandMask);
3457 SDValue ExtendedConcatOperandBitmask =
3458 DAG.getZExtOrTrunc(ConcatOperandBitmask, DL, ReturnVT);
3459
3460 // Shift the previously reconstructed bits to make room for this chunk.
3461 if (I != 0) {
3462 ReconstructedBitmask = DAG.getNode(
3463 ISD::SHL, DL, ReturnVT, ReconstructedBitmask,
3464 DAG.getShiftAmountConstant(ConcatOperandNumElts, ReturnVT, DL));
3465 }
3466
3467 // Merge disjoint partial bitmasks with OR.
3468 ReconstructedBitmask =
3469 DAG.getNode(ISD::OR, DL, ReturnVT, ReconstructedBitmask,
3470 ExtendedConcatOperandBitmask);
3471 }
3472
3473 return ReconstructedBitmask;
3474 }
3475
3476 return SDValue();
3477}
3478
3480 // bitmask (setcc <X>, 0, setlt) => bitmask X
3481 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
3482 using namespace llvm::SDPatternMatch;
3483
3484 if (N->getConstantOperandVal(0) != Intrinsic::wasm_bitmask)
3485 return SDValue();
3486
3487 SDValue LHS;
3488 if (!sd_match(N->getOperand(1), m_c_SetCC(m_Value(LHS), m_Zero(),
3490 return SDValue();
3491
3492 SDLoc DL(N);
3493 return DAG.getNode(
3494 ISD::INTRINSIC_WO_CHAIN, DL, N->getValueType(0),
3495 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32), LHS});
3496}
3497
3499 // any_true (setcc <X>, 0, eq) => (not (all_true X))
3500 // all_true (setcc <X>, 0, eq) => (not (any_true X))
3501 // any_true (setcc <X>, 0, ne) => (any_true X)
3502 // all_true (setcc <X>, 0, ne) => (all_true X)
3503 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
3504 using namespace llvm::SDPatternMatch;
3505
3506 SDValue LHS;
3507 if (N->getNumOperands() < 2 ||
3508 !sd_match(N->getOperand(1),
3510 return SDValue();
3511 EVT LT = LHS.getValueType();
3512 if (LT.getScalarSizeInBits() > 128 / LT.getVectorNumElements())
3513 return SDValue();
3514
3515 auto CombineSetCC = [&N, &DAG](Intrinsic::WASMIntrinsics InPre,
3516 ISD::CondCode SetType,
3517 Intrinsic::WASMIntrinsics InPost) {
3518 if (N->getConstantOperandVal(0) != InPre)
3519 return SDValue();
3520
3521 SDValue LHS;
3522 if (!sd_match(N->getOperand(1), m_c_SetCC(m_Value(LHS), m_Zero(),
3523 m_SpecificCondCode(SetType))))
3524 return SDValue();
3525
3526 SDLoc DL(N);
3527 SDValue Ret = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3528 {DAG.getConstant(InPost, DL, MVT::i32), LHS});
3529 if (SetType == ISD::SETEQ)
3530 Ret = DAG.getNode(ISD::XOR, DL, MVT::i32, Ret,
3531 DAG.getConstant(1, DL, MVT::i32));
3532 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3533 };
3534
3535 if (SDValue AnyTrueEQ = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETEQ,
3536 Intrinsic::wasm_alltrue))
3537 return AnyTrueEQ;
3538 if (SDValue AllTrueEQ = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETEQ,
3539 Intrinsic::wasm_anytrue))
3540 return AllTrueEQ;
3541 if (SDValue AnyTrueNE = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETNE,
3542 Intrinsic::wasm_anytrue))
3543 return AnyTrueNE;
3544 if (SDValue AllTrueNE = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETNE,
3545 Intrinsic::wasm_alltrue))
3546 return AllTrueNE;
3547
3548 return SDValue();
3549}
3550
3556
3558 unsigned NumElts,
3559 const MaskReduceInfo &Info,
3560 SelectionDAG &DAG) {
3561 EVT VecVT = FromVT.changeVectorElementType(*DAG.getContext(),
3562 MVT::getIntegerVT(128 / NumElts));
3563 assert(VecVT.getSizeInBits() == 128 &&
3564 "mask reduction should be widened to a 128-bit vector");
3565
3566 SDLoc DL(N);
3567 SDValue Mask = N->getOperand(0)->getOperand(0);
3568 SDValue Ret = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3569 {DAG.getConstant(Info.IID, DL, MVT::i32),
3570 DAG.getSExtOrTrunc(Mask, DL, VecVT)});
3571 if (Info.Invert)
3572 Ret = DAG.getNode(ISD::XOR, DL, MVT::i32, Ret,
3573 DAG.getConstant(1, DL, MVT::i32));
3574 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3575}
3576
3578 unsigned NumElts,
3579 const MaskReduceInfo &Info,
3580 SelectionDAG &DAG) {
3581 assert((NumElts == 32 || NumElts == 64) &&
3582 "combineWideMaskReduction is only for wide masks");
3583 assert(MaskVT.isFixedLengthVector() &&
3584 MaskVT.getVectorElementType() == MVT::i1);
3585 SDLoc DL(N);
3586 unsigned ChunkElts = 16;
3587 EVT ChunkMaskVT = EVT::getVectorVT(*DAG.getContext(), MVT::i1,
3588 ElementCount::getFixed(ChunkElts));
3589 EVT LegalVecVT = ChunkMaskVT.changeVectorElementType(
3590 *DAG.getContext(), MVT::getIntegerVT(128 / ChunkElts));
3591
3592 SmallVector<SDValue, 4> ChunkResults;
3593 // Split the wide mask into v16i1 chunks and reduce each chunk separately.
3594 // For example:
3595 // v32i1: [0..15] [16..31]
3596 // | |
3597 // v v
3598 // chunk0 chunk1
3599 //
3600 // v64i1: [0..15] [16..31] [32..47] [48..63]
3601 // | | | |
3602 // v v v v
3603 // chunk0 chunk1 chunk2 chunk3
3604 //
3605 // each chunk:
3606 // v16i1 -> v16i8 -> wasm_anytrue/alltrue -> i32 0/1
3607 for (unsigned I = 0; I < NumElts; I += ChunkElts) {
3608 SDValue ChunkMask = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ChunkMaskVT,
3609 Mask, DAG.getVectorIdxConstant(I, DL));
3610 SDValue LegalMask = DAG.getSExtOrTrunc(ChunkMask, DL, LegalVecVT);
3611 SDValue Reduced =
3612 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3613 DAG.getConstant(Info.IID, DL, MVT::i32), LegalMask);
3614 ChunkResults.push_back(Reduced);
3615 }
3616
3617 SDValue Acc = ChunkResults[0];
3618 for (unsigned I = 1; I < ChunkResults.size(); ++I)
3619 Acc =
3620 DAG.getNode(Info.WideCombineOpcode, DL, MVT::i32, Acc, ChunkResults[I]);
3621
3622 if (Info.Invert)
3623 Acc = DAG.getNode(ISD::XOR, DL, MVT::i32, Acc,
3624 DAG.getConstant(1, DL, MVT::i32));
3625
3626 return DAG.getZExtOrTrunc(Acc, DL, N->getValueType(0));
3627}
3628
3629static std::optional<MaskReduceInfo> classifyMaskReduction(SDNode *N) {
3630 auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
3631 if (!C)
3632 return std::nullopt;
3633
3634 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
3635
3636 // setcc (bitcast mask), 0, ne -> any_true(mask)
3637 if (C->isZero() && CC == ISD::SETNE)
3638 return MaskReduceInfo{Intrinsic::wasm_anytrue, ISD::OR, false};
3639
3640 // setcc (bitcast mask), 0, eq -> !any_true(mask)
3641 if (C->isZero() && CC == ISD::SETEQ)
3642 return MaskReduceInfo{Intrinsic::wasm_anytrue, ISD::OR, true};
3643
3644 // setcc (bitcast mask), -1, eq -> all_true(mask)
3645 if (C->isAllOnes() && CC == ISD::SETEQ)
3646 return MaskReduceInfo{Intrinsic::wasm_alltrue, ISD::AND, false};
3647
3648 // setcc (bitcast mask), -1, ne -> !all_true(mask)
3649 if (C->isAllOnes() && CC == ISD::SETNE)
3650 return MaskReduceInfo{Intrinsic::wasm_alltrue, ISD::AND, true};
3651
3652 return std::nullopt;
3653}
3654
3655/// Try to convert a i128 comparison to a v16i8 comparison before type
3656/// legalization splits it up into chunks
3657static SDValue
3659 const WebAssemblySubtarget *Subtarget) {
3660
3661 SDLoc DL(N);
3662 SDValue X = N->getOperand(0);
3663 SDValue Y = N->getOperand(1);
3664 EVT VT = N->getValueType(0);
3665 EVT OpVT = X.getValueType();
3666
3667 SelectionDAG &DAG = DCI.DAG;
3669 Attribute::NoImplicitFloat))
3670 return SDValue();
3671
3672 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
3673 // We're looking for an oversized integer equality comparison with SIMD
3674 if (!OpVT.isScalarInteger() || !OpVT.isByteSized() || OpVT != MVT::i128 ||
3675 !Subtarget->hasSIMD128() || !isIntEqualitySetCC(CC))
3676 return SDValue();
3677
3678 // Don't perform this combine if constructing the vector will be expensive.
3679 auto IsVectorBitCastCheap = [](SDValue X) {
3681 return isa<ConstantSDNode>(X) || X.getOpcode() == ISD::LOAD;
3682 };
3683
3684 if (!IsVectorBitCastCheap(X) || !IsVectorBitCastCheap(Y))
3685 return SDValue();
3686
3687 SDValue VecX = DAG.getBitcast(MVT::v16i8, X);
3688 SDValue VecY = DAG.getBitcast(MVT::v16i8, Y);
3689 SDValue Cmp = DAG.getSetCC(DL, MVT::v16i8, VecX, VecY, CC);
3690
3691 SDValue Intr =
3692 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3693 {DAG.getConstant(CC == ISD::SETEQ ? Intrinsic::wasm_alltrue
3694 : Intrinsic::wasm_anytrue,
3695 DL, MVT::i32),
3696 Cmp});
3697
3698 return DAG.getSetCC(DL, VT, Intr, DAG.getConstant(0, DL, MVT::i32),
3699 ISD::SETNE);
3700}
3701
3704 const WebAssemblySubtarget *Subtarget) {
3705 if (!DCI.isBeforeLegalize())
3706 return SDValue();
3707
3708 EVT VT = N->getValueType(0);
3709 if (!VT.isScalarInteger())
3710 return SDValue();
3711
3712 if (SDValue V = combineVectorSizedSetCCEquality(N, DCI, Subtarget))
3713 return V;
3714
3715 SDValue LHS = N->getOperand(0);
3716 if (LHS->getOpcode() != ISD::BITCAST)
3717 return SDValue();
3718
3719 EVT FromVT = LHS->getOperand(0).getValueType();
3720 if (!FromVT.isFixedLengthVectorOf(MVT::i1))
3721 return SDValue();
3722
3723 unsigned NumElts = FromVT.getVectorNumElements();
3724 auto Info = classifyMaskReduction(N);
3725 if (!Info)
3726 return SDValue();
3727
3728 auto &DAG = DCI.DAG;
3729 if (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16)
3730 return combineSmallMaskReduction(N, FromVT, NumElts, *Info, DAG);
3731
3732 if (NumElts == 32 || NumElts == 64)
3733 return combineWideMaskReduction(N, LHS.getOperand(0), FromVT, NumElts,
3734 *Info, DAG);
3735
3736 return SDValue();
3737}
3738
3740 EVT VT = N->getValueType(0);
3741 if (VT != MVT::v8i32 && VT != MVT::v16i32)
3742 return SDValue();
3743
3744 // Mul with extending inputs.
3745 SDValue LHS = N->getOperand(0);
3746 SDValue RHS = N->getOperand(1);
3747 if (LHS.getOpcode() != RHS.getOpcode())
3748 return SDValue();
3749
3750 if (LHS.getOpcode() != ISD::SIGN_EXTEND &&
3751 LHS.getOpcode() != ISD::ZERO_EXTEND)
3752 return SDValue();
3753
3754 if (LHS->getOperand(0).getValueType() != RHS->getOperand(0).getValueType())
3755 return SDValue();
3756
3757 EVT FromVT = LHS->getOperand(0).getValueType();
3758 EVT EltTy = FromVT.getVectorElementType();
3759 if (EltTy != MVT::i8)
3760 return SDValue();
3761
3762 // For an input DAG that looks like this
3763 // %a = input_type
3764 // %b = input_type
3765 // %lhs = extend %a to output_type
3766 // %rhs = extend %b to output_type
3767 // %mul = mul %lhs, %rhs
3768
3769 // input_type | output_type | instructions
3770 // v16i8 | v16i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3771 // | | %high = i16x8.extmul_high_i8x16_, %a, %b
3772 // | | %low_low = i32x4.ext_low_i16x8_ %low
3773 // | | %low_high = i32x4.ext_high_i16x8_ %low
3774 // | | %high_low = i32x4.ext_low_i16x8_ %high
3775 // | | %high_high = i32x4.ext_high_i16x8_ %high
3776 // | | %res = concat_vector(...)
3777 // v8i8 | v8i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3778 // | | %low_low = i32x4.ext_low_i16x8_ %low
3779 // | | %low_high = i32x4.ext_high_i16x8_ %low
3780 // | | %res = concat_vector(%low_low, %low_high)
3781
3782 SDLoc DL(N);
3783 unsigned NumElts = VT.getVectorNumElements();
3784 SDValue ExtendInLHS = LHS->getOperand(0);
3785 SDValue ExtendInRHS = RHS->getOperand(0);
3786 bool IsSigned = LHS->getOpcode() == ISD::SIGN_EXTEND;
3787 unsigned ExtendLowOpc =
3788 IsSigned ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3789 unsigned ExtendHighOpc =
3790 IsSigned ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
3791
3792 auto GetExtendLow = [&DAG, &DL, &ExtendLowOpc](EVT VT, SDValue Op) {
3793 return DAG.getNode(ExtendLowOpc, DL, VT, Op);
3794 };
3795 auto GetExtendHigh = [&DAG, &DL, &ExtendHighOpc](EVT VT, SDValue Op) {
3796 return DAG.getNode(ExtendHighOpc, DL, VT, Op);
3797 };
3798
3799 if (NumElts == 16) {
3800 SDValue LowLHS = GetExtendLow(MVT::v8i16, ExtendInLHS);
3801 SDValue LowRHS = GetExtendLow(MVT::v8i16, ExtendInRHS);
3802 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3803 SDValue HighLHS = GetExtendHigh(MVT::v8i16, ExtendInLHS);
3804 SDValue HighRHS = GetExtendHigh(MVT::v8i16, ExtendInRHS);
3805 SDValue MulHigh = DAG.getNode(ISD::MUL, DL, MVT::v8i16, HighLHS, HighRHS);
3806 SDValue SubVectors[] = {
3807 GetExtendLow(MVT::v4i32, MulLow),
3808 GetExtendHigh(MVT::v4i32, MulLow),
3809 GetExtendLow(MVT::v4i32, MulHigh),
3810 GetExtendHigh(MVT::v4i32, MulHigh),
3811 };
3812 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, SubVectors);
3813 } else {
3814 assert(NumElts == 8);
3815 SDValue LowLHS = DAG.getNode(LHS->getOpcode(), DL, MVT::v8i16, ExtendInLHS);
3816 SDValue LowRHS = DAG.getNode(RHS->getOpcode(), DL, MVT::v8i16, ExtendInRHS);
3817 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3818 SDValue Lo = GetExtendLow(MVT::v4i32, MulLow);
3819 SDValue Hi = GetExtendHigh(MVT::v4i32, MulLow);
3820 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
3821 }
3822 return SDValue();
3823}
3824
3827 assert(N->getOpcode() == ISD::MUL);
3828 EVT VT = N->getValueType(0);
3829 if (!VT.isVector())
3830 return SDValue();
3831
3832 if (auto Res = TryWideExtMulCombine(N, DCI.DAG))
3833 return Res;
3834
3835 // We don't natively support v16i8 or v8i8 mul, but we do support v8i16. So,
3836 // extend them to v8i16.
3837 if (VT != MVT::v8i8 && VT != MVT::v16i8)
3838 return SDValue();
3839
3840 SDLoc DL(N);
3841 SelectionDAG &DAG = DCI.DAG;
3842 SDValue LHS = N->getOperand(0);
3843 SDValue RHS = N->getOperand(1);
3844 EVT MulVT = MVT::v8i16;
3845
3846 if (VT == MVT::v8i8) {
3847 SDValue PromotedLHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, LHS,
3848 DAG.getUNDEF(MVT::v8i8));
3849 SDValue PromotedRHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, RHS,
3850 DAG.getUNDEF(MVT::v8i8));
3851 SDValue LowLHS =
3852 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedLHS);
3853 SDValue LowRHS =
3854 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedRHS);
3855 SDValue MulLow = DAG.getBitcast(
3856 MVT::v16i8, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3857 // Take the low byte of each lane.
3858 SDValue Shuffle = DAG.getVectorShuffle(
3859 MVT::v16i8, DL, MulLow, DAG.getUNDEF(MVT::v16i8),
3860 {0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1});
3861 return extractSubVector(Shuffle, 0, DAG, DL, 64);
3862 } else {
3863 assert(VT == MVT::v16i8 && "Expected v16i8");
3864 SDValue LowLHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, LHS);
3865 SDValue LowRHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, RHS);
3866 SDValue HighLHS =
3867 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, LHS);
3868 SDValue HighRHS =
3869 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, RHS);
3870
3871 SDValue MulLow =
3872 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3873 SDValue MulHigh =
3874 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, HighLHS, HighRHS));
3875
3876 // Take the low byte of each lane.
3877 return DAG.getVectorShuffle(
3878 VT, DL, MulLow, MulHigh,
3879 {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30});
3880 }
3881}
3882
3883SDValue DoubleVectorWidth(SDValue In, unsigned RequiredNumElems,
3884 SelectionDAG &DAG) {
3885 SDLoc DL(In);
3886 LLVMContext &Ctx = *DAG.getContext();
3887 EVT InVT = In.getValueType();
3888 unsigned NumElems = InVT.getVectorNumElements() * 2;
3889 EVT OutVT = EVT::getVectorVT(Ctx, InVT.getVectorElementType(), NumElems);
3890 SDValue Concat =
3891 DAG.getNode(ISD::CONCAT_VECTORS, DL, OutVT, In, DAG.getPOISON(InVT));
3892 if (NumElems < RequiredNumElems) {
3893 return DoubleVectorWidth(Concat, RequiredNumElems, DAG);
3894 }
3895 return Concat;
3896}
3897
3899 EVT OutVT = N->getValueType(0);
3900 if (!OutVT.isVector())
3901 return SDValue();
3902
3903 EVT OutElTy = OutVT.getVectorElementType();
3904 if (OutElTy != MVT::i8 && OutElTy != MVT::i16)
3905 return SDValue();
3906
3907 unsigned NumElems = OutVT.getVectorNumElements();
3908 if (!isPowerOf2_32(NumElems))
3909 return SDValue();
3910
3911 EVT FPVT = N->getOperand(0)->getValueType(0);
3912 if (FPVT.getVectorElementType() != MVT::f32)
3913 return SDValue();
3914
3915 SDLoc DL(N);
3916
3917 // First, convert to i32.
3918 LLVMContext &Ctx = *DAG.getContext();
3919 EVT IntVT = EVT::getVectorVT(Ctx, MVT::i32, NumElems);
3920 SDValue ToInt = DAG.getNode(N->getOpcode(), DL, IntVT, N->getOperand(0));
3922 OutVT.getScalarSizeInBits());
3923 // Mask out the top MSBs.
3924 SDValue Masked =
3925 DAG.getNode(ISD::AND, DL, IntVT, ToInt, DAG.getConstant(Mask, DL, IntVT));
3926
3927 if (OutVT.getSizeInBits() < 128) {
3928 // Create a wide enough vector that we can use narrow.
3929 EVT NarrowedVT = OutElTy == MVT::i8 ? MVT::v16i8 : MVT::v8i16;
3930 unsigned NumRequiredElems = NarrowedVT.getVectorNumElements();
3931 SDValue WideVector = DoubleVectorWidth(Masked, NumRequiredElems, DAG);
3932 SDValue Trunc = truncateVectorWithNARROW(NarrowedVT, WideVector, DL, DAG);
3933 return DAG.getBitcast(
3934 OutVT, extractSubVector(Trunc, 0, DAG, DL, OutVT.getSizeInBits()));
3935 } else {
3936 return truncateVectorWithNARROW(OutVT, Masked, DL, DAG);
3937 }
3938 return SDValue();
3939}
3940
3941// Wide vector shift operations such as v8i32 with sign-extended
3942// operands cause Type Legalizer crashes because the target-specific
3943// extension nodes cannot be directly mapped to the 256-bit size.
3944//
3945// To resolve the crash and optimize performance, we intercept the
3946// illegal v8i32 shift in DAGCombine. We convert the shift amounts
3947// into multipliers and manually split the vector into two v4i32 halves.
3948//
3949// Before: t1: v8i32 = shl (sign_extend v8i16), const_vec
3950// After : t2: v4i32 = mul (ext_low_s v8i16), (ext_low_s narrow_vec)
3951// t3: v4i32 = mul (ext_high_s v8i16), (ext_high_s narrow_vec)
3952// t4: v8i32 = concat_vectors t2, t3
3955 SelectionDAG &DAG = DCI.DAG;
3956 assert(N->getOpcode() == ISD::SHL);
3957 EVT VT = N->getValueType(0);
3958 if (VT != MVT::v8i32)
3959 return SDValue();
3960
3961 SDValue LHS = N->getOperand(0);
3962 SDValue RHS = N->getOperand(1);
3963 unsigned ExtOpc = LHS.getOpcode();
3964 if (ExtOpc != ISD::SIGN_EXTEND && ExtOpc != ISD::ZERO_EXTEND)
3965 return SDValue();
3966
3967 if (RHS.getOpcode() != ISD::BUILD_VECTOR)
3968 return SDValue();
3969
3970 SDLoc DL(N);
3971 SDValue ExtendIn = LHS.getOperand(0);
3972 EVT FromVT = ExtendIn.getValueType();
3973 if (FromVT != MVT::v8i16)
3974 return SDValue();
3975
3976 unsigned NumElts = VT.getVectorNumElements();
3977 unsigned BitWidth = FromVT.getScalarSizeInBits();
3978 bool IsSigned = (ExtOpc == ISD::SIGN_EXTEND);
3979 unsigned MaxValidShift = IsSigned ? (BitWidth - 1) : BitWidth;
3980 SmallVector<SDValue, 16> MulConsts;
3981 for (unsigned I = 0; I < NumElts; ++I) {
3982 auto *C = dyn_cast<ConstantSDNode>(RHS.getOperand(I));
3983 if (!C)
3984 return SDValue();
3985
3986 const APInt &ShiftAmt = C->getAPIntValue();
3987 if (ShiftAmt.uge(MaxValidShift))
3988 return SDValue();
3989
3990 APInt MulAmt = APInt::getOneBitSet(BitWidth, ShiftAmt.getZExtValue());
3991 MulConsts.push_back(DAG.getConstant(MulAmt, DL, FromVT.getScalarType(),
3992 /*isTarget=*/false, /*isOpaque=*/true));
3993 }
3994
3995 SDValue NarrowConst = DAG.getBuildVector(FromVT, DL, MulConsts);
3996 unsigned ExtLowOpc =
3997 IsSigned ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3998 unsigned ExtHighOpc =
3999 IsSigned ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
4000
4001 EVT HalfVT = MVT::v4i32;
4002 SDValue LHSLo = DAG.getNode(ExtLowOpc, DL, HalfVT, ExtendIn);
4003 SDValue LHSHi = DAG.getNode(ExtHighOpc, DL, HalfVT, ExtendIn);
4004 SDValue RHSLo = DAG.getNode(ExtLowOpc, DL, HalfVT, NarrowConst);
4005 SDValue RHSHi = DAG.getNode(ExtHighOpc, DL, HalfVT, NarrowConst);
4006 SDValue MulLo = DAG.getNode(ISD::MUL, DL, HalfVT, LHSLo, RHSLo);
4007 SDValue MulHi = DAG.getNode(ISD::MUL, DL, HalfVT, LHSHi, RHSHi);
4008 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, MulLo, MulHi);
4009}
4010
4012 if (N->getValueType(0) != MVT::f128)
4013 return SDValue();
4014
4015 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
4016 switch (N->getOpcode()) {
4017 // wasi-libc and emscripten do not currently define fminimuml and fmaximuml.
4018 case ISD::FMINIMUM:
4019 case ISD::FMAXIMUM:
4020 return TLI.expandFMINIMUM_FMAXIMUM(N, DAG);
4021
4022 // wasi-libc and emscripten do not currently define fminimum_numl and
4023 // fmaximum_numl.
4024 case ISD::FMINIMUMNUM:
4025 case ISD::FMAXIMUMNUM:
4026 return TLI.expandFMINIMUMNUM_FMAXIMUMNUM(N, DAG);
4027
4028 default:
4029 return SDValue();
4030 }
4031}
4032
4033SDValue
4034WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
4035 DAGCombinerInfo &DCI) const {
4036 switch (N->getOpcode()) {
4037 default:
4038 return SDValue();
4039 case ISD::BITCAST:
4040 return performBitcastCombine(N, DCI);
4041 case ISD::SETCC:
4042 return performSETCCCombine(N, DCI, Subtarget);
4044 return performVECTOR_SHUFFLECombine(N, DCI);
4045 case ISD::SIGN_EXTEND:
4046 case ISD::ZERO_EXTEND:
4047 return performVectorExtendCombine(N, DCI);
4048 case ISD::UINT_TO_FP:
4049 if (auto ExtCombine = performVectorExtendToFPCombine(N, DCI, Subtarget))
4050 return ExtCombine;
4051 return performVectorNonNegToFPCombine(N, DCI);
4052 case ISD::SINT_TO_FP:
4053 return performVectorExtendToFPCombine(N, DCI, Subtarget);
4056 case ISD::FP_ROUND:
4058 return performVectorTruncZeroCombine(N, DCI);
4059 case ISD::FP_TO_SINT:
4060 case ISD::FP_TO_UINT:
4061 return performConvertFPCombine(N, DCI.DAG);
4062 case ISD::TRUNCATE:
4063 return performTruncateCombine(N, DCI);
4065 if (SDValue V = performBitmaskCombine(N, DCI.DAG))
4066 return V;
4067 return performAnyAllCombine(N, DCI.DAG);
4068 }
4069 case ISD::MUL:
4070 return performMulCombine(N, DCI);
4071 case ISD::SHL:
4072 return performShiftCombine(N, DCI);
4073 case ISD::FMINIMUM:
4074 case ISD::FMAXIMUM:
4075 case ISD::FMINIMUMNUM:
4076 case ISD::FMAXIMUMNUM:
4077 return performMinMaxF128Combine(N, DCI.DAG);
4078 }
4079}
static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const AArch64Subtarget *Subtarget)
static SDValue performTruncateCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned 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:857
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...
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:305
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:356
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:730
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:68
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 uses()
Returns all operands which may be register 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,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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...
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...
SDValue expandFMINIMUMNUM_FMAXIMUMNUM(SDNode *N, SelectionDAG &DAG) const
Expand fminimumnum/fmaximumnum into multiple comparison with selects.
SDValue expandFMINIMUM_FMAXIMUM(SDNode *N, SelectionDAG &DAG) const
Expand fminimum/fmaximum into multiple comparison with selects.
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:717
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:829
@ 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:275
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:789
@ 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:294
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ 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:520
@ 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:220
@ GlobalAddress
Definition ISDOpcodes.h:88
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:890
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:586
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:749
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition ISDOpcodes.h:920
@ SDIVREM
SDIVREM/UDIVREM - Divide two integers and produce both a quotient and remainder result.
Definition ISDOpcodes.h:280
@ 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:530
@ 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:254
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:89
@ PARTIAL_REDUCE_UMLA
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:854
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:667
@ 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:374
@ EXTRACT_ELEMENT
EXTRACT_ELEMENT - This is used to get the lower or upper (determined by a Constant,...
Definition ISDOpcodes.h:247
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition ISDOpcodes.h:674
@ 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:706
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:771
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:651
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:616
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:578
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:224
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:860
@ 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:821
@ FMINNUM
FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values, following IEEE-754 definition...
@ 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:909
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:898
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:729
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:988
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:110
@ FMINIMUM
FMINIMUM/FMAXIMUM - NaN-propagating minimum/maximum that also treat -0.0 as less than 0....
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:936
@ TargetConstant
TargetConstant* - Like Constant*, but the DAG does not do any folding, simplification,...
Definition ISDOpcodes.h:179
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:741
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:205
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:304
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:567
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:53
@ ExternalSymbol
Definition ISDOpcodes.h:93
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:969
@ 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:931
@ 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:955
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:866
@ 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:843
@ FCOPYSIGN
FCOPYSIGN(X, Y) - Return the value of X with the sign of Y.
Definition ISDOpcodes.h:536
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:365
@ FMINIMUMNUM
FMINIMUMNUM/FMAXIMUMNUM - minimumnum/maximumnum that is same with FMINNUM_IEEE and FMAXNUM_IEEE besid...
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:213
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:558
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.
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P)
CondCode_match m_SpecificCondCode(ISD::CondCode CC)
Match a conditional code SDNode with a specific ISD::CondCode.
CondCode_match m_CondCode()
Match any conditional code SDNode.
TernaryOpc_match< T0_P, T1_P, T2_P, true, false > m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
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.
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
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:145
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:155
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
bool isByteSized() const
Return true if the bit size is a multiple of 8.
Definition ValueTypes.h:266
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
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:339
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:230
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:404
EVT widenIntegerVectorElementType(LLVMContext &Context) const
Return a VT for an integer vector type with the size of the elements doubled.
Definition ValueTypes.h:475
bool isFixedLengthVector() const
Definition ValueTypes.h:199
bool isFixedLengthVectorOf(EVT EltVT) const
Return true if this is a fixed length vector with matching element type.
Definition ValueTypes.h:205
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
bool bitsGE(EVT VT) const
Return true if this has no less bits than VT.
Definition ValueTypes.h:315
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:235
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:351
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:121
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:484
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.