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