LLVM 21.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
31#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), Subtarget(&STI) {
46 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
47
48 // Booleans always contain 0 or 1.
50 // Except in SIMD vectors
52 // We don't know the microarchitecture here, so just reduce register pressure.
54 // Tell ISel that we have a stack pointer.
56 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
57 // Set up the register classes.
58 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
59 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
60 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
61 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
62 if (Subtarget->hasSIMD128()) {
63 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
64 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
65 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
66 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
67 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
68 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
69 }
70 if (Subtarget->hasFP16()) {
71 addRegisterClass(MVT::v8f16, &WebAssembly::V128RegClass);
72 }
73 if (Subtarget->hasReferenceTypes()) {
74 addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
75 addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);
76 if (Subtarget->hasExceptionHandling()) {
77 addRegisterClass(MVT::exnref, &WebAssembly::EXNREFRegClass);
78 }
79 }
80 // Compute derived properties from the register classes.
82
83 // Transform loads and stores to pointers in address space 1 to loads and
84 // stores to WebAssembly global variables, outside linear memory.
85 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) {
88 }
89 if (Subtarget->hasSIMD128()) {
90 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
91 MVT::v2f64}) {
94 }
95 }
96 if (Subtarget->hasFP16()) {
99 }
100 if (Subtarget->hasReferenceTypes()) {
101 // We need custom load and store lowering for both externref, funcref and
102 // Other. The MVT::Other here represents tables of reference types.
103 for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) {
106 }
107 }
108
116
117 // Take the default expansion for va_arg, va_copy, and va_end. There is no
118 // default action for va_start, so we do that custom.
123
124 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
125 // Don't expand the floating-point types to constant pools.
127 // Expand floating-point comparisons.
131 // Expand floating-point library function operators.
132 for (auto Op :
135 // Note supported floating-point library function operators that otherwise
136 // default to expand.
140 // Support minimum and maximum, which otherwise default to expand.
143 // WebAssembly currently has no builtin f16 support.
147 setTruncStoreAction(T, MVT::f16, Expand);
148 }
149
150 if (Subtarget->hasFP16()) {
153 }
154
155 // Expand unavailable integer operations.
156 for (auto Op :
160 for (auto T : {MVT::i32, MVT::i64})
162 if (Subtarget->hasSIMD128())
163 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
165 }
166
167 if (Subtarget->hasWideArithmetic()) {
172 }
173
174 if (Subtarget->hasNontrappingFPToInt())
176 for (auto T : {MVT::i32, MVT::i64})
178
179 // SIMD-specific configuration
180 if (Subtarget->hasSIMD128()) {
181
182 // Combine partial.reduce.add before legalization gets confused.
184
185 // Combine vector mask reductions into alltrue/anytrue
187
188 // Convert vector to integer bitcasts to bitmask
190
191 // Hoist bitcasts out of shuffles
193
194 // Combine extends of extract_subvectors into widening ops
196
197 // Combine int_to_fp or fp_extend of extract_vectors and vice versa into
198 // conversions ops
201
202 // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa
203 // into conversion ops
206
208
209 // Support saturating add/sub for i8x16 and i16x8
211 for (auto T : {MVT::v16i8, MVT::v8i16})
213
214 // Support integer abs
215 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
217
218 // Custom lower BUILD_VECTORs to minimize number of replace_lanes
219 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
220 MVT::v2f64})
222
223 if (Subtarget->hasFP16())
225
226 // We have custom shuffle lowering to expose the shuffle mask
227 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
228 MVT::v2f64})
230
231 // Support splatting
232 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
233 MVT::v2f64})
235
236 // Custom lowering since wasm shifts must have a scalar shift amount
237 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
238 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
240
241 // Custom lower lane accesses to expand out variable indices
243 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
244 MVT::v2f64})
246
247 // There is no i8x16.mul instruction
248 setOperationAction(ISD::MUL, MVT::v16i8, Expand);
249
250 // There is no vector conditional select instruction
251 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
252 MVT::v2f64})
254
255 // Expand integer operations supported for scalars but not SIMD
256 for (auto Op :
258 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
260
261 // But we do have integer min and max operations
262 for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
263 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
265
266 // And we have popcnt for i8x16. It can be used to expand ctlz/cttz.
267 setOperationAction(ISD::CTPOP, MVT::v16i8, Legal);
268 setOperationAction(ISD::CTLZ, MVT::v16i8, Expand);
269 setOperationAction(ISD::CTTZ, MVT::v16i8, Expand);
270
271 // Custom lower bit counting operations for other types to scalarize them.
272 for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP})
273 for (auto T : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
275
276 // Expand float operations supported for scalars but not SIMD
279 for (auto T : {MVT::v4f32, MVT::v2f64})
281
282 // Unsigned comparison operations are unavailable for i64x2 vectors.
284 setCondCodeAction(CC, MVT::v2i64, Custom);
285
286 // 64x2 conversions are not in the spec
287 for (auto Op :
289 for (auto T : {MVT::v2i64, MVT::v2f64})
291
292 // But saturating fp_to_int converstions are
294 setOperationAction(Op, MVT::v4i32, Custom);
295 if (Subtarget->hasFP16()) {
296 setOperationAction(Op, MVT::v8i16, Custom);
297 }
298 }
299
300 // Support vector extending
304 }
305 }
306
307 // As a special case, these operators use the type to mean the type to
308 // sign-extend from.
310 if (!Subtarget->hasSignExt()) {
311 // Sign extends are legal only when extending a vector extract
312 auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
313 for (auto T : {MVT::i8, MVT::i16, MVT::i32})
315 }
318
319 // Dynamic stack allocation: use the default expansion.
323
327
328 // Expand these forms; we pattern-match the forms that we can handle in isel.
329 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
330 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
332
333 // We have custom switch handling.
335
336 // WebAssembly doesn't have:
337 // - Floating-point extending loads.
338 // - Floating-point truncating stores.
339 // - i1 extending loads.
340 // - truncating SIMD stores and most extending loads
341 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
342 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
343 for (auto T : MVT::integer_valuetypes())
344 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
345 setLoadExtAction(Ext, T, MVT::i1, Promote);
346 if (Subtarget->hasSIMD128()) {
347 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
348 MVT::v2f64}) {
349 for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
350 if (MVT(T) != MemT) {
352 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
353 setLoadExtAction(Ext, T, MemT, Expand);
354 }
355 }
356 }
357 // But some vector extending loads are legal
358 for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
359 setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
360 setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
361 setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
362 }
363 setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal);
364 }
365
366 // Don't do anything clever with build_pairs
368
369 // Trap lowers to wasm unreachable
370 setOperationAction(ISD::TRAP, MVT::Other, Legal);
372
373 // Exception handling intrinsics
377
379
380 // Override the __gnu_f2h_ieee/__gnu_h2f_ieee names so that the f32 name is
381 // consistent with the f64 and f128 names.
382 setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
383 setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
384
385 // Define the emscripten name for return address helper.
386 // TODO: when implementing other Wasm backends, make this generic or only do
387 // this on emscripten depending on what they end up doing.
388 setLibcallName(RTLIB::RETURN_ADDRESS, "emscripten_return_address");
389
390 // Always convert switches to br_tables unless there is only one case, which
391 // is equivalent to a simple branch. This reduces code size for wasm, and we
392 // defer possible jump table optimizations to the VM.
394}
395
397 uint32_t AS) const {
399 return MVT::externref;
401 return MVT::funcref;
403}
404
406 uint32_t AS) const {
408 return MVT::externref;
410 return MVT::funcref;
412}
413
414bool WebAssemblyTargetLowering::shouldExpandPartialReductionIntrinsic(
415 const IntrinsicInst *I) const {
416 if (I->getIntrinsicID() != Intrinsic::experimental_vector_partial_reduce_add)
417 return true;
418
419 EVT VT = EVT::getEVT(I->getType());
420 auto Op1 = I->getOperand(1);
421
422 if (auto *InputInst = dyn_cast<Instruction>(Op1)) {
423 if (InstructionOpcodeToISD(InputInst->getOpcode()) != ISD::MUL)
424 return true;
425
426 if (isa<Instruction>(InputInst->getOperand(0)) &&
427 isa<Instruction>(InputInst->getOperand(1))) {
428 // dot only supports signed inputs but also support lowering unsigned.
429 if (cast<Instruction>(InputInst->getOperand(0))->getOpcode() !=
430 cast<Instruction>(InputInst->getOperand(1))->getOpcode())
431 return true;
432
433 EVT Op1VT = EVT::getEVT(Op1->getType());
434 if (Op1VT.getVectorElementType() == VT.getVectorElementType() &&
435 ((VT.getVectorElementCount() * 2 == Op1VT.getVectorElementCount()) ||
436 (VT.getVectorElementCount() * 4 == Op1VT.getVectorElementCount())))
437 return false;
438 }
439 }
440 return true;
441}
442
444WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
445 // We have wasm instructions for these
446 switch (AI->getOperation()) {
454 default:
455 break;
456 }
458}
459
460bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const {
461 // Implementation copied from X86TargetLowering.
462 unsigned Opc = VecOp.getOpcode();
463
464 // Assume target opcodes can't be scalarized.
465 // TODO - do we have any exceptions?
466 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
467 return false;
468
469 // If the vector op is not supported, try to convert to scalar.
470 EVT VecVT = VecOp.getValueType();
471 if (!isOperationLegalOrCustomOrPromote(Opc, VecVT))
472 return true;
473
474 // If the vector op is supported, but the scalar op is not, the transform may
475 // not be worthwhile.
476 EVT ScalarVT = VecVT.getScalarType();
477 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
478}
479
480FastISel *WebAssemblyTargetLowering::createFastISel(
481 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
482 return WebAssembly::createFastISel(FuncInfo, LibInfo);
483}
484
485MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
486 EVT VT) const {
487 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
488 if (BitWidth > 1 && BitWidth < 8)
489 BitWidth = 8;
490
491 if (BitWidth > 64) {
492 // The shift will be lowered to a libcall, and compiler-rt libcalls expect
493 // the count to be an i32.
494 BitWidth = 32;
496 "32-bit shift counts ought to be enough for anyone");
497 }
498
501 "Unable to represent scalar shift amount type");
502 return Result;
503}
504
505// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
506// undefined result on invalid/overflow, to the WebAssembly opcode, which
507// traps on invalid/overflow.
510 const TargetInstrInfo &TII,
511 bool IsUnsigned, bool Int64,
512 bool Float64, unsigned LoweredOpcode) {
514
515 Register OutReg = MI.getOperand(0).getReg();
516 Register InReg = MI.getOperand(1).getReg();
517
518 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
519 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
520 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
521 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
522 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
523 unsigned Eqz = WebAssembly::EQZ_I32;
524 unsigned And = WebAssembly::AND_I32;
525 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
526 int64_t Substitute = IsUnsigned ? 0 : Limit;
527 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
528 auto &Context = BB->getParent()->getFunction().getContext();
529 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
530
531 const BasicBlock *LLVMBB = BB->getBasicBlock();
532 MachineFunction *F = BB->getParent();
533 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
534 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
535 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
536
538 F->insert(It, FalseMBB);
539 F->insert(It, TrueMBB);
540 F->insert(It, DoneMBB);
541
542 // Transfer the remainder of BB and its successor edges to DoneMBB.
543 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
545
546 BB->addSuccessor(TrueMBB);
547 BB->addSuccessor(FalseMBB);
548 TrueMBB->addSuccessor(DoneMBB);
549 FalseMBB->addSuccessor(DoneMBB);
550
551 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
552 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
553 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
554 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
555 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
556 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
557 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
558
559 MI.eraseFromParent();
560 // For signed numbers, we can do a single comparison to determine whether
561 // fabs(x) is within range.
562 if (IsUnsigned) {
563 Tmp0 = InReg;
564 } else {
565 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
566 }
567 BuildMI(BB, DL, TII.get(FConst), Tmp1)
568 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
569 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
570
571 // For unsigned numbers, we have to do a separate comparison with zero.
572 if (IsUnsigned) {
573 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
574 Register SecondCmpReg =
575 MRI.createVirtualRegister(&WebAssembly::I32RegClass);
576 Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
577 BuildMI(BB, DL, TII.get(FConst), Tmp1)
578 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
579 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
580 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
581 CmpReg = AndReg;
582 }
583
584 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
585
586 // Create the CFG diamond to select between doing the conversion or using
587 // the substitute value.
588 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
589 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
590 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
591 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
592 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
593 .addReg(FalseReg)
594 .addMBB(FalseMBB)
595 .addReg(TrueReg)
596 .addMBB(TrueMBB);
597
598 return DoneMBB;
599}
600
601// Lower a `MEMCPY` instruction into a CFG triangle around a `MEMORY_COPY`
602// instuction to handle the zero-length case.
605 const TargetInstrInfo &TII, bool Int64) {
607
608 MachineOperand DstMem = MI.getOperand(0);
609 MachineOperand SrcMem = MI.getOperand(1);
610 MachineOperand Dst = MI.getOperand(2);
611 MachineOperand Src = MI.getOperand(3);
612 MachineOperand Len = MI.getOperand(4);
613
614 // We're going to add an extra use to `Len` to test if it's zero; that
615 // use shouldn't be a kill, even if the original use is.
616 MachineOperand NoKillLen = Len;
617 NoKillLen.setIsKill(false);
618
619 // Decide on which `MachineInstr` opcode we're going to use.
620 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
621 unsigned MemoryCopy =
622 Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
623
624 // Create two new basic blocks; one for the new `memory.fill` that we can
625 // branch over, and one for the rest of the instructions after the original
626 // `memory.fill`.
627 const BasicBlock *LLVMBB = BB->getBasicBlock();
628 MachineFunction *F = BB->getParent();
629 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
630 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
631
633 F->insert(It, TrueMBB);
634 F->insert(It, DoneMBB);
635
636 // Transfer the remainder of BB and its successor edges to DoneMBB.
637 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
639
640 // Connect the CFG edges.
641 BB->addSuccessor(TrueMBB);
642 BB->addSuccessor(DoneMBB);
643 TrueMBB->addSuccessor(DoneMBB);
644
645 // Create a virtual register for the `Eqz` result.
646 unsigned EqzReg;
647 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
648
649 // Erase the original `memory.copy`.
650 MI.eraseFromParent();
651
652 // Test if `Len` is zero.
653 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
654
655 // Insert a new `memory.copy`.
656 BuildMI(TrueMBB, DL, TII.get(MemoryCopy))
657 .add(DstMem)
658 .add(SrcMem)
659 .add(Dst)
660 .add(Src)
661 .add(Len);
662
663 // Create the CFG triangle.
664 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
665 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
666
667 return DoneMBB;
668}
669
670// Lower a `MEMSET` instruction into a CFG triangle around a `MEMORY_FILL`
671// instuction to handle the zero-length case.
674 const TargetInstrInfo &TII, bool Int64) {
676
677 MachineOperand Mem = MI.getOperand(0);
678 MachineOperand Dst = MI.getOperand(1);
679 MachineOperand Val = MI.getOperand(2);
680 MachineOperand Len = MI.getOperand(3);
681
682 // We're going to add an extra use to `Len` to test if it's zero; that
683 // use shouldn't be a kill, even if the original use is.
684 MachineOperand NoKillLen = Len;
685 NoKillLen.setIsKill(false);
686
687 // Decide on which `MachineInstr` opcode we're going to use.
688 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
689 unsigned MemoryFill =
690 Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
691
692 // Create two new basic blocks; one for the new `memory.fill` that we can
693 // branch over, and one for the rest of the instructions after the original
694 // `memory.fill`.
695 const BasicBlock *LLVMBB = BB->getBasicBlock();
696 MachineFunction *F = BB->getParent();
697 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
698 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
699
701 F->insert(It, TrueMBB);
702 F->insert(It, DoneMBB);
703
704 // Transfer the remainder of BB and its successor edges to DoneMBB.
705 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
707
708 // Connect the CFG edges.
709 BB->addSuccessor(TrueMBB);
710 BB->addSuccessor(DoneMBB);
711 TrueMBB->addSuccessor(DoneMBB);
712
713 // Create a virtual register for the `Eqz` result.
714 unsigned EqzReg;
715 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
716
717 // Erase the original `memory.fill`.
718 MI.eraseFromParent();
719
720 // Test if `Len` is zero.
721 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
722
723 // Insert a new `memory.copy`.
724 BuildMI(TrueMBB, DL, TII.get(MemoryFill)).add(Mem).add(Dst).add(Val).add(Len);
725
726 // Create the CFG triangle.
727 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
728 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
729
730 return DoneMBB;
731}
732
733static MachineBasicBlock *
735 const WebAssemblySubtarget *Subtarget,
736 const TargetInstrInfo &TII) {
737 MachineInstr &CallParams = *CallResults.getPrevNode();
738 assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
739 assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
740 CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
741
742 bool IsIndirect =
743 CallParams.getOperand(0).isReg() || CallParams.getOperand(0).isFI();
744 bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
745
746 bool IsFuncrefCall = false;
747 if (IsIndirect && CallParams.getOperand(0).isReg()) {
748 Register Reg = CallParams.getOperand(0).getReg();
749 const MachineFunction *MF = BB->getParent();
750 const MachineRegisterInfo &MRI = MF->getRegInfo();
751 const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
752 IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
753 assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
754 }
755
756 unsigned CallOp;
757 if (IsIndirect && IsRetCall) {
758 CallOp = WebAssembly::RET_CALL_INDIRECT;
759 } else if (IsIndirect) {
760 CallOp = WebAssembly::CALL_INDIRECT;
761 } else if (IsRetCall) {
762 CallOp = WebAssembly::RET_CALL;
763 } else {
764 CallOp = WebAssembly::CALL;
765 }
766
767 MachineFunction &MF = *BB->getParent();
768 const MCInstrDesc &MCID = TII.get(CallOp);
769 MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
770
771 // Move the function pointer to the end of the arguments for indirect calls
772 if (IsIndirect) {
773 auto FnPtr = CallParams.getOperand(0);
774 CallParams.removeOperand(0);
775
776 // For funcrefs, call_indirect is done through __funcref_call_table and the
777 // funcref is always installed in slot 0 of the table, therefore instead of
778 // having the function pointer added at the end of the params list, a zero
779 // (the index in
780 // __funcref_call_table is added).
781 if (IsFuncrefCall) {
782 Register RegZero =
783 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
784 MachineInstrBuilder MIBC0 =
785 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
786
787 BB->insert(CallResults.getIterator(), MIBC0);
788 MachineInstrBuilder(MF, CallParams).addReg(RegZero);
789 } else
790 CallParams.addOperand(FnPtr);
791 }
792
793 for (auto Def : CallResults.defs())
794 MIB.add(Def);
795
796 if (IsIndirect) {
797 // Placeholder for the type index.
798 MIB.addImm(0);
799 // The table into which this call_indirect indexes.
800 MCSymbolWasm *Table = IsFuncrefCall
802 MF.getContext(), Subtarget)
804 MF.getContext(), Subtarget);
805 if (Subtarget->hasCallIndirectOverlong()) {
806 MIB.addSym(Table);
807 } else {
808 // For the MVP there is at most one table whose number is 0, but we can't
809 // write a table symbol or issue relocations. Instead we just ensure the
810 // table is live and write a zero.
811 Table->setNoStrip();
812 MIB.addImm(0);
813 }
814 }
815
816 for (auto Use : CallParams.uses())
817 MIB.add(Use);
818
819 BB->insert(CallResults.getIterator(), MIB);
820 CallParams.eraseFromParent();
821 CallResults.eraseFromParent();
822
823 // If this is a funcref call, to avoid hidden GC roots, we need to clear the
824 // table slot with ref.null upon call_indirect return.
825 //
826 // This generates the following code, which comes right after a call_indirect
827 // of a funcref:
828 //
829 // i32.const 0
830 // ref.null func
831 // table.set __funcref_call_table
832 if (IsIndirect && IsFuncrefCall) {
834 MF.getContext(), Subtarget);
835 Register RegZero =
836 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
837 MachineInstr *Const0 =
838 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
839 BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
840
841 Register RegFuncref =
842 MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
843 MachineInstr *RefNull =
844 BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref);
845 BB->insertAfter(Const0->getIterator(), RefNull);
846
847 MachineInstr *TableSet =
848 BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
849 .addSym(Table)
850 .addReg(RegZero)
851 .addReg(RegFuncref);
852 BB->insertAfter(RefNull->getIterator(), TableSet);
853 }
854
855 return BB;
856}
857
858MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
859 MachineInstr &MI, MachineBasicBlock *BB) const {
860 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
861 DebugLoc DL = MI.getDebugLoc();
862
863 switch (MI.getOpcode()) {
864 default:
865 llvm_unreachable("Unexpected instr type to insert");
866 case WebAssembly::FP_TO_SINT_I32_F32:
867 return LowerFPToInt(MI, DL, BB, TII, false, false, false,
868 WebAssembly::I32_TRUNC_S_F32);
869 case WebAssembly::FP_TO_UINT_I32_F32:
870 return LowerFPToInt(MI, DL, BB, TII, true, false, false,
871 WebAssembly::I32_TRUNC_U_F32);
872 case WebAssembly::FP_TO_SINT_I64_F32:
873 return LowerFPToInt(MI, DL, BB, TII, false, true, false,
874 WebAssembly::I64_TRUNC_S_F32);
875 case WebAssembly::FP_TO_UINT_I64_F32:
876 return LowerFPToInt(MI, DL, BB, TII, true, true, false,
877 WebAssembly::I64_TRUNC_U_F32);
878 case WebAssembly::FP_TO_SINT_I32_F64:
879 return LowerFPToInt(MI, DL, BB, TII, false, false, true,
880 WebAssembly::I32_TRUNC_S_F64);
881 case WebAssembly::FP_TO_UINT_I32_F64:
882 return LowerFPToInt(MI, DL, BB, TII, true, false, true,
883 WebAssembly::I32_TRUNC_U_F64);
884 case WebAssembly::FP_TO_SINT_I64_F64:
885 return LowerFPToInt(MI, DL, BB, TII, false, true, true,
886 WebAssembly::I64_TRUNC_S_F64);
887 case WebAssembly::FP_TO_UINT_I64_F64:
888 return LowerFPToInt(MI, DL, BB, TII, true, true, true,
889 WebAssembly::I64_TRUNC_U_F64);
890 case WebAssembly::MEMCPY_A32:
891 return LowerMemcpy(MI, DL, BB, TII, false);
892 case WebAssembly::MEMCPY_A64:
893 return LowerMemcpy(MI, DL, BB, TII, true);
894 case WebAssembly::MEMSET_A32:
895 return LowerMemset(MI, DL, BB, TII, false);
896 case WebAssembly::MEMSET_A64:
897 return LowerMemset(MI, DL, BB, TII, true);
898 case WebAssembly::CALL_RESULTS:
899 case WebAssembly::RET_CALL_RESULTS:
900 return LowerCallResults(MI, DL, BB, Subtarget, TII);
901 }
902}
903
904const char *
905WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
906 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
908 break;
909#define HANDLE_NODETYPE(NODE) \
910 case WebAssemblyISD::NODE: \
911 return "WebAssemblyISD::" #NODE;
912#include "WebAssemblyISD.def"
913#undef HANDLE_NODETYPE
914 }
915 return nullptr;
916}
917
918std::pair<unsigned, const TargetRegisterClass *>
919WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
920 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
921 // First, see if this is a constraint that directly corresponds to a
922 // WebAssembly register class.
923 if (Constraint.size() == 1) {
924 switch (Constraint[0]) {
925 case 'r':
926 assert(VT != MVT::iPTR && "Pointer MVT not expected here");
927 if (Subtarget->hasSIMD128() && VT.isVector()) {
928 if (VT.getSizeInBits() == 128)
929 return std::make_pair(0U, &WebAssembly::V128RegClass);
930 }
931 if (VT.isInteger() && !VT.isVector()) {
932 if (VT.getSizeInBits() <= 32)
933 return std::make_pair(0U, &WebAssembly::I32RegClass);
934 if (VT.getSizeInBits() <= 64)
935 return std::make_pair(0U, &WebAssembly::I64RegClass);
936 }
937 if (VT.isFloatingPoint() && !VT.isVector()) {
938 switch (VT.getSizeInBits()) {
939 case 32:
940 return std::make_pair(0U, &WebAssembly::F32RegClass);
941 case 64:
942 return std::make_pair(0U, &WebAssembly::F64RegClass);
943 default:
944 break;
945 }
946 }
947 break;
948 default:
949 break;
950 }
951 }
952
954}
955
956bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const {
957 // Assume ctz is a relatively cheap operation.
958 return true;
959}
960
961bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
962 // Assume clz is a relatively cheap operation.
963 return true;
964}
965
966bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
967 const AddrMode &AM,
968 Type *Ty, unsigned AS,
969 Instruction *I) const {
970 // WebAssembly offsets are added as unsigned without wrapping. The
971 // isLegalAddressingMode gives us no way to determine if wrapping could be
972 // happening, so we approximate this by accepting only non-negative offsets.
973 if (AM.BaseOffs < 0)
974 return false;
975
976 // WebAssembly has no scale register operands.
977 if (AM.Scale != 0)
978 return false;
979
980 // Everything else is legal.
981 return true;
982}
983
984bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
985 EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/,
986 MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const {
987 // WebAssembly supports unaligned accesses, though it should be declared
988 // with the p2align attribute on loads and stores which do so, and there
989 // may be a performance impact. We tell LLVM they're "fast" because
990 // for the kinds of things that LLVM uses this for (merging adjacent stores
991 // of constants, etc.), WebAssembly implementations will either want the
992 // unaligned access or they'll split anyway.
993 if (Fast)
994 *Fast = 1;
995 return true;
996}
997
998bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
999 AttributeList Attr) const {
1000 // The current thinking is that wasm engines will perform this optimization,
1001 // so we can save on code size.
1002 return true;
1003}
1004
1005bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
1006 EVT ExtT = ExtVal.getValueType();
1007 EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0);
1008 return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
1009 (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
1010 (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
1011}
1012
1013bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
1014 const GlobalAddressSDNode *GA) const {
1015 // Wasm doesn't support function addresses with offsets
1016 const GlobalValue *GV = GA->getGlobal();
1017 return isa<Function>(GV) ? false : TargetLowering::isOffsetFoldingLegal(GA);
1018}
1019
1020EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
1021 LLVMContext &C,
1022 EVT VT) const {
1023 if (VT.isVector())
1025
1026 // So far, all branch instructions in Wasm take an I32 condition.
1027 // The default TargetLowering::getSetCCResultType returns the pointer size,
1028 // which would be useful to reduce instruction counts when testing
1029 // against 64-bit pointers/values if at some point Wasm supports that.
1030 return EVT::getIntegerVT(C, 32);
1031}
1032
1033bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
1034 const CallInst &I,
1035 MachineFunction &MF,
1036 unsigned Intrinsic) const {
1037 switch (Intrinsic) {
1038 case Intrinsic::wasm_memory_atomic_notify:
1040 Info.memVT = MVT::i32;
1041 Info.ptrVal = I.getArgOperand(0);
1042 Info.offset = 0;
1043 Info.align = Align(4);
1044 // atomic.notify instruction does not really load the memory specified with
1045 // this argument, but MachineMemOperand should either be load or store, so
1046 // we set this to a load.
1047 // FIXME Volatile isn't really correct, but currently all LLVM atomic
1048 // instructions are treated as volatiles in the backend, so we should be
1049 // consistent. The same applies for wasm_atomic_wait intrinsics too.
1051 return true;
1052 case Intrinsic::wasm_memory_atomic_wait32:
1054 Info.memVT = MVT::i32;
1055 Info.ptrVal = I.getArgOperand(0);
1056 Info.offset = 0;
1057 Info.align = Align(4);
1059 return true;
1060 case Intrinsic::wasm_memory_atomic_wait64:
1062 Info.memVT = MVT::i64;
1063 Info.ptrVal = I.getArgOperand(0);
1064 Info.offset = 0;
1065 Info.align = Align(8);
1067 return true;
1068 case Intrinsic::wasm_loadf16_f32:
1070 Info.memVT = MVT::f16;
1071 Info.ptrVal = I.getArgOperand(0);
1072 Info.offset = 0;
1073 Info.align = Align(2);
1075 return true;
1076 case Intrinsic::wasm_storef16_f32:
1078 Info.memVT = MVT::f16;
1079 Info.ptrVal = I.getArgOperand(1);
1080 Info.offset = 0;
1081 Info.align = Align(2);
1083 return true;
1084 default:
1085 return false;
1086 }
1087}
1088
1089void WebAssemblyTargetLowering::computeKnownBitsForTargetNode(
1090 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
1091 const SelectionDAG &DAG, unsigned Depth) const {
1092 switch (Op.getOpcode()) {
1093 default:
1094 break;
1096 unsigned IntNo = Op.getConstantOperandVal(0);
1097 switch (IntNo) {
1098 default:
1099 break;
1100 case Intrinsic::wasm_bitmask: {
1101 unsigned BitWidth = Known.getBitWidth();
1102 EVT VT = Op.getOperand(1).getSimpleValueType();
1103 unsigned PossibleBits = VT.getVectorNumElements();
1104 APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits);
1105 Known.Zero |= ZeroMask;
1106 break;
1107 }
1108 }
1109 }
1110 }
1111}
1112
1114WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
1115 if (VT.isFixedLengthVector()) {
1116 MVT EltVT = VT.getVectorElementType();
1117 // We have legal vector types with these lane types, so widening the
1118 // vector would let us use some of the lanes directly without having to
1119 // extend or truncate values.
1120 if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
1121 EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64)
1122 return TypeWidenVector;
1123 }
1124
1126}
1127
1128bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
1129 SDValue Op, const TargetLoweringOpt &TLO) const {
1130 // ISel process runs DAGCombiner after legalization; this step is called
1131 // SelectionDAG optimization phase. This post-legalization combining process
1132 // runs DAGCombiner on each node, and if there was a change to be made,
1133 // re-runs legalization again on it and its user nodes to make sure
1134 // everythiing is in a legalized state.
1135 //
1136 // The legalization calls lowering routines, and we do our custom lowering for
1137 // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
1138 // into zeros. But there is a set of routines in DAGCombiner that turns unused
1139 // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
1140 // turns unused vector elements into undefs. But this routine does not work
1141 // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
1142 // combination can result in a infinite loop, in which undefs are converted to
1143 // zeros in legalization and back to undefs in combining.
1144 //
1145 // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
1146 // running for build_vectors.
1147 if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
1148 return false;
1149 return true;
1150}
1151
1152//===----------------------------------------------------------------------===//
1153// WebAssembly Lowering private implementation.
1154//===----------------------------------------------------------------------===//
1155
1156//===----------------------------------------------------------------------===//
1157// Lowering Code
1158//===----------------------------------------------------------------------===//
1159
1160static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
1162 DAG.getContext()->diagnose(
1163 DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
1164}
1165
1166// Test whether the given calling convention is supported.
1168 // We currently support the language-independent target-independent
1169 // conventions. We don't yet have a way to annotate calls with properties like
1170 // "cold", and we don't have any call-clobbered registers, so these are mostly
1171 // all handled the same.
1172 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
1173 CallConv == CallingConv::Cold ||
1174 CallConv == CallingConv::PreserveMost ||
1175 CallConv == CallingConv::PreserveAll ||
1176 CallConv == CallingConv::CXX_FAST_TLS ||
1178 CallConv == CallingConv::Swift;
1179}
1180
1181SDValue
1182WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
1183 SmallVectorImpl<SDValue> &InVals) const {
1184 SelectionDAG &DAG = CLI.DAG;
1185 SDLoc DL = CLI.DL;
1186 SDValue Chain = CLI.Chain;
1187 SDValue Callee = CLI.Callee;
1189 auto Layout = MF.getDataLayout();
1190
1191 CallingConv::ID CallConv = CLI.CallConv;
1192 if (!callingConvSupported(CallConv))
1193 fail(DL, DAG,
1194 "WebAssembly doesn't support language-specific or target-specific "
1195 "calling conventions yet");
1196 if (CLI.IsPatchPoint)
1197 fail(DL, DAG, "WebAssembly doesn't support patch point yet");
1198
1199 if (CLI.IsTailCall) {
1200 auto NoTail = [&](const char *Msg) {
1201 if (CLI.CB && CLI.CB->isMustTailCall())
1202 fail(DL, DAG, Msg);
1203 CLI.IsTailCall = false;
1204 };
1205
1206 if (!Subtarget->hasTailCall())
1207 NoTail("WebAssembly 'tail-call' feature not enabled");
1208
1209 // Varargs calls cannot be tail calls because the buffer is on the stack
1210 if (CLI.IsVarArg)
1211 NoTail("WebAssembly does not support varargs tail calls");
1212
1213 // Do not tail call unless caller and callee return types match
1214 const Function &F = MF.getFunction();
1216 Type *RetTy = F.getReturnType();
1217 SmallVector<MVT, 4> CallerRetTys;
1218 SmallVector<MVT, 4> CalleeRetTys;
1219 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1220 computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
1221 bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
1222 std::equal(CallerRetTys.begin(), CallerRetTys.end(),
1223 CalleeRetTys.begin());
1224 if (!TypesMatch)
1225 NoTail("WebAssembly tail call requires caller and callee return types to "
1226 "match");
1227
1228 // If pointers to local stack values are passed, we cannot tail call
1229 if (CLI.CB) {
1230 for (auto &Arg : CLI.CB->args()) {
1231 Value *Val = Arg.get();
1232 // Trace the value back through pointer operations
1233 while (true) {
1234 Value *Src = Val->stripPointerCastsAndAliases();
1235 if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
1236 Src = GEP->getPointerOperand();
1237 if (Val == Src)
1238 break;
1239 Val = Src;
1240 }
1241 if (isa<AllocaInst>(Val)) {
1242 NoTail(
1243 "WebAssembly does not support tail calling with stack arguments");
1244 break;
1245 }
1246 }
1247 }
1248 }
1249
1251 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
1252 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
1253
1254 // The generic code may have added an sret argument. If we're lowering an
1255 // invoke function, the ABI requires that the function pointer be the first
1256 // argument, so we may have to swap the arguments.
1257 if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
1258 Outs[0].Flags.isSRet()) {
1259 std::swap(Outs[0], Outs[1]);
1260 std::swap(OutVals[0], OutVals[1]);
1261 }
1262
1263 bool HasSwiftSelfArg = false;
1264 bool HasSwiftErrorArg = false;
1265 unsigned NumFixedArgs = 0;
1266 for (unsigned I = 0; I < Outs.size(); ++I) {
1267 const ISD::OutputArg &Out = Outs[I];
1268 SDValue &OutVal = OutVals[I];
1269 HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
1270 HasSwiftErrorArg |= Out.Flags.isSwiftError();
1271 if (Out.Flags.isNest())
1272 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1273 if (Out.Flags.isInAlloca())
1274 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1275 if (Out.Flags.isInConsecutiveRegs())
1276 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1278 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1279 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
1280 auto &MFI = MF.getFrameInfo();
1281 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
1283 /*isSS=*/false);
1284 SDValue SizeNode =
1285 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
1286 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1287 Chain = DAG.getMemcpy(Chain, DL, FINode, OutVal, SizeNode,
1289 /*isVolatile*/ false, /*AlwaysInline=*/false,
1290 /*CI=*/nullptr, std::nullopt, MachinePointerInfo(),
1292 OutVal = FINode;
1293 }
1294 // Count the number of fixed args *after* legalization.
1295 NumFixedArgs += Out.IsFixed;
1296 }
1297
1298 bool IsVarArg = CLI.IsVarArg;
1299 auto PtrVT = getPointerTy(Layout);
1300
1301 // For swiftcc, emit additional swiftself and swifterror arguments
1302 // if there aren't. These additional arguments are also added for callee
1303 // signature They are necessary to match callee and caller signature for
1304 // indirect call.
1305 if (CallConv == CallingConv::Swift) {
1306 if (!HasSwiftSelfArg) {
1307 NumFixedArgs++;
1308 ISD::OutputArg Arg;
1309 Arg.Flags.setSwiftSelf();
1310 CLI.Outs.push_back(Arg);
1311 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1312 CLI.OutVals.push_back(ArgVal);
1313 }
1314 if (!HasSwiftErrorArg) {
1315 NumFixedArgs++;
1316 ISD::OutputArg Arg;
1317 Arg.Flags.setSwiftError();
1318 CLI.Outs.push_back(Arg);
1319 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1320 CLI.OutVals.push_back(ArgVal);
1321 }
1322 }
1323
1324 // Analyze operands of the call, assigning locations to each operand.
1326 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1327
1328 if (IsVarArg) {
1329 // Outgoing non-fixed arguments are placed in a buffer. First
1330 // compute their offsets and the total amount of buffer space needed.
1331 for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
1332 const ISD::OutputArg &Out = Outs[I];
1333 SDValue &Arg = OutVals[I];
1334 EVT VT = Arg.getValueType();
1335 assert(VT != MVT::iPTR && "Legalized args should be concrete");
1336 Type *Ty = VT.getTypeForEVT(*DAG.getContext());
1337 Align Alignment =
1338 std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
1339 unsigned Offset =
1340 CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
1341 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
1342 Offset, VT.getSimpleVT(),
1344 }
1345 }
1346
1347 unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
1348
1349 SDValue FINode;
1350 if (IsVarArg && NumBytes) {
1351 // For non-fixed arguments, next emit stores to store the argument values
1352 // to the stack buffer at the offsets computed above.
1353 MaybeAlign StackAlign = Layout.getStackAlignment();
1354 assert(StackAlign && "data layout string is missing stack alignment");
1355 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, *StackAlign,
1356 /*isSS=*/false);
1357 unsigned ValNo = 0;
1359 for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) {
1360 assert(ArgLocs[ValNo].getValNo() == ValNo &&
1361 "ArgLocs should remain in order and only hold varargs args");
1362 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
1363 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1364 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
1365 DAG.getConstant(Offset, DL, PtrVT));
1366 Chains.push_back(
1367 DAG.getStore(Chain, DL, Arg, Add,
1369 }
1370 if (!Chains.empty())
1371 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
1372 } else if (IsVarArg) {
1373 FINode = DAG.getIntPtrConstant(0, DL);
1374 }
1375
1376 if (Callee->getOpcode() == ISD::GlobalAddress) {
1377 // If the callee is a GlobalAddress node (quite common, every direct call
1378 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
1379 // doesn't at MO_GOT which is not needed for direct calls.
1380 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
1383 GA->getOffset());
1384 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
1385 getPointerTy(DAG.getDataLayout()), Callee);
1386 }
1387
1388 // Compute the operands for the CALLn node.
1390 Ops.push_back(Chain);
1391 Ops.push_back(Callee);
1392
1393 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
1394 // isn't reliable.
1395 Ops.append(OutVals.begin(),
1396 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
1397 // Add a pointer to the vararg buffer.
1398 if (IsVarArg)
1399 Ops.push_back(FINode);
1400
1401 SmallVector<EVT, 8> InTys;
1402 for (const auto &In : Ins) {
1403 assert(!In.Flags.isByVal() && "byval is not valid for return values");
1404 assert(!In.Flags.isNest() && "nest is not valid for return values");
1405 if (In.Flags.isInAlloca())
1406 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
1407 if (In.Flags.isInConsecutiveRegs())
1408 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
1409 if (In.Flags.isInConsecutiveRegsLast())
1410 fail(DL, DAG,
1411 "WebAssembly hasn't implemented cons regs last return values");
1412 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1413 // registers.
1414 InTys.push_back(In.VT);
1415 }
1416
1417 // Lastly, if this is a call to a funcref we need to add an instruction
1418 // table.set to the chain and transform the call.
1420 CLI.CB->getCalledOperand()->getType())) {
1421 // In the absence of function references proposal where a funcref call is
1422 // lowered to call_ref, using reference types we generate a table.set to set
1423 // the funcref to a special table used solely for this purpose, followed by
1424 // a call_indirect. Here we just generate the table set, and return the
1425 // SDValue of the table.set so that LowerCall can finalize the lowering by
1426 // generating the call_indirect.
1427 SDValue Chain = Ops[0];
1428
1430 MF.getContext(), Subtarget);
1431 SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
1432 SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
1433 SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
1434 SDValue TableSet = DAG.getMemIntrinsicNode(
1435 WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
1436 MVT::funcref,
1437 // Machine Mem Operand args
1440 CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()),
1442
1443 Ops[0] = TableSet; // The new chain is the TableSet itself
1444 }
1445
1446 if (CLI.IsTailCall) {
1447 // ret_calls do not return values to the current frame
1448 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1449 return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
1450 }
1451
1452 InTys.push_back(MVT::Other);
1453 SDVTList InTyList = DAG.getVTList(InTys);
1454 SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
1455
1456 for (size_t I = 0; I < Ins.size(); ++I)
1457 InVals.push_back(Res.getValue(I));
1458
1459 // Return the chain
1460 return Res.getValue(Ins.size());
1461}
1462
1463bool WebAssemblyTargetLowering::CanLowerReturn(
1464 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
1466 LLVMContext & /*Context*/,
1467 const Type *RetTy) const {
1468 // WebAssembly can only handle returning tuples with multivalue enabled
1469 return WebAssembly::canLowerReturn(Outs.size(), Subtarget);
1470}
1471
1472SDValue WebAssemblyTargetLowering::LowerReturn(
1473 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
1475 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
1476 SelectionDAG &DAG) const {
1477 assert(WebAssembly::canLowerReturn(Outs.size(), Subtarget) &&
1478 "MVP WebAssembly can only return up to one value");
1479 if (!callingConvSupported(CallConv))
1480 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1481
1482 SmallVector<SDValue, 4> RetOps(1, Chain);
1483 RetOps.append(OutVals.begin(), OutVals.end());
1484 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
1485
1486 // Record the number and types of the return values.
1487 for (const ISD::OutputArg &Out : Outs) {
1488 assert(!Out.Flags.isByVal() && "byval is not valid for return values");
1489 assert(!Out.Flags.isNest() && "nest is not valid for return values");
1490 assert(Out.IsFixed && "non-fixed return value is not valid");
1491 if (Out.Flags.isInAlloca())
1492 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
1493 if (Out.Flags.isInConsecutiveRegs())
1494 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
1496 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
1497 }
1498
1499 return Chain;
1500}
1501
1502SDValue WebAssemblyTargetLowering::LowerFormalArguments(
1503 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
1504 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
1505 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
1506 if (!callingConvSupported(CallConv))
1507 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1508
1510 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
1511
1512 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
1513 // of the incoming values before they're represented by virtual registers.
1514 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
1515
1516 bool HasSwiftErrorArg = false;
1517 bool HasSwiftSelfArg = false;
1518 for (const ISD::InputArg &In : Ins) {
1519 HasSwiftSelfArg |= In.Flags.isSwiftSelf();
1520 HasSwiftErrorArg |= In.Flags.isSwiftError();
1521 if (In.Flags.isInAlloca())
1522 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1523 if (In.Flags.isNest())
1524 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1525 if (In.Flags.isInConsecutiveRegs())
1526 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1527 if (In.Flags.isInConsecutiveRegsLast())
1528 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1529 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1530 // registers.
1531 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
1532 DAG.getTargetConstant(InVals.size(),
1533 DL, MVT::i32))
1534 : DAG.getUNDEF(In.VT));
1535
1536 // Record the number and types of arguments.
1537 MFI->addParam(In.VT);
1538 }
1539
1540 // For swiftcc, emit additional swiftself and swifterror arguments
1541 // if there aren't. These additional arguments are also added for callee
1542 // signature They are necessary to match callee and caller signature for
1543 // indirect call.
1544 auto PtrVT = getPointerTy(MF.getDataLayout());
1545 if (CallConv == CallingConv::Swift) {
1546 if (!HasSwiftSelfArg) {
1547 MFI->addParam(PtrVT);
1548 }
1549 if (!HasSwiftErrorArg) {
1550 MFI->addParam(PtrVT);
1551 }
1552 }
1553 // Varargs are copied into a buffer allocated by the caller, and a pointer to
1554 // the buffer is passed as an argument.
1555 if (IsVarArg) {
1556 MVT PtrVT = getPointerTy(MF.getDataLayout());
1557 Register VarargVreg =
1559 MFI->setVarargBufferVreg(VarargVreg);
1560 Chain = DAG.getCopyToReg(
1561 Chain, DL, VarargVreg,
1562 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
1563 DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
1564 MFI->addParam(PtrVT);
1565 }
1566
1567 // Record the number and types of arguments and results.
1568 SmallVector<MVT, 4> Params;
1571 MF.getFunction(), DAG.getTarget(), Params, Results);
1572 for (MVT VT : Results)
1573 MFI->addResult(VT);
1574 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
1575 // the param logic here with ComputeSignatureVTs
1576 assert(MFI->getParams().size() == Params.size() &&
1577 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
1578 Params.begin()));
1579
1580 return Chain;
1581}
1582
1583void WebAssemblyTargetLowering::ReplaceNodeResults(
1585 switch (N->getOpcode()) {
1587 // Do not add any results, signifying that N should not be custom lowered
1588 // after all. This happens because simd128 turns on custom lowering for
1589 // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1590 // illegal type.
1591 break;
1594 // Do not add any results, signifying that N should not be custom lowered.
1595 // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
1596 break;
1597 case ISD::ADD:
1598 case ISD::SUB:
1599 Results.push_back(Replace128Op(N, DAG));
1600 break;
1601 default:
1603 "ReplaceNodeResults not implemented for this op for WebAssembly!");
1604 }
1605}
1606
1607//===----------------------------------------------------------------------===//
1608// Custom lowering hooks.
1609//===----------------------------------------------------------------------===//
1610
1611SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1612 SelectionDAG &DAG) const {
1613 SDLoc DL(Op);
1614 switch (Op.getOpcode()) {
1615 default:
1616 llvm_unreachable("unimplemented operation lowering");
1617 return SDValue();
1618 case ISD::FrameIndex:
1619 return LowerFrameIndex(Op, DAG);
1620 case ISD::GlobalAddress:
1621 return LowerGlobalAddress(Op, DAG);
1623 return LowerGlobalTLSAddress(Op, DAG);
1625 return LowerExternalSymbol(Op, DAG);
1626 case ISD::JumpTable:
1627 return LowerJumpTable(Op, DAG);
1628 case ISD::BR_JT:
1629 return LowerBR_JT(Op, DAG);
1630 case ISD::VASTART:
1631 return LowerVASTART(Op, DAG);
1632 case ISD::BlockAddress:
1633 case ISD::BRIND:
1634 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
1635 return SDValue();
1636 case ISD::RETURNADDR:
1637 return LowerRETURNADDR(Op, DAG);
1638 case ISD::FRAMEADDR:
1639 return LowerFRAMEADDR(Op, DAG);
1640 case ISD::CopyToReg:
1641 return LowerCopyToReg(Op, DAG);
1644 return LowerAccessVectorElement(Op, DAG);
1648 return LowerIntrinsic(Op, DAG);
1650 return LowerSIGN_EXTEND_INREG(Op, DAG);
1653 return LowerEXTEND_VECTOR_INREG(Op, DAG);
1654 case ISD::BUILD_VECTOR:
1655 return LowerBUILD_VECTOR(Op, DAG);
1657 return LowerVECTOR_SHUFFLE(Op, DAG);
1658 case ISD::SETCC:
1659 return LowerSETCC(Op, DAG);
1660 case ISD::SHL:
1661 case ISD::SRA:
1662 case ISD::SRL:
1663 return LowerShift(Op, DAG);
1666 return LowerFP_TO_INT_SAT(Op, DAG);
1667 case ISD::LOAD:
1668 return LowerLoad(Op, DAG);
1669 case ISD::STORE:
1670 return LowerStore(Op, DAG);
1671 case ISD::CTPOP:
1672 case ISD::CTLZ:
1673 case ISD::CTTZ:
1674 return DAG.UnrollVectorOp(Op.getNode());
1675 case ISD::CLEAR_CACHE:
1676 report_fatal_error("llvm.clear_cache is not supported on wasm");
1677 case ISD::SMUL_LOHI:
1678 case ISD::UMUL_LOHI:
1679 return LowerMUL_LOHI(Op, DAG);
1680 }
1681}
1682
1684 if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
1686
1687 return false;
1688}
1689
1690static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op,
1691 SelectionDAG &DAG) {
1692 const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op);
1693 if (!FI)
1694 return std::nullopt;
1695
1696 auto &MF = DAG.getMachineFunction();
1698}
1699
1700SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
1701 SelectionDAG &DAG) const {
1702 SDLoc DL(Op);
1703 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
1704 const SDValue &Value = SN->getValue();
1705 const SDValue &Base = SN->getBasePtr();
1706 const SDValue &Offset = SN->getOffset();
1707
1709 if (!Offset->isUndef())
1710 report_fatal_error("unexpected offset when storing to webassembly global",
1711 false);
1712
1713 SDVTList Tys = DAG.getVTList(MVT::Other);
1714 SDValue Ops[] = {SN->getChain(), Value, Base};
1715 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops,
1716 SN->getMemoryVT(), SN->getMemOperand());
1717 }
1718
1719 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1720 if (!Offset->isUndef())
1721 report_fatal_error("unexpected offset when storing to webassembly local",
1722 false);
1723
1724 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1725 SDVTList Tys = DAG.getVTList(MVT::Other); // The chain.
1726 SDValue Ops[] = {SN->getChain(), Idx, Value};
1727 return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops);
1728 }
1729
1732 "Encountered an unlowerable store to the wasm_var address space",
1733 false);
1734
1735 return Op;
1736}
1737
1738SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
1739 SelectionDAG &DAG) const {
1740 SDLoc DL(Op);
1741 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
1742 const SDValue &Base = LN->getBasePtr();
1743 const SDValue &Offset = LN->getOffset();
1744
1746 if (!Offset->isUndef())
1748 "unexpected offset when loading from webassembly global", false);
1749
1750 SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
1751 SDValue Ops[] = {LN->getChain(), Base};
1752 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops,
1753 LN->getMemoryVT(), LN->getMemOperand());
1754 }
1755
1756 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1757 if (!Offset->isUndef())
1759 "unexpected offset when loading from webassembly local", false);
1760
1761 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1762 EVT LocalVT = LN->getValueType(0);
1763 SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT,
1764 {LN->getChain(), Idx});
1765 SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL);
1766 assert(Result->getNumValues() == 2 && "Loads must carry a chain!");
1767 return Result;
1768 }
1769
1772 "Encountered an unlowerable load from the wasm_var address space",
1773 false);
1774
1775 return Op;
1776}
1777
1778SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
1779 SelectionDAG &DAG) const {
1780 assert(Subtarget->hasWideArithmetic());
1781 assert(Op.getValueType() == MVT::i64);
1782 SDLoc DL(Op);
1783 unsigned Opcode;
1784 switch (Op.getOpcode()) {
1785 case ISD::UMUL_LOHI:
1786 Opcode = WebAssemblyISD::I64_MUL_WIDE_U;
1787 break;
1788 case ISD::SMUL_LOHI:
1789 Opcode = WebAssemblyISD::I64_MUL_WIDE_S;
1790 break;
1791 default:
1792 llvm_unreachable("unexpected opcode");
1793 }
1794 SDValue LHS = Op.getOperand(0);
1795 SDValue RHS = Op.getOperand(1);
1796 SDValue Hi =
1797 DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
1798 SDValue Lo(Hi.getNode(), 1);
1799 SDValue Ops[] = {Hi, Lo};
1800 return DAG.getMergeValues(Ops, DL);
1801}
1802
1803SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
1804 SelectionDAG &DAG) const {
1805 assert(Subtarget->hasWideArithmetic());
1806 assert(N->getValueType(0) == MVT::i128);
1807 SDLoc DL(N);
1808 unsigned Opcode;
1809 switch (N->getOpcode()) {
1810 case ISD::ADD:
1811 Opcode = WebAssemblyISD::I64_ADD128;
1812 break;
1813 case ISD::SUB:
1814 Opcode = WebAssemblyISD::I64_SUB128;
1815 break;
1816 default:
1817 llvm_unreachable("unexpected opcode");
1818 }
1819 SDValue LHS = N->getOperand(0);
1820 SDValue RHS = N->getOperand(1);
1821
1822 SDValue C0 = DAG.getConstant(0, DL, MVT::i64);
1823 SDValue C1 = DAG.getConstant(1, DL, MVT::i64);
1824 SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C0);
1825 SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C1);
1826 SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
1827 SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
1828 SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
1829 LHS_0, LHS_1, RHS_0, RHS_1);
1830 SDValue Result_HI(Result_LO.getNode(), 1);
1831 return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
1832}
1833
1834SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
1835 SelectionDAG &DAG) const {
1836 SDValue Src = Op.getOperand(2);
1837 if (isa<FrameIndexSDNode>(Src.getNode())) {
1838 // CopyToReg nodes don't support FrameIndex operands. Other targets select
1839 // the FI to some LEA-like instruction, but since we don't have that, we
1840 // need to insert some kind of instruction that can take an FI operand and
1841 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
1842 // local.copy between Op and its FI operand.
1843 SDValue Chain = Op.getOperand(0);
1844 SDLoc DL(Op);
1845 Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
1846 EVT VT = Src.getValueType();
1847 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
1848 : WebAssembly::COPY_I64,
1849 DL, VT, Src),
1850 0);
1851 return Op.getNode()->getNumValues() == 1
1852 ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
1853 : DAG.getCopyToReg(Chain, DL, Reg, Copy,
1854 Op.getNumOperands() == 4 ? Op.getOperand(3)
1855 : SDValue());
1856 }
1857 return SDValue();
1858}
1859
1860SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
1861 SelectionDAG &DAG) const {
1862 int FI = cast<FrameIndexSDNode>(Op)->getIndex();
1863 return DAG.getTargetFrameIndex(FI, Op.getValueType());
1864}
1865
1866SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
1867 SelectionDAG &DAG) const {
1868 SDLoc DL(Op);
1869
1870 if (!Subtarget->getTargetTriple().isOSEmscripten()) {
1871 fail(DL, DAG,
1872 "Non-Emscripten WebAssembly hasn't implemented "
1873 "__builtin_return_address");
1874 return SDValue();
1875 }
1876
1878 return SDValue();
1879
1880 unsigned Depth = Op.getConstantOperandVal(0);
1881 MakeLibCallOptions CallOptions;
1882 return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
1883 {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
1884 .first;
1885}
1886
1887SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
1888 SelectionDAG &DAG) const {
1889 // Non-zero depths are not supported by WebAssembly currently. Use the
1890 // legalizer's default expansion, which is to return 0 (what this function is
1891 // documented to do).
1892 if (Op.getConstantOperandVal(0) > 0)
1893 return SDValue();
1894
1896 EVT VT = Op.getValueType();
1897 Register FP =
1899 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
1900}
1901
1902SDValue
1903WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
1904 SelectionDAG &DAG) const {
1905 SDLoc DL(Op);
1906 const auto *GA = cast<GlobalAddressSDNode>(Op);
1907
1910 report_fatal_error("cannot use thread-local storage without bulk memory",
1911 false);
1912
1913 const GlobalValue *GV = GA->getGlobal();
1914
1915 // Currently only Emscripten supports dynamic linking with threads. Therefore,
1916 // on other targets, if we have thread-local storage, only the local-exec
1917 // model is possible.
1918 auto model = Subtarget->getTargetTriple().isOSEmscripten()
1919 ? GV->getThreadLocalMode()
1921
1922 // Unsupported TLS modes
1925
1926 if (model == GlobalValue::LocalExecTLSModel ||
1929 getTargetMachine().shouldAssumeDSOLocal(GV))) {
1930 // For DSO-local TLS variables we use offset from __tls_base
1931
1932 MVT PtrVT = getPointerTy(DAG.getDataLayout());
1933 auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
1934 : WebAssembly::GLOBAL_GET_I32;
1935 const char *BaseName = MF.createExternalSymbolName("__tls_base");
1936
1938 DAG.getMachineNode(GlobalGet, DL, PtrVT,
1939 DAG.getTargetExternalSymbol(BaseName, PtrVT)),
1940 0);
1941
1942 SDValue TLSOffset = DAG.getTargetGlobalAddress(
1943 GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL);
1944 SDValue SymOffset =
1945 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset);
1946
1947 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset);
1948 }
1949
1951
1952 EVT VT = Op.getValueType();
1953 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
1954 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
1955 GA->getOffset(),
1957}
1958
1959SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
1960 SelectionDAG &DAG) const {
1961 SDLoc DL(Op);
1962 const auto *GA = cast<GlobalAddressSDNode>(Op);
1963 EVT VT = Op.getValueType();
1964 assert(GA->getTargetFlags() == 0 &&
1965 "Unexpected target flags on generic GlobalAddressSDNode");
1967 fail(DL, DAG, "Invalid address space for WebAssembly target");
1968
1969 unsigned OperandFlags = 0;
1970 const GlobalValue *GV = GA->getGlobal();
1971 // Since WebAssembly tables cannot yet be shared accross modules, we don't
1972 // need special treatment for tables in PIC mode.
1973 if (isPositionIndependent() &&
1975 if (getTargetMachine().shouldAssumeDSOLocal(GV)) {
1977 MVT PtrVT = getPointerTy(MF.getDataLayout());
1978 const char *BaseName;
1979 if (GV->getValueType()->isFunctionTy()) {
1980 BaseName = MF.createExternalSymbolName("__table_base");
1982 } else {
1983 BaseName = MF.createExternalSymbolName("__memory_base");
1985 }
1987 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
1988 DAG.getTargetExternalSymbol(BaseName, PtrVT));
1989
1990 SDValue SymAddr = DAG.getNode(
1991 WebAssemblyISD::WrapperREL, DL, VT,
1992 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
1993 OperandFlags));
1994
1995 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
1996 }
1998 }
1999
2000 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2001 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2002 GA->getOffset(), OperandFlags));
2003}
2004
2005SDValue
2006WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
2007 SelectionDAG &DAG) const {
2008 SDLoc DL(Op);
2009 const auto *ES = cast<ExternalSymbolSDNode>(Op);
2010 EVT VT = Op.getValueType();
2011 assert(ES->getTargetFlags() == 0 &&
2012 "Unexpected target flags on generic ExternalSymbolSDNode");
2013 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2014 DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
2015}
2016
2017SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
2018 SelectionDAG &DAG) const {
2019 // There's no need for a Wrapper node because we always incorporate a jump
2020 // table operand into a BR_TABLE instruction, rather than ever
2021 // materializing it in a register.
2022 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
2023 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
2024 JT->getTargetFlags());
2025}
2026
2027SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
2028 SelectionDAG &DAG) const {
2029 SDLoc DL(Op);
2030 SDValue Chain = Op.getOperand(0);
2031 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
2032 SDValue Index = Op.getOperand(2);
2033 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
2034
2036 Ops.push_back(Chain);
2037 Ops.push_back(Index);
2038
2040 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
2041
2042 // Add an operand for each case.
2043 for (auto *MBB : MBBs)
2044 Ops.push_back(DAG.getBasicBlock(MBB));
2045
2046 // Add the first MBB as a dummy default target for now. This will be replaced
2047 // with the proper default target (and the preceding range check eliminated)
2048 // if possible by WebAssemblyFixBrTableDefaults.
2049 Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
2050 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
2051}
2052
2053SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
2054 SelectionDAG &DAG) const {
2055 SDLoc DL(Op);
2057
2059 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
2060
2061 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
2062 MFI->getVarargBufferVreg(), PtrVT);
2063 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
2064 MachinePointerInfo(SV));
2065}
2066
2067// Try to lower partial.reduce.add to a dot or fallback to a sequence with
2068// extmul and adds.
2070 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
2071 if (N->getConstantOperandVal(0) !=
2072 Intrinsic::experimental_vector_partial_reduce_add)
2073 return SDValue();
2074
2075 assert(N->getValueType(0) == MVT::v4i32 && "can only support v4i32");
2076 SDLoc DL(N);
2077 SDValue Mul = N->getOperand(2);
2078 assert(Mul->getOpcode() == ISD::MUL && "expected mul input");
2079
2080 SDValue ExtendLHS = Mul->getOperand(0);
2081 SDValue ExtendRHS = Mul->getOperand(1);
2082 assert((ISD::isExtOpcode(ExtendLHS.getOpcode()) &&
2083 ISD::isExtOpcode(ExtendRHS.getOpcode())) &&
2084 "expected widening mul");
2085 assert(ExtendLHS.getOpcode() == ExtendRHS.getOpcode() &&
2086 "expected mul to use the same extend for both operands");
2087
2088 SDValue ExtendInLHS = ExtendLHS->getOperand(0);
2089 SDValue ExtendInRHS = ExtendRHS->getOperand(0);
2090 bool IsSigned = ExtendLHS->getOpcode() == ISD::SIGN_EXTEND;
2091
2092 if (ExtendInLHS->getValueType(0) == MVT::v8i16) {
2093 if (IsSigned) {
2094 // i32x4.dot_i16x8_s
2095 SDValue Dot = DAG.getNode(WebAssemblyISD::DOT, DL, MVT::v4i32,
2096 ExtendInLHS, ExtendInRHS);
2097 return DAG.getNode(ISD::ADD, DL, MVT::v4i32, N->getOperand(1), Dot);
2098 }
2099
2100 unsigned LowOpc = WebAssemblyISD::EXTEND_LOW_U;
2101 unsigned HighOpc = WebAssemblyISD::EXTEND_HIGH_U;
2102
2103 // (add (add (extmul_low_sx lhs, rhs), (extmul_high_sx lhs, rhs)))
2104 SDValue LowLHS = DAG.getNode(LowOpc, DL, MVT::v4i32, ExtendInLHS);
2105 SDValue LowRHS = DAG.getNode(LowOpc, DL, MVT::v4i32, ExtendInRHS);
2106 SDValue HighLHS = DAG.getNode(HighOpc, DL, MVT::v4i32, ExtendInLHS);
2107 SDValue HighRHS = DAG.getNode(HighOpc, DL, MVT::v4i32, ExtendInRHS);
2108
2109 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v4i32, LowLHS, LowRHS);
2110 SDValue MulHigh = DAG.getNode(ISD::MUL, DL, MVT::v4i32, HighLHS, HighRHS);
2111 SDValue Add = DAG.getNode(ISD::ADD, DL, MVT::v4i32, MulLow, MulHigh);
2112 return DAG.getNode(ISD::ADD, DL, MVT::v4i32, N->getOperand(1), Add);
2113 } else {
2114 assert(ExtendInLHS->getValueType(0) == MVT::v16i8 &&
2115 "expected v16i8 input types");
2116 // Lower to a wider tree, using twice the operations compared to above.
2117 if (IsSigned) {
2118 // Use two dots
2119 unsigned LowOpc = WebAssemblyISD::EXTEND_LOW_S;
2120 unsigned HighOpc = WebAssemblyISD::EXTEND_HIGH_S;
2121 SDValue LowLHS = DAG.getNode(LowOpc, DL, MVT::v8i16, ExtendInLHS);
2122 SDValue LowRHS = DAG.getNode(LowOpc, DL, MVT::v8i16, ExtendInRHS);
2123 SDValue HighLHS = DAG.getNode(HighOpc, DL, MVT::v8i16, ExtendInLHS);
2124 SDValue HighRHS = DAG.getNode(HighOpc, DL, MVT::v8i16, ExtendInRHS);
2125 SDValue DotLHS =
2126 DAG.getNode(WebAssemblyISD::DOT, DL, MVT::v4i32, LowLHS, LowRHS);
2127 SDValue DotRHS =
2128 DAG.getNode(WebAssemblyISD::DOT, DL, MVT::v4i32, HighLHS, HighRHS);
2129 SDValue Add = DAG.getNode(ISD::ADD, DL, MVT::v4i32, DotLHS, DotRHS);
2130 return DAG.getNode(ISD::ADD, DL, MVT::v4i32, N->getOperand(1), Add);
2131 }
2132
2133 unsigned LowOpc = WebAssemblyISD::EXTEND_LOW_U;
2134 unsigned HighOpc = WebAssemblyISD::EXTEND_HIGH_U;
2135 SDValue LowLHS = DAG.getNode(LowOpc, DL, MVT::v8i16, ExtendInLHS);
2136 SDValue LowRHS = DAG.getNode(LowOpc, DL, MVT::v8i16, ExtendInRHS);
2137 SDValue HighLHS = DAG.getNode(HighOpc, DL, MVT::v8i16, ExtendInLHS);
2138 SDValue HighRHS = DAG.getNode(HighOpc, DL, MVT::v8i16, ExtendInRHS);
2139
2140 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
2141 SDValue MulHigh = DAG.getNode(ISD::MUL, DL, MVT::v8i16, HighLHS, HighRHS);
2142
2143 SDValue LowLow = DAG.getNode(LowOpc, DL, MVT::v4i32, MulLow);
2144 SDValue LowHigh = DAG.getNode(LowOpc, DL, MVT::v4i32, MulHigh);
2145 SDValue HighLow = DAG.getNode(HighOpc, DL, MVT::v4i32, MulLow);
2146 SDValue HighHigh = DAG.getNode(HighOpc, DL, MVT::v4i32, MulHigh);
2147
2148 SDValue AddLow = DAG.getNode(ISD::ADD, DL, MVT::v4i32, LowLow, HighLow);
2149 SDValue AddHigh = DAG.getNode(ISD::ADD, DL, MVT::v4i32, LowHigh, HighHigh);
2150 SDValue Add = DAG.getNode(ISD::ADD, DL, MVT::v4i32, AddLow, AddHigh);
2151 return DAG.getNode(ISD::ADD, DL, MVT::v4i32, N->getOperand(1), Add);
2152 }
2153}
2154
2155SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
2156 SelectionDAG &DAG) const {
2158 unsigned IntNo;
2159 switch (Op.getOpcode()) {
2162 IntNo = Op.getConstantOperandVal(1);
2163 break;
2165 IntNo = Op.getConstantOperandVal(0);
2166 break;
2167 default:
2168 llvm_unreachable("Invalid intrinsic");
2169 }
2170 SDLoc DL(Op);
2171
2172 switch (IntNo) {
2173 default:
2174 return SDValue(); // Don't custom lower most intrinsics.
2175
2176 case Intrinsic::wasm_lsda: {
2177 auto PtrVT = getPointerTy(MF.getDataLayout());
2178 const char *SymName = MF.createExternalSymbolName(
2179 "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
2180 if (isPositionIndependent()) {
2182 SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
2183 const char *BaseName = MF.createExternalSymbolName("__memory_base");
2185 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2186 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2187 SDValue SymAddr =
2188 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
2189 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
2190 }
2191 SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
2192 return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
2193 }
2194
2195 case Intrinsic::wasm_shuffle: {
2196 // Drop in-chain and replace undefs, but otherwise pass through unchanged
2197 SDValue Ops[18];
2198 size_t OpIdx = 0;
2199 Ops[OpIdx++] = Op.getOperand(1);
2200 Ops[OpIdx++] = Op.getOperand(2);
2201 while (OpIdx < 18) {
2202 const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
2203 if (MaskIdx.isUndef() || MaskIdx.getNode()->getAsZExtVal() >= 32) {
2204 bool isTarget = MaskIdx.getNode()->getOpcode() == ISD::TargetConstant;
2205 Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32, isTarget);
2206 } else {
2207 Ops[OpIdx++] = MaskIdx;
2208 }
2209 }
2210 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2211 }
2212
2213 case Intrinsic::thread_pointer: {
2214 MVT PtrVT = getPointerTy(DAG.getDataLayout());
2215 auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
2216 : WebAssembly::GLOBAL_GET_I32;
2217 const char *TlsBase = MF.createExternalSymbolName("__tls_base");
2218 return SDValue(
2219 DAG.getMachineNode(GlobalGet, DL, PtrVT,
2220 DAG.getTargetExternalSymbol(TlsBase, PtrVT)),
2221 0);
2222 }
2223 }
2224}
2225
2226SDValue
2227WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
2228 SelectionDAG &DAG) const {
2229 SDLoc DL(Op);
2230 // If sign extension operations are disabled, allow sext_inreg only if operand
2231 // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
2232 // extension operations, but allowing sext_inreg in this context lets us have
2233 // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
2234 // everywhere would be simpler in this file, but would necessitate large and
2235 // brittle patterns to undo the expansion and select extract_lane_s
2236 // instructions.
2237 assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
2238 if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2239 return SDValue();
2240
2241 const SDValue &Extract = Op.getOperand(0);
2242 MVT VecT = Extract.getOperand(0).getSimpleValueType();
2243 if (VecT.getVectorElementType().getSizeInBits() > 32)
2244 return SDValue();
2245 MVT ExtractedLaneT =
2246 cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
2247 MVT ExtractedVecT =
2248 MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
2249 if (ExtractedVecT == VecT)
2250 return Op;
2251
2252 // Bitcast vector to appropriate type to ensure ISel pattern coverage
2253 const SDNode *Index = Extract.getOperand(1).getNode();
2254 if (!isa<ConstantSDNode>(Index))
2255 return SDValue();
2256 unsigned IndexVal = Index->getAsZExtVal();
2257 unsigned Scale =
2258 ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
2259 assert(Scale > 1);
2260 SDValue NewIndex =
2261 DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
2262 SDValue NewExtract = DAG.getNode(
2264 DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
2265 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
2266 Op.getOperand(1));
2267}
2268
2269SDValue
2270WebAssemblyTargetLowering::LowerEXTEND_VECTOR_INREG(SDValue Op,
2271 SelectionDAG &DAG) const {
2272 SDLoc DL(Op);
2273 EVT VT = Op.getValueType();
2274 SDValue Src = Op.getOperand(0);
2275 EVT SrcVT = Src.getValueType();
2276
2277 if (SrcVT.getVectorElementType() == MVT::i1 ||
2278 SrcVT.getVectorElementType() == MVT::i64)
2279 return SDValue();
2280
2281 assert(VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits() == 0 &&
2282 "Unexpected extension factor.");
2283 unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits();
2284
2285 if (Scale != 2 && Scale != 4 && Scale != 8)
2286 return SDValue();
2287
2288 unsigned Ext;
2289 switch (Op.getOpcode()) {
2291 Ext = WebAssemblyISD::EXTEND_LOW_U;
2292 break;
2294 Ext = WebAssemblyISD::EXTEND_LOW_S;
2295 break;
2296 }
2297
2298 SDValue Ret = Src;
2299 while (Scale != 1) {
2300 Ret = DAG.getNode(Ext, DL,
2301 Ret.getValueType()
2302 .widenIntegerVectorElementType(*DAG.getContext())
2303 .getHalfNumVectorElementsVT(*DAG.getContext()),
2304 Ret);
2305 Scale /= 2;
2306 }
2307 assert(Ret.getValueType() == VT);
2308 return Ret;
2309}
2310
2312 SDLoc DL(Op);
2313 if (Op.getValueType() != MVT::v2f64)
2314 return SDValue();
2315
2316 auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec,
2317 unsigned &Index) -> bool {
2318 switch (Op.getOpcode()) {
2319 case ISD::SINT_TO_FP:
2320 Opcode = WebAssemblyISD::CONVERT_LOW_S;
2321 break;
2322 case ISD::UINT_TO_FP:
2323 Opcode = WebAssemblyISD::CONVERT_LOW_U;
2324 break;
2325 case ISD::FP_EXTEND:
2326 Opcode = WebAssemblyISD::PROMOTE_LOW;
2327 break;
2328 default:
2329 return false;
2330 }
2331
2332 auto ExtractVector = Op.getOperand(0);
2333 if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2334 return false;
2335
2336 if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode()))
2337 return false;
2338
2339 SrcVec = ExtractVector.getOperand(0);
2340 Index = ExtractVector.getConstantOperandVal(1);
2341 return true;
2342 };
2343
2344 unsigned LHSOpcode, RHSOpcode, LHSIndex, RHSIndex;
2345 SDValue LHSSrcVec, RHSSrcVec;
2346 if (!GetConvertedLane(Op.getOperand(0), LHSOpcode, LHSSrcVec, LHSIndex) ||
2347 !GetConvertedLane(Op.getOperand(1), RHSOpcode, RHSSrcVec, RHSIndex))
2348 return SDValue();
2349
2350 if (LHSOpcode != RHSOpcode)
2351 return SDValue();
2352
2353 MVT ExpectedSrcVT;
2354 switch (LHSOpcode) {
2355 case WebAssemblyISD::CONVERT_LOW_S:
2356 case WebAssemblyISD::CONVERT_LOW_U:
2357 ExpectedSrcVT = MVT::v4i32;
2358 break;
2359 case WebAssemblyISD::PROMOTE_LOW:
2360 ExpectedSrcVT = MVT::v4f32;
2361 break;
2362 }
2363 if (LHSSrcVec.getValueType() != ExpectedSrcVT)
2364 return SDValue();
2365
2366 auto Src = LHSSrcVec;
2367 if (LHSIndex != 0 || RHSIndex != 1 || LHSSrcVec != RHSSrcVec) {
2368 // Shuffle the source vector so that the converted lanes are the low lanes.
2369 Src = DAG.getVectorShuffle(
2370 ExpectedSrcVT, DL, LHSSrcVec, RHSSrcVec,
2371 {static_cast<int>(LHSIndex), static_cast<int>(RHSIndex) + 4, -1, -1});
2372 }
2373 return DAG.getNode(LHSOpcode, DL, MVT::v2f64, Src);
2374}
2375
2376SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
2377 SelectionDAG &DAG) const {
2378 MVT VT = Op.getSimpleValueType();
2379 if (VT == MVT::v8f16) {
2380 // BUILD_VECTOR can't handle FP16 operands since Wasm doesn't have a scaler
2381 // FP16 type, so cast them to I16s.
2382 MVT IVT = VT.changeVectorElementType(MVT::i16);
2384 for (unsigned I = 0, E = Op.getNumOperands(); I < E; ++I)
2385 NewOps.push_back(DAG.getBitcast(MVT::i16, Op.getOperand(I)));
2386 SDValue Res = DAG.getNode(ISD::BUILD_VECTOR, SDLoc(), IVT, NewOps);
2387 return DAG.getBitcast(VT, Res);
2388 }
2389
2390 if (auto ConvertLow = LowerConvertLow(Op, DAG))
2391 return ConvertLow;
2392
2393 SDLoc DL(Op);
2394 const EVT VecT = Op.getValueType();
2395 const EVT LaneT = Op.getOperand(0).getValueType();
2396 const size_t Lanes = Op.getNumOperands();
2397 bool CanSwizzle = VecT == MVT::v16i8;
2398
2399 // BUILD_VECTORs are lowered to the instruction that initializes the highest
2400 // possible number of lanes at once followed by a sequence of replace_lane
2401 // instructions to individually initialize any remaining lanes.
2402
2403 // TODO: Tune this. For example, lanewise swizzling is very expensive, so
2404 // swizzled lanes should be given greater weight.
2405
2406 // TODO: Investigate looping rather than always extracting/replacing specific
2407 // lanes to fill gaps.
2408
2409 auto IsConstant = [](const SDValue &V) {
2410 return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
2411 };
2412
2413 // Returns the source vector and index vector pair if they exist. Checks for:
2414 // (extract_vector_elt
2415 // $src,
2416 // (sign_extend_inreg (extract_vector_elt $indices, $i))
2417 // )
2418 auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
2419 auto Bail = std::make_pair(SDValue(), SDValue());
2420 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2421 return Bail;
2422 const SDValue &SwizzleSrc = Lane->getOperand(0);
2423 const SDValue &IndexExt = Lane->getOperand(1);
2424 if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
2425 return Bail;
2426 const SDValue &Index = IndexExt->getOperand(0);
2427 if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2428 return Bail;
2429 const SDValue &SwizzleIndices = Index->getOperand(0);
2430 if (SwizzleSrc.getValueType() != MVT::v16i8 ||
2431 SwizzleIndices.getValueType() != MVT::v16i8 ||
2432 Index->getOperand(1)->getOpcode() != ISD::Constant ||
2433 Index->getConstantOperandVal(1) != I)
2434 return Bail;
2435 return std::make_pair(SwizzleSrc, SwizzleIndices);
2436 };
2437
2438 // If the lane is extracted from another vector at a constant index, return
2439 // that vector. The source vector must not have more lanes than the dest
2440 // because the shufflevector indices are in terms of the destination lanes and
2441 // would not be able to address the smaller individual source lanes.
2442 auto GetShuffleSrc = [&](const SDValue &Lane) {
2443 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2444 return SDValue();
2445 if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode()))
2446 return SDValue();
2447 if (Lane->getOperand(0).getValueType().getVectorNumElements() >
2448 VecT.getVectorNumElements())
2449 return SDValue();
2450 return Lane->getOperand(0);
2451 };
2452
2453 using ValueEntry = std::pair<SDValue, size_t>;
2454 SmallVector<ValueEntry, 16> SplatValueCounts;
2455
2456 using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
2457 SmallVector<SwizzleEntry, 16> SwizzleCounts;
2458
2459 using ShuffleEntry = std::pair<SDValue, size_t>;
2460 SmallVector<ShuffleEntry, 16> ShuffleCounts;
2461
2462 auto AddCount = [](auto &Counts, const auto &Val) {
2463 auto CountIt =
2464 llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; });
2465 if (CountIt == Counts.end()) {
2466 Counts.emplace_back(Val, 1);
2467 } else {
2468 CountIt->second++;
2469 }
2470 };
2471
2472 auto GetMostCommon = [](auto &Counts) {
2473 auto CommonIt =
2474 std::max_element(Counts.begin(), Counts.end(), llvm::less_second());
2475 assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
2476 return *CommonIt;
2477 };
2478
2479 size_t NumConstantLanes = 0;
2480
2481 // Count eligible lanes for each type of vector creation op
2482 for (size_t I = 0; I < Lanes; ++I) {
2483 const SDValue &Lane = Op->getOperand(I);
2484 if (Lane.isUndef())
2485 continue;
2486
2487 AddCount(SplatValueCounts, Lane);
2488
2489 if (IsConstant(Lane))
2490 NumConstantLanes++;
2491 if (auto ShuffleSrc = GetShuffleSrc(Lane))
2492 AddCount(ShuffleCounts, ShuffleSrc);
2493 if (CanSwizzle) {
2494 auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
2495 if (SwizzleSrcs.first)
2496 AddCount(SwizzleCounts, SwizzleSrcs);
2497 }
2498 }
2499
2500 SDValue SplatValue;
2501 size_t NumSplatLanes;
2502 std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
2503
2504 SDValue SwizzleSrc;
2505 SDValue SwizzleIndices;
2506 size_t NumSwizzleLanes = 0;
2507 if (SwizzleCounts.size())
2508 std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
2509 NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
2510
2511 // Shuffles can draw from up to two vectors, so find the two most common
2512 // sources.
2513 SDValue ShuffleSrc1, ShuffleSrc2;
2514 size_t NumShuffleLanes = 0;
2515 if (ShuffleCounts.size()) {
2516 std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts);
2517 llvm::erase_if(ShuffleCounts,
2518 [&](const auto &Pair) { return Pair.first == ShuffleSrc1; });
2519 }
2520 if (ShuffleCounts.size()) {
2521 size_t AdditionalShuffleLanes;
2522 std::tie(ShuffleSrc2, AdditionalShuffleLanes) =
2523 GetMostCommon(ShuffleCounts);
2524 NumShuffleLanes += AdditionalShuffleLanes;
2525 }
2526
2527 // Predicate returning true if the lane is properly initialized by the
2528 // original instruction
2529 std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
2531 // Prefer swizzles over shuffles over vector consts over splats
2532 if (NumSwizzleLanes >= NumShuffleLanes &&
2533 NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) {
2534 Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
2535 SwizzleIndices);
2536 auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
2537 IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
2538 return Swizzled == GetSwizzleSrcs(I, Lane);
2539 };
2540 } else if (NumShuffleLanes >= NumConstantLanes &&
2541 NumShuffleLanes >= NumSplatLanes) {
2542 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8;
2543 size_t DestLaneCount = VecT.getVectorNumElements();
2544 size_t Scale1 = 1;
2545 size_t Scale2 = 1;
2546 SDValue Src1 = ShuffleSrc1;
2547 SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT);
2548 if (Src1.getValueType() != VecT) {
2549 size_t LaneSize =
2551 assert(LaneSize > DestLaneSize);
2552 Scale1 = LaneSize / DestLaneSize;
2553 Src1 = DAG.getBitcast(VecT, Src1);
2554 }
2555 if (Src2.getValueType() != VecT) {
2556 size_t LaneSize =
2558 assert(LaneSize > DestLaneSize);
2559 Scale2 = LaneSize / DestLaneSize;
2560 Src2 = DAG.getBitcast(VecT, Src2);
2561 }
2562
2563 int Mask[16];
2564 assert(DestLaneCount <= 16);
2565 for (size_t I = 0; I < DestLaneCount; ++I) {
2566 const SDValue &Lane = Op->getOperand(I);
2567 SDValue Src = GetShuffleSrc(Lane);
2568 if (Src == ShuffleSrc1) {
2569 Mask[I] = Lane->getConstantOperandVal(1) * Scale1;
2570 } else if (Src && Src == ShuffleSrc2) {
2571 Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2;
2572 } else {
2573 Mask[I] = -1;
2574 }
2575 }
2576 ArrayRef<int> MaskRef(Mask, DestLaneCount);
2577 Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef);
2578 IsLaneConstructed = [&](size_t, const SDValue &Lane) {
2579 auto Src = GetShuffleSrc(Lane);
2580 return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2);
2581 };
2582 } else if (NumConstantLanes >= NumSplatLanes) {
2583 SmallVector<SDValue, 16> ConstLanes;
2584 for (const SDValue &Lane : Op->op_values()) {
2585 if (IsConstant(Lane)) {
2586 // Values may need to be fixed so that they will sign extend to be
2587 // within the expected range during ISel. Check whether the value is in
2588 // bounds based on the lane bit width and if it is out of bounds, lop
2589 // off the extra bits and subtract 2^n to reflect giving the high bit
2590 // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it
2591 // cannot possibly be out of range.
2592 auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode());
2593 int64_t Val = Const ? Const->getSExtValue() : 0;
2594 uint64_t LaneBits = 128 / Lanes;
2595 assert((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) &&
2596 "Unexpected out of bounds negative value");
2597 if (Const && LaneBits != 64 && Val > (1ll << (LaneBits - 1)) - 1) {
2598 uint64_t Mask = (1ll << LaneBits) - 1;
2599 auto NewVal = (((uint64_t)Val & Mask) - (1ll << LaneBits)) & Mask;
2600 ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT));
2601 } else {
2602 ConstLanes.push_back(Lane);
2603 }
2604 } else if (LaneT.isFloatingPoint()) {
2605 ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
2606 } else {
2607 ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
2608 }
2609 }
2610 Result = DAG.getBuildVector(VecT, DL, ConstLanes);
2611 IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) {
2612 return IsConstant(Lane);
2613 };
2614 } else {
2615 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits();
2616 if (NumSplatLanes == 1 && Op->getOperand(0) == SplatValue &&
2617 (DestLaneSize == 32 || DestLaneSize == 64)) {
2618 // Could be selected to load_zero.
2619 Result = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecT, SplatValue);
2620 } else {
2621 // Use a splat (which might be selected as a load splat)
2622 Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
2623 }
2624 IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) {
2625 return Lane == SplatValue;
2626 };
2627 }
2628
2629 assert(Result);
2630 assert(IsLaneConstructed);
2631
2632 // Add replace_lane instructions for any unhandled values
2633 for (size_t I = 0; I < Lanes; ++I) {
2634 const SDValue &Lane = Op->getOperand(I);
2635 if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
2636 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
2637 DAG.getConstant(I, DL, MVT::i32));
2638 }
2639
2640 return Result;
2641}
2642
2643SDValue
2644WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2645 SelectionDAG &DAG) const {
2646 SDLoc DL(Op);
2647 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
2648 MVT VecType = Op.getOperand(0).getSimpleValueType();
2649 assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
2650 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
2651
2652 // Space for two vector args and sixteen mask indices
2653 SDValue Ops[18];
2654 size_t OpIdx = 0;
2655 Ops[OpIdx++] = Op.getOperand(0);
2656 Ops[OpIdx++] = Op.getOperand(1);
2657
2658 // Expand mask indices to byte indices and materialize them as operands
2659 for (int M : Mask) {
2660 for (size_t J = 0; J < LaneBytes; ++J) {
2661 // Lower undefs (represented by -1 in mask) to {0..J}, which use a
2662 // whole lane of vector input, to allow further reduction at VM. E.g.
2663 // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle.
2664 uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J;
2665 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
2666 }
2667 }
2668
2669 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2670}
2671
2672SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
2673 SelectionDAG &DAG) const {
2674 SDLoc DL(Op);
2675 // The legalizer does not know how to expand the unsupported comparison modes
2676 // of i64x2 vectors, so we manually unroll them here.
2677 assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
2679 DAG.ExtractVectorElements(Op->getOperand(0), LHS);
2680 DAG.ExtractVectorElements(Op->getOperand(1), RHS);
2681 const SDValue &CC = Op->getOperand(2);
2682 auto MakeLane = [&](unsigned I) {
2683 return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
2684 DAG.getConstant(uint64_t(-1), DL, MVT::i64),
2685 DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
2686 };
2687 return DAG.getBuildVector(Op->getValueType(0), DL,
2688 {MakeLane(0), MakeLane(1)});
2689}
2690
2691SDValue
2692WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
2693 SelectionDAG &DAG) const {
2694 // Allow constant lane indices, expand variable lane indices
2695 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
2696 if (isa<ConstantSDNode>(IdxNode)) {
2697 // Ensure the index type is i32 to match the tablegen patterns
2698 uint64_t Idx = IdxNode->getAsZExtVal();
2699 SmallVector<SDValue, 3> Ops(Op.getNode()->ops());
2700 Ops[Op.getNumOperands() - 1] =
2701 DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32);
2702 return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops);
2703 }
2704 // Perform default expansion
2705 return SDValue();
2706}
2707
2709 EVT LaneT = Op.getSimpleValueType().getVectorElementType();
2710 // 32-bit and 64-bit unrolled shifts will have proper semantics
2711 if (LaneT.bitsGE(MVT::i32))
2712 return DAG.UnrollVectorOp(Op.getNode());
2713 // Otherwise mask the shift value to get proper semantics from 32-bit shift
2714 SDLoc DL(Op);
2715 size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
2716 SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
2717 unsigned ShiftOpcode = Op.getOpcode();
2718 SmallVector<SDValue, 16> ShiftedElements;
2719 DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
2720 SmallVector<SDValue, 16> ShiftElements;
2721 DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
2722 SmallVector<SDValue, 16> UnrolledOps;
2723 for (size_t i = 0; i < NumLanes; ++i) {
2724 SDValue MaskedShiftValue =
2725 DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
2726 SDValue ShiftedValue = ShiftedElements[i];
2727 if (ShiftOpcode == ISD::SRA)
2728 ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
2729 ShiftedValue, DAG.getValueType(LaneT));
2730 UnrolledOps.push_back(
2731 DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
2732 }
2733 return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
2734}
2735
2736SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
2737 SelectionDAG &DAG) const {
2738 SDLoc DL(Op);
2739
2740 // Only manually lower vector shifts
2741 assert(Op.getSimpleValueType().isVector());
2742
2743 uint64_t LaneBits = Op.getValueType().getScalarSizeInBits();
2744 auto ShiftVal = Op.getOperand(1);
2745
2746 // Try to skip bitmask operation since it is implied inside shift instruction
2747 auto SkipImpliedMask = [](SDValue MaskOp, uint64_t MaskBits) {
2748 if (MaskOp.getOpcode() != ISD::AND)
2749 return MaskOp;
2750 SDValue LHS = MaskOp.getOperand(0);
2751 SDValue RHS = MaskOp.getOperand(1);
2752 if (MaskOp.getValueType().isVector()) {
2753 APInt MaskVal;
2754 if (!ISD::isConstantSplatVector(RHS.getNode(), MaskVal))
2755 std::swap(LHS, RHS);
2756
2757 if (ISD::isConstantSplatVector(RHS.getNode(), MaskVal) &&
2758 MaskVal == MaskBits)
2759 MaskOp = LHS;
2760 } else {
2761 if (!isa<ConstantSDNode>(RHS.getNode()))
2762 std::swap(LHS, RHS);
2763
2764 auto ConstantRHS = dyn_cast<ConstantSDNode>(RHS.getNode());
2765 if (ConstantRHS && ConstantRHS->getAPIntValue() == MaskBits)
2766 MaskOp = LHS;
2767 }
2768
2769 return MaskOp;
2770 };
2771
2772 // Skip vector and operation
2773 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2774 ShiftVal = DAG.getSplatValue(ShiftVal);
2775 if (!ShiftVal)
2776 return unrollVectorShift(Op, DAG);
2777
2778 // Skip scalar and operation
2779 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2780 // Use anyext because none of the high bits can affect the shift
2781 ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
2782
2783 unsigned Opcode;
2784 switch (Op.getOpcode()) {
2785 case ISD::SHL:
2786 Opcode = WebAssemblyISD::VEC_SHL;
2787 break;
2788 case ISD::SRA:
2789 Opcode = WebAssemblyISD::VEC_SHR_S;
2790 break;
2791 case ISD::SRL:
2792 Opcode = WebAssemblyISD::VEC_SHR_U;
2793 break;
2794 default:
2795 llvm_unreachable("unexpected opcode");
2796 }
2797
2798 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
2799}
2800
2801SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op,
2802 SelectionDAG &DAG) const {
2803 SDLoc DL(Op);
2804 EVT ResT = Op.getValueType();
2805 EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
2806
2807 if ((ResT == MVT::i32 || ResT == MVT::i64) &&
2808 (SatVT == MVT::i32 || SatVT == MVT::i64))
2809 return Op;
2810
2811 if (ResT == MVT::v4i32 && SatVT == MVT::i32)
2812 return Op;
2813
2814 if (ResT == MVT::v8i16 && SatVT == MVT::i16)
2815 return Op;
2816
2817 return SDValue();
2818}
2819
2820//===----------------------------------------------------------------------===//
2821// Custom DAG combine hooks
2822//===----------------------------------------------------------------------===//
2823static SDValue
2825 auto &DAG = DCI.DAG;
2826 auto Shuffle = cast<ShuffleVectorSDNode>(N);
2827
2828 // Hoist vector bitcasts that don't change the number of lanes out of unary
2829 // shuffles, where they are less likely to get in the way of other combines.
2830 // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
2831 // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
2832 SDValue Bitcast = N->getOperand(0);
2833 if (Bitcast.getOpcode() != ISD::BITCAST)
2834 return SDValue();
2835 if (!N->getOperand(1).isUndef())
2836 return SDValue();
2837 SDValue CastOp = Bitcast.getOperand(0);
2838 EVT SrcType = CastOp.getValueType();
2839 EVT DstType = Bitcast.getValueType();
2840 if (!SrcType.is128BitVector() ||
2841 SrcType.getVectorNumElements() != DstType.getVectorNumElements())
2842 return SDValue();
2843 SDValue NewShuffle = DAG.getVectorShuffle(
2844 SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
2845 return DAG.getBitcast(DstType, NewShuffle);
2846}
2847
2848/// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get
2849/// split up into scalar instructions during legalization, and the vector
2850/// extending instructions are selected in performVectorExtendCombine below.
2851static SDValue
2854 auto &DAG = DCI.DAG;
2855 assert(N->getOpcode() == ISD::UINT_TO_FP ||
2856 N->getOpcode() == ISD::SINT_TO_FP);
2857
2858 EVT InVT = N->getOperand(0)->getValueType(0);
2859 EVT ResVT = N->getValueType(0);
2860 MVT ExtVT;
2861 if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8))
2862 ExtVT = MVT::v4i32;
2863 else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8))
2864 ExtVT = MVT::v2i32;
2865 else
2866 return SDValue();
2867
2868 unsigned Op =
2870 SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0));
2871 return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv);
2872}
2873
2874static SDValue
2876 auto &DAG = DCI.DAG;
2877 assert(N->getOpcode() == ISD::SIGN_EXTEND ||
2878 N->getOpcode() == ISD::ZERO_EXTEND);
2879
2880 // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if
2881 // possible before the extract_subvector can be expanded.
2882 auto Extract = N->getOperand(0);
2883 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR)
2884 return SDValue();
2885 auto Source = Extract.getOperand(0);
2886 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1));
2887 if (IndexNode == nullptr)
2888 return SDValue();
2889 auto Index = IndexNode->getZExtValue();
2890
2891 // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the
2892 // extracted subvector is the low or high half of its source.
2893 EVT ResVT = N->getValueType(0);
2894 if (ResVT == MVT::v8i16) {
2895 if (Extract.getValueType() != MVT::v8i8 ||
2896 Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8))
2897 return SDValue();
2898 } else if (ResVT == MVT::v4i32) {
2899 if (Extract.getValueType() != MVT::v4i16 ||
2900 Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4))
2901 return SDValue();
2902 } else if (ResVT == MVT::v2i64) {
2903 if (Extract.getValueType() != MVT::v2i32 ||
2904 Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2))
2905 return SDValue();
2906 } else {
2907 return SDValue();
2908 }
2909
2910 bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND;
2911 bool IsLow = Index == 0;
2912
2913 unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S
2914 : WebAssemblyISD::EXTEND_HIGH_S)
2915 : (IsLow ? WebAssemblyISD::EXTEND_LOW_U
2916 : WebAssemblyISD::EXTEND_HIGH_U);
2917
2918 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
2919}
2920
2921static SDValue
2923 auto &DAG = DCI.DAG;
2924
2925 auto GetWasmConversionOp = [](unsigned Op) {
2926 switch (Op) {
2928 return WebAssemblyISD::TRUNC_SAT_ZERO_S;
2930 return WebAssemblyISD::TRUNC_SAT_ZERO_U;
2931 case ISD::FP_ROUND:
2932 return WebAssemblyISD::DEMOTE_ZERO;
2933 }
2934 llvm_unreachable("unexpected op");
2935 };
2936
2937 auto IsZeroSplat = [](SDValue SplatVal) {
2938 auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode());
2939 APInt SplatValue, SplatUndef;
2940 unsigned SplatBitSize;
2941 bool HasAnyUndefs;
2942 // Endianness doesn't matter in this context because we are looking for
2943 // an all-zero value.
2944 return Splat &&
2945 Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
2946 HasAnyUndefs) &&
2947 SplatValue == 0;
2948 };
2949
2950 if (N->getOpcode() == ISD::CONCAT_VECTORS) {
2951 // Combine this:
2952 //
2953 // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0)))
2954 //
2955 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
2956 //
2957 // Or this:
2958 //
2959 // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0)))
2960 //
2961 // into (f32x4.demote_zero_f64x2 $x).
2962 EVT ResVT;
2963 EVT ExpectedConversionType;
2964 auto Conversion = N->getOperand(0);
2965 auto ConversionOp = Conversion.getOpcode();
2966 switch (ConversionOp) {
2969 ResVT = MVT::v4i32;
2970 ExpectedConversionType = MVT::v2i32;
2971 break;
2972 case ISD::FP_ROUND:
2973 ResVT = MVT::v4f32;
2974 ExpectedConversionType = MVT::v2f32;
2975 break;
2976 default:
2977 return SDValue();
2978 }
2979
2980 if (N->getValueType(0) != ResVT)
2981 return SDValue();
2982
2983 if (Conversion.getValueType() != ExpectedConversionType)
2984 return SDValue();
2985
2986 auto Source = Conversion.getOperand(0);
2987 if (Source.getValueType() != MVT::v2f64)
2988 return SDValue();
2989
2990 if (!IsZeroSplat(N->getOperand(1)) ||
2991 N->getOperand(1).getValueType() != ExpectedConversionType)
2992 return SDValue();
2993
2994 unsigned Op = GetWasmConversionOp(ConversionOp);
2995 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
2996 }
2997
2998 // Combine this:
2999 //
3000 // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32)
3001 //
3002 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3003 //
3004 // Or this:
3005 //
3006 // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0)))))
3007 //
3008 // into (f32x4.demote_zero_f64x2 $x).
3009 EVT ResVT;
3010 auto ConversionOp = N->getOpcode();
3011 switch (ConversionOp) {
3014 ResVT = MVT::v4i32;
3015 break;
3016 case ISD::FP_ROUND:
3017 ResVT = MVT::v4f32;
3018 break;
3019 default:
3020 llvm_unreachable("unexpected op");
3021 }
3022
3023 if (N->getValueType(0) != ResVT)
3024 return SDValue();
3025
3026 auto Concat = N->getOperand(0);
3027 if (Concat.getValueType() != MVT::v4f64)
3028 return SDValue();
3029
3030 auto Source = Concat.getOperand(0);
3031 if (Source.getValueType() != MVT::v2f64)
3032 return SDValue();
3033
3034 if (!IsZeroSplat(Concat.getOperand(1)) ||
3035 Concat.getOperand(1).getValueType() != MVT::v2f64)
3036 return SDValue();
3037
3038 unsigned Op = GetWasmConversionOp(ConversionOp);
3039 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
3040}
3041
3042// Helper to extract VectorWidth bits from Vec, starting from IdxVal.
3043static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
3044 const SDLoc &DL, unsigned VectorWidth) {
3045 EVT VT = Vec.getValueType();
3046 EVT ElVT = VT.getVectorElementType();
3047 unsigned Factor = VT.getSizeInBits() / VectorWidth;
3048 EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT,
3049 VT.getVectorNumElements() / Factor);
3050
3051 // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR
3052 unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits();
3053 assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2");
3054
3055 // This is the index of the first element of the VectorWidth-bit chunk
3056 // we want. Since ElemsPerChunk is a power of 2 just need to clear bits.
3057 IdxVal &= ~(ElemsPerChunk - 1);
3058
3059 // If the input is a buildvector just emit a smaller one.
3060 if (Vec.getOpcode() == ISD::BUILD_VECTOR)
3061 return DAG.getBuildVector(ResultVT, DL,
3062 Vec->ops().slice(IdxVal, ElemsPerChunk));
3063
3064 SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL);
3065 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx);
3066}
3067
3068// Helper to recursively truncate vector elements in half with NARROW_U. DstVT
3069// is the expected destination value type after recursion. In is the initial
3070// input. Note that the input should have enough leading zero bits to prevent
3071// NARROW_U from saturating results.
3073 SelectionDAG &DAG) {
3074 EVT SrcVT = In.getValueType();
3075
3076 // No truncation required, we might get here due to recursive calls.
3077 if (SrcVT == DstVT)
3078 return In;
3079
3080 unsigned SrcSizeInBits = SrcVT.getSizeInBits();
3081 unsigned NumElems = SrcVT.getVectorNumElements();
3082 if (!isPowerOf2_32(NumElems))
3083 return SDValue();
3084 assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
3085 assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation");
3086
3087 LLVMContext &Ctx = *DAG.getContext();
3088 EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2);
3089
3090 // Narrow to the largest type possible:
3091 // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u.
3092 EVT InVT = MVT::i16, OutVT = MVT::i8;
3093 if (SrcVT.getScalarSizeInBits() > 16) {
3094 InVT = MVT::i32;
3095 OutVT = MVT::i16;
3096 }
3097 unsigned SubSizeInBits = SrcSizeInBits / 2;
3098 InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits());
3099 OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits());
3100
3101 // Split lower/upper subvectors.
3102 SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits);
3103 SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits);
3104
3105 // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors.
3106 if (SrcVT.is256BitVector() && DstVT.is128BitVector()) {
3107 Lo = DAG.getBitcast(InVT, Lo);
3108 Hi = DAG.getBitcast(InVT, Hi);
3109 SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi);
3110 return DAG.getBitcast(DstVT, Res);
3111 }
3112
3113 // Recursively narrow lower/upper subvectors, concat result and narrow again.
3114 EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2);
3115 Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG);
3116 Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG);
3117
3118 PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems);
3119 SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
3120 return truncateVectorWithNARROW(DstVT, Res, DL, DAG);
3121}
3122
3125 auto &DAG = DCI.DAG;
3126
3127 SDValue In = N->getOperand(0);
3128 EVT InVT = In.getValueType();
3129 if (!InVT.isSimple())
3130 return SDValue();
3131
3132 EVT OutVT = N->getValueType(0);
3133 if (!OutVT.isVector())
3134 return SDValue();
3135
3136 EVT OutSVT = OutVT.getVectorElementType();
3137 EVT InSVT = InVT.getVectorElementType();
3138 // Currently only cover truncate to v16i8 or v8i16.
3139 if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) &&
3140 (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector()))
3141 return SDValue();
3142
3143 SDLoc DL(N);
3145 OutVT.getScalarSizeInBits());
3146 In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT));
3147 return truncateVectorWithNARROW(OutVT, In, DL, DAG);
3148}
3149
3152 auto &DAG = DCI.DAG;
3153 SDLoc DL(N);
3154 SDValue Src = N->getOperand(0);
3155 EVT VT = N->getValueType(0);
3156 EVT SrcVT = Src.getValueType();
3157
3158 // bitcast <N x i1> to iN
3159 // ==> bitmask
3160 if (DCI.isBeforeLegalize() && VT.isScalarInteger() &&
3161 SrcVT.isFixedLengthVector() && SrcVT.getScalarType() == MVT::i1) {
3162 unsigned NumElts = SrcVT.getVectorNumElements();
3163 if (NumElts != 2 && NumElts != 4 && NumElts != 8 && NumElts != 16)
3164 return SDValue();
3165 EVT Width = MVT::getIntegerVT(128 / NumElts);
3166 return DAG.getZExtOrTrunc(
3167 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3168 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32),
3169 DAG.getSExtOrTrunc(N->getOperand(0), DL,
3170 SrcVT.changeVectorElementType(Width))}),
3171 DL, VT);
3172 }
3173
3174 return SDValue();
3175}
3176
3179 auto &DAG = DCI.DAG;
3180
3181 SDValue LHS = N->getOperand(0);
3182 SDValue RHS = N->getOperand(1);
3183 ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(2))->get();
3184 SDLoc DL(N);
3185 EVT VT = N->getValueType(0);
3186
3187 // setcc (iN (bitcast (vNi1 X))), 0, ne
3188 // ==> any_true (vNi1 X)
3189 // setcc (iN (bitcast (vNi1 X))), 0, eq
3190 // ==> xor (any_true (vNi1 X)), -1
3191 // setcc (iN (bitcast (vNi1 X))), -1, eq
3192 // ==> all_true (vNi1 X)
3193 // setcc (iN (bitcast (vNi1 X))), -1, ne
3194 // ==> xor (all_true (vNi1 X)), -1
3195 if (DCI.isBeforeLegalize() && VT.isScalarInteger() &&
3196 (Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
3198 LHS->getOpcode() == ISD::BITCAST) {
3199 EVT FromVT = LHS->getOperand(0).getValueType();
3200 if (FromVT.isFixedLengthVector() &&
3201 FromVT.getVectorElementType() == MVT::i1) {
3202 int Intrin = isNullConstant(RHS) ? Intrinsic::wasm_anytrue
3203 : Intrinsic::wasm_alltrue;
3204 unsigned NumElts = FromVT.getVectorNumElements();
3205 if (NumElts != 2 && NumElts != 4 && NumElts != 8 && NumElts != 16)
3206 return SDValue();
3207 EVT Width = MVT::getIntegerVT(128 / NumElts);
3208 SDValue Ret = DAG.getZExtOrTrunc(
3209 DAG.getNode(
3210 ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3211 {DAG.getConstant(Intrin, DL, MVT::i32),
3212 DAG.getSExtOrTrunc(LHS->getOperand(0), DL,
3213 FromVT.changeVectorElementType(Width))}),
3214 DL, MVT::i1);
3215 if ((isNullConstant(RHS) && (Cond == ISD::SETEQ)) ||
3216 (isAllOnesConstant(RHS) && (Cond == ISD::SETNE))) {
3217 Ret = DAG.getNOT(DL, Ret, MVT::i1);
3218 }
3219 return DAG.getZExtOrTrunc(Ret, DL, VT);
3220 }
3221 }
3222
3223 return SDValue();
3224}
3225
3226SDValue
3227WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
3228 DAGCombinerInfo &DCI) const {
3229 switch (N->getOpcode()) {
3230 default:
3231 return SDValue();
3232 case ISD::BITCAST:
3233 return performBitcastCombine(N, DCI);
3234 case ISD::SETCC:
3235 return performSETCCCombine(N, DCI);
3237 return performVECTOR_SHUFFLECombine(N, DCI);
3238 case ISD::SIGN_EXTEND:
3239 case ISD::ZERO_EXTEND:
3240 return performVectorExtendCombine(N, DCI);
3241 case ISD::UINT_TO_FP:
3242 case ISD::SINT_TO_FP:
3243 return performVectorExtendToFPCombine(N, DCI);
3246 case ISD::FP_ROUND:
3248 return performVectorTruncZeroCombine(N, DCI);
3249 case ISD::TRUNCATE:
3250 return performTruncateCombine(N, DCI);
3252 return performLowerPartialReduction(N, DCI.DAG);
3253 }
3254}
unsigned const MachineRegisterInfo * MRI
static SDValue performTruncateCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
return RetTy
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Symbol * Sym
Definition: ELF_riscv.cpp:479
Hexagon Common GEP
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
static unsigned NumFixedArgs
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
static SDValue performVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget, const RISCVTargetLowering &TLI)
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MachineBasicBlock * LowerFPToInt(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool IsUnsigned, bool Int64, bool Float64, unsigned LoweredOpcode)
static bool callingConvSupported(CallingConv::ID CallConv)
static MachineBasicBlock * LowerMemcpy(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool Int64)
static std::optional< unsigned > IsWebAssemblyLocal(SDValue Op, SelectionDAG &DAG)
static SDValue performVectorExtendCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG)
static MachineBasicBlock * LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, const WebAssemblySubtarget *Subtarget, const TargetInstrInfo &TII)
static SDValue performVectorTruncZeroCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static bool IsWebAssemblyGlobal(SDValue Op)
static MachineBasicBlock * LowerMemset(MachineInstr &MI, DebugLoc DL, MachineBasicBlock *BB, const TargetInstrInfo &TII, bool Int64)
static SDValue performVectorExtendToFPCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get split up into scalar instr...
static SDValue LowerConvertLow(SDValue Op, SelectionDAG &DAG)
SDValue performLowerPartialReduction(SDNode *N, 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)
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
Class for arbitrary precision integers.
Definition: APInt.h:78
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition: APInt.h:306
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition: APInt.h:296
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
an instruction that atomically reads a memory location, combines it with another value,...
Definition: Instructions.h:704
@ Add
*p = old + v
Definition: Instructions.h:720
@ Or
*p = old | v
Definition: Instructions.h:728
@ Sub
*p = old - v
Definition: Instructions.h:722
@ And
*p = old & v
Definition: Instructions.h:724
@ Xor
*p = old ^ v
Definition: Instructions.h:730
BinOp getOperation() const
Definition: Instructions.h:805
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
CCState - This class holds information needed while lowering arguments and return values.
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
This class represents a function call, abstracting a target machine's calling convention.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
A debug info location.
Definition: DebugLoc.h:33
Diagnostic information for unsupported feature in backend.
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
Definition: FastISel.h:66
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:216
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition: Function.cpp:369
unsigned getAddressSpace() const
const GlobalValue * getGlobal() const
ThreadLocalMode getThreadLocalMode() const
Definition: GlobalValue.h:272
Type * getValueType() const
Definition: GlobalValue.h:297
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:48
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This class is used to represent ISD::LOAD nodes.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:198
void setNoStrip() const
Definition: MCSymbolWasm.h:66
Machine Value Type.
@ INVALID_SIMPLE_VALUE_TYPE
static auto integer_fixedlen_vector_valuetypes()
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 MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
Definition: ValueTypes.cpp:237
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)
void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
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.
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 '...
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.
MachineInstr * CreateMachineInstr(const MCInstrDesc &MCID, DebugLoc DL, bool NoImplicit=false)
CreateMachineInstr - Allocate a new MachineInstr.
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.
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 & 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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
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.
Definition: MachineInstr.h:71
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:577
iterator_range< mop_iterator > uses()
Returns a range that includes all operands which may be register uses.
Definition: MachineInstr.h:741
void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
iterator_range< mop_iterator > defs()
Returns a range over all explicit operands that are register definitions.
Definition: MachineInstr.h:730
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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
Definition: MachineInstr.h:587
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,...
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 a MachineMemOperand object describing the memory reference performed by operation.
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
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...
Definition: SelectionDAG.h:228
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:751
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
Definition: SelectionDAG.h:802
SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
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...
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),...
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.
SDValue UnrollVectorOp(SDNode *N, unsigned ResNE=0)
Utility function used by legalize and lowering to "unroll" a vector operation by splitting out the sc...
SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget=false)
Create a ConstantFPSDNode wrapping a constant value.
SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
Definition: SelectionDAG.h:761
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.
Definition: SelectionDAG.h:857
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)
Definition: SelectionDAG.h:828
const DataLayout & getDataLayout() const
Definition: SelectionDAG.h:497
SDValue getTargetFrameIndex(int FI, EVT VT)
Definition: SelectionDAG.h:756
SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
Helper function to build ISD::STORE nodes.
SDValue getBasicBlock(MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
Definition: SelectionDAG.h:498
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...
SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
SDValue getValueType(EVT)
SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
Definition: SelectionDAG.h:701
MachineFunction & getMachineFunction() const
Definition: SelectionDAG.h:492
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
Definition: SelectionDAG.h:874
SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
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
Definition: SelectionDAG.h:510
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=0, const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
SDValue getMCSymbol(MCSymbol *Sym, EVT VT)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
Definition: SelectionDAG.h:580
SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
bool empty() const
Definition: SmallVector.h:81
size_t size() const
Definition: SmallVector.h:78
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:683
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
This class is used to represent ISD::STORE nodes.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
const SDValue & getValue() const
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
TargetInstrInfo - Interface to description of machine instruction set.
Provides information about what library functions are available for the current target.
int InstructionOpcodeToISD(unsigned Opcode) const
Get the ISD node that corresponds to the Instruction class opcode.
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
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 setLibcallName(RTLIB::Libcall Call, const char *Name)
Rename the default libcall routine name for the specified libcall.
void setMinimumJumpTableEntries(unsigned Val)
Indicate the minimum number of blocks to generate jump tables.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
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...
virtual MVT getPointerMemTy(const DataLayout &DL, uint32_t AS=0) const
Return the in-memory pointer type for the given address space, defaults to the pointer type from the ...
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...
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
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.
bool verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const
virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const
Return true if folding a constant offset with the given GlobalAddress is legal.
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:80
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
bool isOSEmscripten() const
Tests whether the OS is Emscripten.
Definition: Triple.h:732
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static Type * getDoubleTy(LLVMContext &C)
bool isFunctionTy() const
True if this is an instance of FunctionType.
Definition: Type.h:255
static Type * getFloatTy(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
Definition: Use.h:35
LLVM Value Representation.
Definition: Value.h:74
const Value * stripPointerCastsAndAliases() const
Strip off pointer casts, all-zero GEPs, address space casts, and aliases.
Definition: Value.cpp:698
static std::optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
Register getFrameRegister(const MachineFunction &MF) const override
const Triple & getTargetTriple() const
const WebAssemblyInstrInfo * getInstrInfo() const override
const WebAssemblyRegisterInfo * getRegisterInfo() const override
WebAssemblyTargetLowering(const TargetMachine &TM, const WebAssemblySubtarget &STI)
MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const override
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
MVT getPointerMemTy(const DataLayout &DL, uint32_t AS=0) const override
Return the in-memory pointer type for the given address space, defaults to the pointer type from the ...
self_iterator getIterator()
Definition: ilist_node.h:132
#define INT64_MIN
Definition: DataTypes.h:74
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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.
Definition: BitmaskEnum.h:125
@ 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.
Definition: CallingConv.h:229
@ 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
@ 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:780
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
Definition: ISDOpcodes.h:1197
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
Definition: ISDOpcodes.h:1193
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition: ISDOpcodes.h:257
@ BSWAP
Byte Swap and Counting operators.
Definition: ISDOpcodes.h:744
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
Definition: ISDOpcodes.h:1226
@ ConstantFP
Definition: ISDOpcodes.h:77
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:276
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1102
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition: ISDOpcodes.h:498
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition: ISDOpcodes.h:205
@ GlobalAddress
Definition: ISDOpcodes.h:78
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition: ISDOpcodes.h:841
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition: ISDOpcodes.h:558
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition: ISDOpcodes.h:717
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition: ISDOpcodes.h:871
@ SDIVREM
SDIVREM/UDIVREM - Divide two integers and produce both a quotient and remainder result.
Definition: ISDOpcodes.h:262
@ FP16_TO_FP
FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions and truncation for half-preci...
Definition: ISDOpcodes.h:964
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
Definition: ISDOpcodes.h:954
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition: ISDOpcodes.h:236
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
Definition: ISDOpcodes.h:1494
@ GlobalTLSAddress
Definition: ISDOpcodes.h:79
@ FrameIndex
Definition: ISDOpcodes.h:80
@ SIGN_EXTEND
Conversion operators.
Definition: ISDOpcodes.h:805
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition: ISDOpcodes.h:635
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
Definition: ISDOpcodes.h:1059
@ BR_CC
BR_CC - Conditional branch.
Definition: ISDOpcodes.h:1148
@ BRIND
BRIND - Indirect branch.
Definition: ISDOpcodes.h:1123
@ BR_JT
BR_JT - Jumptable branch.
Definition: ISDOpcodes.h:1127
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition: ISDOpcodes.h:356
@ EXTRACT_ELEMENT
EXTRACT_ELEMENT - This is used to get the lower or upper (determined by a Constant,...
Definition: ISDOpcodes.h:229
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition: ISDOpcodes.h:642
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
Definition: ISDOpcodes.h:1222
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition: ISDOpcodes.h:674
@ SHL
Shift and rotation operations.
Definition: ISDOpcodes.h:735
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition: ISDOpcodes.h:615
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition: ISDOpcodes.h:588
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition: ISDOpcodes.h:550
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition: ISDOpcodes.h:209
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition: ISDOpcodes.h:811
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
Definition: ISDOpcodes.h:1282
@ FP_TO_UINT_SAT
Definition: ISDOpcodes.h:907
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition: ISDOpcodes.h:772
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
Definition: ISDOpcodes.h:1112
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition: ISDOpcodes.h:849
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition: ISDOpcodes.h:697
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition: ISDOpcodes.h:939
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition: ISDOpcodes.h:100
@ FMINIMUM
FMINIMUM/FMAXIMUM - NaN-propagating minimum/maximum that also treat -0.0 as less than 0....
Definition: ISDOpcodes.h:1050
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition: ISDOpcodes.h:887
@ TargetConstant
TargetConstant* - Like Constant*, but the DAG does not do any folding, simplification,...
Definition: ISDOpcodes.h:164
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:709
@ TRAP
TRAP - Trapping instruction.
Definition: ISDOpcodes.h:1279
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition: ISDOpcodes.h:190
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition: ISDOpcodes.h:286
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition: ISDOpcodes.h:539
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition: ISDOpcodes.h:52
@ ExternalSymbol
Definition: ISDOpcodes.h:83
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition: ISDOpcodes.h:920
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition: ISDOpcodes.h:882
@ 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:906
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition: ISDOpcodes.h:817
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
Definition: ISDOpcodes.h:1217
@ BlockAddress
Definition: ISDOpcodes.h:84
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition: ISDOpcodes.h:794
@ FCOPYSIGN
FCOPYSIGN(X, Y) - Return the value of X with the sign of Y.
Definition: ISDOpcodes.h:508
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition: ISDOpcodes.h:347
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:198
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition: ISDOpcodes.h:530
bool isExtOpcode(unsigned Opcode)
Definition: ISDOpcodes.h:1681
bool isConstantSplatVector(const SDNode *N, APInt &SplatValue)
Node predicates.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
Definition: ISDOpcodes.h:1610
ID ArrayRef< Type * > Tys
Definition: Intrinsics.h:102
OperandFlags
These are flags set on operands, but should be considered private, all access should go through the M...
Definition: MCInstrDesc.h:50
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
bool isWebAssemblyFuncrefType(const Type *Ty)
Return true if this is a WebAssembly Funcref Type.
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.
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo)
bool isValidAddressSpace(unsigned AS)
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...
bool isWasmVarAddressSpace(unsigned AS)
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
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:354
@ Offset
Definition: DWP.cpp:480
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:292
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
@ Mul
Product of integers.
@ And
Bitwise or logical AND of integers.
@ Add
Sum of integers.
DWARFExpression::Operation Op
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:217
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:1766
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:2099
void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, LLVMContext &Ctx, const DataLayout &DL, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
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:383
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
#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:94
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition: ValueTypes.h:137
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:74
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition: ValueTypes.h:147
ElementCount getVectorElementCount() const
Definition: ValueTypes.h:345
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition: ValueTypes.h:368
uint64_t getScalarSizeInBits() const
Definition: ValueTypes.h:380
static EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
Definition: ValueTypes.cpp:289
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:311
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition: ValueTypes.h:207
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition: ValueTypes.h:65
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition: ValueTypes.h:376
bool isFixedLengthVector() const
Definition: ValueTypes.h:181
bool isVector() const
Return true if this is a vector value type.
Definition: ValueTypes.h:168
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition: ValueTypes.h:318
bool bitsGE(EVT VT) const
Return true if this has no less bits than VT.
Definition: ValueTypes.h:287
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition: ValueTypes.h:212
Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
Definition: ValueTypes.cpp:210
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition: ValueTypes.h:323
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition: ValueTypes.h:157
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition: ValueTypes.h:331
bool isInConsecutiveRegs() const
Align getNonZeroOrigAlign() const
unsigned getByValSize() const
bool isInConsecutiveRegsLast() const
Align getNonZeroByValAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
OutputArg - This struct carries flags and a value for a single outgoing (actual) argument or outgoing...
bool IsFixed
IsFixed - Is this a "fixed" value, ie not passed through a vararg "...".
unsigned getBitWidth() const
Get the bit width of this value.
Definition: KnownBits.h:43
This class contains a discriminated union of information about pointers in memory operands,...
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition: Alignment.h:117
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
Function object to check whether the second component of a container supported by std::get (like std:...
Definition: STLExtras.h:1476