LLVM 22.0.0git
WebAssemblyISelLowering.cpp
Go to the documentation of this file.
1//=- WebAssemblyISelLowering.cpp - WebAssembly DAG Lowering Implementation -==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file implements the WebAssemblyTargetLowering class.
11///
12//===----------------------------------------------------------------------===//
13
32#include "llvm/IR/Function.h"
34#include "llvm/IR/Intrinsics.h"
35#include "llvm/IR/IntrinsicsWebAssembly.h"
40using namespace llvm;
41
42#define DEBUG_TYPE "wasm-lower"
43
45 const TargetMachine &TM, const WebAssemblySubtarget &STI)
46 : TargetLowering(TM), Subtarget(&STI) {
47 auto MVTPtr = Subtarget->hasAddr64() ? MVT::i64 : MVT::i32;
48
49 // Set the load count for memcmp expand optimization
52
53 // Booleans always contain 0 or 1.
55 // Except in SIMD vectors
57 // We don't know the microarchitecture here, so just reduce register pressure.
59 // Tell ISel that we have a stack pointer.
61 Subtarget->hasAddr64() ? WebAssembly::SP64 : WebAssembly::SP32);
62 // Set up the register classes.
63 addRegisterClass(MVT::i32, &WebAssembly::I32RegClass);
64 addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
65 addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
66 addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
67 if (Subtarget->hasSIMD128()) {
68 addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
69 addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
70 addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
71 addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
72 addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
73 addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
74 }
75 if (Subtarget->hasFP16()) {
76 addRegisterClass(MVT::v8f16, &WebAssembly::V128RegClass);
77 }
78 if (Subtarget->hasReferenceTypes()) {
79 addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
80 addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);
81 if (Subtarget->hasExceptionHandling()) {
82 addRegisterClass(MVT::exnref, &WebAssembly::EXNREFRegClass);
83 }
84 }
85 // Compute derived properties from the register classes.
86 computeRegisterProperties(Subtarget->getRegisterInfo());
87
88 // Transform loads and stores to pointers in address space 1 to loads and
89 // stores to WebAssembly global variables, outside linear memory.
90 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) {
91 setOperationAction(ISD::LOAD, T, Custom);
92 setOperationAction(ISD::STORE, T, Custom);
93 }
94 if (Subtarget->hasSIMD128()) {
95 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
96 MVT::v2f64}) {
97 setOperationAction(ISD::LOAD, T, Custom);
98 setOperationAction(ISD::STORE, T, Custom);
99 }
100 }
101 if (Subtarget->hasFP16()) {
102 setOperationAction(ISD::LOAD, MVT::v8f16, Custom);
103 setOperationAction(ISD::STORE, MVT::v8f16, Custom);
104 }
105 if (Subtarget->hasReferenceTypes()) {
106 // We need custom load and store lowering for both externref, funcref and
107 // Other. The MVT::Other here represents tables of reference types.
108 for (auto T : {MVT::externref, MVT::funcref, MVT::Other}) {
109 setOperationAction(ISD::LOAD, T, Custom);
110 setOperationAction(ISD::STORE, T, Custom);
111 }
112 }
113
119 setOperationAction(ISD::BRIND, MVT::Other, Custom);
121
122 // Take the default expansion for va_arg, va_copy, and va_end. There is no
123 // default action for va_start, so we do that custom.
124 setOperationAction(ISD::VASTART, MVT::Other, Custom);
125 setOperationAction(ISD::VAARG, MVT::Other, Expand);
126 setOperationAction(ISD::VACOPY, MVT::Other, Expand);
127 setOperationAction(ISD::VAEND, MVT::Other, Expand);
128
129 for (auto T : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64, MVT::v8f16}) {
130 if (!Subtarget->hasFP16() && T == MVT::v8f16) {
131 continue;
132 }
133 // Don't expand the floating-point types to constant pools.
135 // Expand floating-point comparisons.
136 for (auto CC : {ISD::SETO, ISD::SETUO, ISD::SETUEQ, ISD::SETONE,
139 // Expand floating-point library function operators.
140 for (auto Op :
141 {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FMA})
143 // Note supported floating-point library function operators that otherwise
144 // default to expand.
145 for (auto Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FTRUNC, ISD::FNEARBYINT,
146 ISD::FRINT, ISD::FROUNDEVEN})
148 // Support minimum and maximum, which otherwise default to expand.
149 setOperationAction(ISD::FMINIMUM, T, Legal);
150 setOperationAction(ISD::FMAXIMUM, T, Legal);
151 // When experimental v8f16 support is enabled these instructions don't need
152 // to be expanded.
153 if (T != MVT::v8f16) {
154 setOperationAction(ISD::FP16_TO_FP, T, Expand);
155 setOperationAction(ISD::FP_TO_FP16, T, Expand);
156 }
158 setTruncStoreAction(T, MVT::f16, Expand);
159 }
160
161 // Expand unavailable integer operations.
162 for (auto Op :
166 for (auto T : {MVT::i32, MVT::i64})
168 if (Subtarget->hasSIMD128())
169 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
171 }
172
173 if (Subtarget->hasWideArithmetic()) {
179 }
180
181 if (Subtarget->hasNontrappingFPToInt())
183 for (auto T : {MVT::i32, MVT::i64})
185
186 // SIMD-specific configuration
187 if (Subtarget->hasSIMD128()) {
188
190
191 // Combine wide-vector muls, with extend inputs, to extmul_half.
193
194 // Combine vector mask reductions into alltrue/anytrue
196
197 // Convert vector to integer bitcasts to bitmask
198 setTargetDAGCombine(ISD::BITCAST);
199
200 // Hoist bitcasts out of shuffles
202
203 // Combine extends of extract_subvectors into widening ops
205
206 // Combine int_to_fp or fp_extend of extract_vectors and vice versa into
207 // conversions ops
210
211 // Combine fp_to_{s,u}int_sat or fp_round of concat_vectors or vice versa
212 // into conversion ops
215
217
218 // Support saturating add/sub for i8x16 and i16x8
220 for (auto T : {MVT::v16i8, MVT::v8i16})
222
223 // Support integer abs
224 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
226
227 // Custom lower BUILD_VECTORs to minimize number of replace_lanes
228 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
229 MVT::v2f64})
231
232 if (Subtarget->hasFP16())
234
235 // We have custom shuffle lowering to expose the shuffle mask
236 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
237 MVT::v2f64})
239
240 if (Subtarget->hasFP16())
242
243 // Support splatting
244 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
245 MVT::v2f64})
247
248 setOperationAction(ISD::AVGCEILU, {MVT::v8i16, MVT::v16i8}, Legal);
249
250 // Custom lowering since wasm shifts must have a scalar shift amount
251 for (auto Op : {ISD::SHL, ISD::SRA, ISD::SRL})
252 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
254
255 // Custom lower lane accesses to expand out variable indices
257 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
258 MVT::v2f64})
260
261 // There is no i8x16.mul instruction
262 setOperationAction(ISD::MUL, MVT::v16i8, Expand);
263
264 // There is no vector conditional select instruction
265 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32, MVT::v2i64,
266 MVT::v2f64})
268
269 // Expand integer operations supported for scalars but not SIMD
270 for (auto Op :
272 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64})
274
275 // But we do have integer min and max operations
276 for (auto Op : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
277 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
279
280 // And we have popcnt for i8x16. It can be used to expand ctlz/cttz.
281 setOperationAction(ISD::CTPOP, MVT::v16i8, Legal);
282 setOperationAction(ISD::CTLZ, MVT::v16i8, Expand);
283 setOperationAction(ISD::CTTZ, MVT::v16i8, Expand);
284
285 // Custom lower bit counting operations for other types to scalarize them.
286 for (auto Op : {ISD::CTLZ, ISD::CTTZ, ISD::CTPOP})
287 for (auto T : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
289
290 // Expand float operations supported for scalars but not SIMD
291 for (auto Op : {ISD::FCOPYSIGN, ISD::FLOG, ISD::FLOG2, ISD::FLOG10,
292 ISD::FEXP, ISD::FEXP2, ISD::FEXP10})
293 for (auto T : {MVT::v4f32, MVT::v2f64})
295
296 // Unsigned comparison operations are unavailable for i64x2 vectors.
298 setCondCodeAction(CC, MVT::v2i64, Custom);
299
300 // 64x2 conversions are not in the spec
301 for (auto Op :
303 for (auto T : {MVT::v2i64, MVT::v2f64})
305
306 // But saturating fp_to_int converstions are
308 setOperationAction(Op, MVT::v4i32, Custom);
309 if (Subtarget->hasFP16()) {
310 setOperationAction(Op, MVT::v8i16, Custom);
311 }
312 }
313
314 // Support vector extending
318 }
319
320 if (Subtarget->hasFP16()) {
321 setOperationAction(ISD::FMA, MVT::v8f16, Legal);
322 }
323
324 if (Subtarget->hasRelaxedSIMD()) {
327 }
328
329 // Partial MLA reductions.
330 for (auto Op : {ISD::PARTIAL_REDUCE_SMLA, ISD::PARTIAL_REDUCE_UMLA}) {
331 setPartialReduceMLAAction(Op, MVT::v4i32, MVT::v16i8, Legal);
332 setPartialReduceMLAAction(Op, MVT::v4i32, MVT::v8i16, Legal);
333 }
334 }
335
336 // As a special case, these operators use the type to mean the type to
337 // sign-extend from.
339 if (!Subtarget->hasSignExt()) {
340 // Sign extends are legal only when extending a vector extract
341 auto Action = Subtarget->hasSIMD128() ? Custom : Expand;
342 for (auto T : {MVT::i8, MVT::i16, MVT::i32})
344 }
347
348 // Dynamic stack allocation: use the default expansion.
349 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
350 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
351 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVTPtr, Expand);
352
356
357 // Expand these forms; we pattern-match the forms that we can handle in isel.
358 for (auto T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
359 for (auto Op : {ISD::BR_CC, ISD::SELECT_CC})
361
362 // We have custom switch handling.
363 setOperationAction(ISD::BR_JT, MVT::Other, Custom);
364
365 // WebAssembly doesn't have:
366 // - Floating-point extending loads.
367 // - Floating-point truncating stores.
368 // - i1 extending loads.
369 // - truncating SIMD stores and most extending loads
370 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
371 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
372 for (auto T : MVT::integer_valuetypes())
373 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
374 setLoadExtAction(Ext, T, MVT::i1, Promote);
375 if (Subtarget->hasSIMD128()) {
376 for (auto T : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32,
377 MVT::v2f64}) {
378 for (auto MemT : MVT::fixedlen_vector_valuetypes()) {
379 if (MVT(T) != MemT) {
381 for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
382 setLoadExtAction(Ext, T, MemT, Expand);
383 }
384 }
385 }
386 // But some vector extending loads are legal
387 for (auto Ext : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
388 setLoadExtAction(Ext, MVT::v8i16, MVT::v8i8, Legal);
389 setLoadExtAction(Ext, MVT::v4i32, MVT::v4i16, Legal);
390 setLoadExtAction(Ext, MVT::v2i64, MVT::v2i32, Legal);
391 }
392 setLoadExtAction(ISD::EXTLOAD, MVT::v2f64, MVT::v2f32, Legal);
393 }
394
395 // Don't do anything clever with build_pairs
397
398 // Trap lowers to wasm unreachable
399 setOperationAction(ISD::TRAP, MVT::Other, Legal);
400 setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
401
402 // Exception handling intrinsics
406
408
409 // Always convert switches to br_tables unless there is only one case, which
410 // is equivalent to a simple branch. This reduces code size for wasm, and we
411 // defer possible jump table optimizations to the VM.
413}
414
423
432
434WebAssemblyTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
435 // We have wasm instructions for these
436 switch (AI->getOperation()) {
444 default:
445 break;
446 }
448}
449
450bool WebAssemblyTargetLowering::shouldScalarizeBinop(SDValue VecOp) const {
451 // Implementation copied from X86TargetLowering.
452 unsigned Opc = VecOp.getOpcode();
453
454 // Assume target opcodes can't be scalarized.
455 // TODO - do we have any exceptions?
457 return false;
458
459 // If the vector op is not supported, try to convert to scalar.
460 EVT VecVT = VecOp.getValueType();
462 return true;
463
464 // If the vector op is supported, but the scalar op is not, the transform may
465 // not be worthwhile.
466 EVT ScalarVT = VecVT.getScalarType();
467 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
468}
469
470FastISel *WebAssemblyTargetLowering::createFastISel(
471 FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) const {
472 return WebAssembly::createFastISel(FuncInfo, LibInfo);
473}
474
475MVT WebAssemblyTargetLowering::getScalarShiftAmountTy(const DataLayout & /*DL*/,
476 EVT VT) const {
477 unsigned BitWidth = NextPowerOf2(VT.getSizeInBits() - 1);
478 if (BitWidth > 1 && BitWidth < 8)
479 BitWidth = 8;
480
481 if (BitWidth > 64) {
482 // The shift will be lowered to a libcall, and compiler-rt libcalls expect
483 // the count to be an i32.
484 BitWidth = 32;
486 "32-bit shift counts ought to be enough for anyone");
487 }
488
491 "Unable to represent scalar shift amount type");
492 return Result;
493}
494
495// Lower an fp-to-int conversion operator from the LLVM opcode, which has an
496// undefined result on invalid/overflow, to the WebAssembly opcode, which
497// traps on invalid/overflow.
500 const TargetInstrInfo &TII,
501 bool IsUnsigned, bool Int64,
502 bool Float64, unsigned LoweredOpcode) {
504
505 Register OutReg = MI.getOperand(0).getReg();
506 Register InReg = MI.getOperand(1).getReg();
507
508 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
509 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
510 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
511 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
512 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
513 unsigned Eqz = WebAssembly::EQZ_I32;
514 unsigned And = WebAssembly::AND_I32;
515 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
516 int64_t Substitute = IsUnsigned ? 0 : Limit;
517 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
518 auto &Context = BB->getParent()->getFunction().getContext();
519 Type *Ty = Float64 ? Type::getDoubleTy(Context) : Type::getFloatTy(Context);
520
521 const BasicBlock *LLVMBB = BB->getBasicBlock();
522 MachineFunction *F = BB->getParent();
523 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
524 MachineBasicBlock *FalseMBB = F->CreateMachineBasicBlock(LLVMBB);
525 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
526
528 F->insert(It, FalseMBB);
529 F->insert(It, TrueMBB);
530 F->insert(It, DoneMBB);
531
532 // Transfer the remainder of BB and its successor edges to DoneMBB.
533 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
535
536 BB->addSuccessor(TrueMBB);
537 BB->addSuccessor(FalseMBB);
538 TrueMBB->addSuccessor(DoneMBB);
539 FalseMBB->addSuccessor(DoneMBB);
540
541 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
542 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
543 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
544 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
545 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
546 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
547 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
548
549 MI.eraseFromParent();
550 // For signed numbers, we can do a single comparison to determine whether
551 // fabs(x) is within range.
552 if (IsUnsigned) {
553 Tmp0 = InReg;
554 } else {
555 BuildMI(BB, DL, TII.get(Abs), Tmp0).addReg(InReg);
556 }
557 BuildMI(BB, DL, TII.get(FConst), Tmp1)
558 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
559 BuildMI(BB, DL, TII.get(LT), CmpReg).addReg(Tmp0).addReg(Tmp1);
560
561 // For unsigned numbers, we have to do a separate comparison with zero.
562 if (IsUnsigned) {
563 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
564 Register SecondCmpReg =
565 MRI.createVirtualRegister(&WebAssembly::I32RegClass);
566 Register AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
567 BuildMI(BB, DL, TII.get(FConst), Tmp1)
568 .addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
569 BuildMI(BB, DL, TII.get(GE), SecondCmpReg).addReg(Tmp0).addReg(Tmp1);
570 BuildMI(BB, DL, TII.get(And), AndReg).addReg(CmpReg).addReg(SecondCmpReg);
571 CmpReg = AndReg;
572 }
573
574 BuildMI(BB, DL, TII.get(Eqz), EqzReg).addReg(CmpReg);
575
576 // Create the CFG diamond to select between doing the conversion or using
577 // the substitute value.
578 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(TrueMBB).addReg(EqzReg);
579 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg).addReg(InReg);
580 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
581 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg).addImm(Substitute);
582 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
583 .addReg(FalseReg)
584 .addMBB(FalseMBB)
585 .addReg(TrueReg)
586 .addMBB(TrueMBB);
587
588 return DoneMBB;
589}
590
591// Lower a `MEMCPY` instruction into a CFG triangle around a `MEMORY_COPY`
592// instuction to handle the zero-length case.
595 const TargetInstrInfo &TII, bool Int64) {
597
598 MachineOperand DstMem = MI.getOperand(0);
599 MachineOperand SrcMem = MI.getOperand(1);
600 MachineOperand Dst = MI.getOperand(2);
601 MachineOperand Src = MI.getOperand(3);
602 MachineOperand Len = MI.getOperand(4);
603
604 // If the length is a constant, we don't actually need the check.
605 if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
606 if (Def->getOpcode() == WebAssembly::CONST_I32 ||
607 Def->getOpcode() == WebAssembly::CONST_I64) {
608 if (Def->getOperand(1).getImm() == 0) {
609 // A zero-length memcpy is a no-op.
610 MI.eraseFromParent();
611 return BB;
612 }
613 // A non-zero-length memcpy doesn't need a zero check.
614 unsigned MemoryCopy =
615 Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
616 BuildMI(*BB, MI, DL, TII.get(MemoryCopy))
617 .add(DstMem)
618 .add(SrcMem)
619 .add(Dst)
620 .add(Src)
621 .add(Len);
622 MI.eraseFromParent();
623 return BB;
624 }
625 }
626
627 // We're going to add an extra use to `Len` to test if it's zero; that
628 // use shouldn't be a kill, even if the original use is.
629 MachineOperand NoKillLen = Len;
630 NoKillLen.setIsKill(false);
631
632 // Decide on which `MachineInstr` opcode we're going to use.
633 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
634 unsigned MemoryCopy =
635 Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
636
637 // Create two new basic blocks; one for the new `memory.fill` that we can
638 // branch over, and one for the rest of the instructions after the original
639 // `memory.fill`.
640 const BasicBlock *LLVMBB = BB->getBasicBlock();
641 MachineFunction *F = BB->getParent();
642 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
643 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
644
646 F->insert(It, TrueMBB);
647 F->insert(It, DoneMBB);
648
649 // Transfer the remainder of BB and its successor edges to DoneMBB.
650 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
652
653 // Connect the CFG edges.
654 BB->addSuccessor(TrueMBB);
655 BB->addSuccessor(DoneMBB);
656 TrueMBB->addSuccessor(DoneMBB);
657
658 // Create a virtual register for the `Eqz` result.
659 unsigned EqzReg;
660 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
661
662 // Erase the original `memory.copy`.
663 MI.eraseFromParent();
664
665 // Test if `Len` is zero.
666 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
667
668 // Insert a new `memory.copy`.
669 BuildMI(TrueMBB, DL, TII.get(MemoryCopy))
670 .add(DstMem)
671 .add(SrcMem)
672 .add(Dst)
673 .add(Src)
674 .add(Len);
675
676 // Create the CFG triangle.
677 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
678 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
679
680 return DoneMBB;
681}
682
683// Lower a `MEMSET` instruction into a CFG triangle around a `MEMORY_FILL`
684// instuction to handle the zero-length case.
687 const TargetInstrInfo &TII, bool Int64) {
689
690 MachineOperand Mem = MI.getOperand(0);
691 MachineOperand Dst = MI.getOperand(1);
692 MachineOperand Val = MI.getOperand(2);
693 MachineOperand Len = MI.getOperand(3);
694
695 // If the length is a constant, we don't actually need the check.
696 if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
697 if (Def->getOpcode() == WebAssembly::CONST_I32 ||
698 Def->getOpcode() == WebAssembly::CONST_I64) {
699 if (Def->getOperand(1).getImm() == 0) {
700 // A zero-length memset is a no-op.
701 MI.eraseFromParent();
702 return BB;
703 }
704 // A non-zero-length memset doesn't need a zero check.
705 unsigned MemoryFill =
706 Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
707 BuildMI(*BB, MI, DL, TII.get(MemoryFill))
708 .add(Mem)
709 .add(Dst)
710 .add(Val)
711 .add(Len);
712 MI.eraseFromParent();
713 return BB;
714 }
715 }
716
717 // We're going to add an extra use to `Len` to test if it's zero; that
718 // use shouldn't be a kill, even if the original use is.
719 MachineOperand NoKillLen = Len;
720 NoKillLen.setIsKill(false);
721
722 // Decide on which `MachineInstr` opcode we're going to use.
723 unsigned Eqz = Int64 ? WebAssembly::EQZ_I64 : WebAssembly::EQZ_I32;
724 unsigned MemoryFill =
725 Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
726
727 // Create two new basic blocks; one for the new `memory.fill` that we can
728 // branch over, and one for the rest of the instructions after the original
729 // `memory.fill`.
730 const BasicBlock *LLVMBB = BB->getBasicBlock();
731 MachineFunction *F = BB->getParent();
732 MachineBasicBlock *TrueMBB = F->CreateMachineBasicBlock(LLVMBB);
733 MachineBasicBlock *DoneMBB = F->CreateMachineBasicBlock(LLVMBB);
734
736 F->insert(It, TrueMBB);
737 F->insert(It, DoneMBB);
738
739 // Transfer the remainder of BB and its successor edges to DoneMBB.
740 DoneMBB->splice(DoneMBB->begin(), BB, std::next(MI.getIterator()), BB->end());
742
743 // Connect the CFG edges.
744 BB->addSuccessor(TrueMBB);
745 BB->addSuccessor(DoneMBB);
746 TrueMBB->addSuccessor(DoneMBB);
747
748 // Create a virtual register for the `Eqz` result.
749 unsigned EqzReg;
750 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
751
752 // Erase the original `memory.fill`.
753 MI.eraseFromParent();
754
755 // Test if `Len` is zero.
756 BuildMI(BB, DL, TII.get(Eqz), EqzReg).add(NoKillLen);
757
758 // Insert a new `memory.copy`.
759 BuildMI(TrueMBB, DL, TII.get(MemoryFill)).add(Mem).add(Dst).add(Val).add(Len);
760
761 // Create the CFG triangle.
762 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)).addMBB(DoneMBB).addReg(EqzReg);
763 BuildMI(TrueMBB, DL, TII.get(WebAssembly::BR)).addMBB(DoneMBB);
764
765 return DoneMBB;
766}
767
768static MachineBasicBlock *
770 const WebAssemblySubtarget *Subtarget,
771 const TargetInstrInfo &TII) {
772 MachineInstr &CallParams = *CallResults.getPrevNode();
773 assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
774 assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
775 CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS);
776
777 bool IsIndirect =
778 CallParams.getOperand(0).isReg() || CallParams.getOperand(0).isFI();
779 bool IsRetCall = CallResults.getOpcode() == WebAssembly::RET_CALL_RESULTS;
780
781 bool IsFuncrefCall = false;
782 if (IsIndirect && CallParams.getOperand(0).isReg()) {
783 Register Reg = CallParams.getOperand(0).getReg();
784 const MachineFunction *MF = BB->getParent();
785 const MachineRegisterInfo &MRI = MF->getRegInfo();
786 const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
787 IsFuncrefCall = (TRC == &WebAssembly::FUNCREFRegClass);
788 assert(!IsFuncrefCall || Subtarget->hasReferenceTypes());
789 }
790
791 unsigned CallOp;
792 if (IsIndirect && IsRetCall) {
793 CallOp = WebAssembly::RET_CALL_INDIRECT;
794 } else if (IsIndirect) {
795 CallOp = WebAssembly::CALL_INDIRECT;
796 } else if (IsRetCall) {
797 CallOp = WebAssembly::RET_CALL;
798 } else {
799 CallOp = WebAssembly::CALL;
800 }
801
802 MachineFunction &MF = *BB->getParent();
803 const MCInstrDesc &MCID = TII.get(CallOp);
804 MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
805
806 // Move the function pointer to the end of the arguments for indirect calls
807 if (IsIndirect) {
808 auto FnPtr = CallParams.getOperand(0);
809 CallParams.removeOperand(0);
810
811 // For funcrefs, call_indirect is done through __funcref_call_table and the
812 // funcref is always installed in slot 0 of the table, therefore instead of
813 // having the function pointer added at the end of the params list, a zero
814 // (the index in
815 // __funcref_call_table is added).
816 if (IsFuncrefCall) {
817 Register RegZero =
818 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
819 MachineInstrBuilder MIBC0 =
820 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
821
822 BB->insert(CallResults.getIterator(), MIBC0);
823 MachineInstrBuilder(MF, CallParams).addReg(RegZero);
824 } else
825 CallParams.addOperand(FnPtr);
826 }
827
828 for (auto Def : CallResults.defs())
829 MIB.add(Def);
830
831 if (IsIndirect) {
832 // Placeholder for the type index.
833 // This gets replaced with the correct value in WebAssemblyMCInstLower.cpp
834 MIB.addImm(0);
835 // The table into which this call_indirect indexes.
836 MCSymbolWasm *Table = IsFuncrefCall
838 MF.getContext(), Subtarget)
840 MF.getContext(), Subtarget);
841 if (Subtarget->hasCallIndirectOverlong()) {
842 MIB.addSym(Table);
843 } else {
844 // For the MVP there is at most one table whose number is 0, but we can't
845 // write a table symbol or issue relocations. Instead we just ensure the
846 // table is live and write a zero.
847 Table->setNoStrip();
848 MIB.addImm(0);
849 }
850 }
851
852 for (auto Use : CallParams.uses())
853 MIB.add(Use);
854
855 BB->insert(CallResults.getIterator(), MIB);
856 CallParams.eraseFromParent();
857 CallResults.eraseFromParent();
858
859 // If this is a funcref call, to avoid hidden GC roots, we need to clear the
860 // table slot with ref.null upon call_indirect return.
861 //
862 // This generates the following code, which comes right after a call_indirect
863 // of a funcref:
864 //
865 // i32.const 0
866 // ref.null func
867 // table.set __funcref_call_table
868 if (IsIndirect && IsFuncrefCall) {
870 MF.getContext(), Subtarget);
871 Register RegZero =
872 MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
873 MachineInstr *Const0 =
874 BuildMI(MF, DL, TII.get(WebAssembly::CONST_I32), RegZero).addImm(0);
875 BB->insertAfter(MIB.getInstr()->getIterator(), Const0);
876
877 Register RegFuncref =
878 MF.getRegInfo().createVirtualRegister(&WebAssembly::FUNCREFRegClass);
879 MachineInstr *RefNull =
880 BuildMI(MF, DL, TII.get(WebAssembly::REF_NULL_FUNCREF), RegFuncref);
881 BB->insertAfter(Const0->getIterator(), RefNull);
882
883 MachineInstr *TableSet =
884 BuildMI(MF, DL, TII.get(WebAssembly::TABLE_SET_FUNCREF))
885 .addSym(Table)
886 .addReg(RegZero)
887 .addReg(RegFuncref);
888 BB->insertAfter(RefNull->getIterator(), TableSet);
889 }
890
891 return BB;
892}
893
894MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
895 MachineInstr &MI, MachineBasicBlock *BB) const {
896 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
897 DebugLoc DL = MI.getDebugLoc();
898
899 switch (MI.getOpcode()) {
900 default:
901 llvm_unreachable("Unexpected instr type to insert");
902 case WebAssembly::FP_TO_SINT_I32_F32:
903 return LowerFPToInt(MI, DL, BB, TII, false, false, false,
904 WebAssembly::I32_TRUNC_S_F32);
905 case WebAssembly::FP_TO_UINT_I32_F32:
906 return LowerFPToInt(MI, DL, BB, TII, true, false, false,
907 WebAssembly::I32_TRUNC_U_F32);
908 case WebAssembly::FP_TO_SINT_I64_F32:
909 return LowerFPToInt(MI, DL, BB, TII, false, true, false,
910 WebAssembly::I64_TRUNC_S_F32);
911 case WebAssembly::FP_TO_UINT_I64_F32:
912 return LowerFPToInt(MI, DL, BB, TII, true, true, false,
913 WebAssembly::I64_TRUNC_U_F32);
914 case WebAssembly::FP_TO_SINT_I32_F64:
915 return LowerFPToInt(MI, DL, BB, TII, false, false, true,
916 WebAssembly::I32_TRUNC_S_F64);
917 case WebAssembly::FP_TO_UINT_I32_F64:
918 return LowerFPToInt(MI, DL, BB, TII, true, false, true,
919 WebAssembly::I32_TRUNC_U_F64);
920 case WebAssembly::FP_TO_SINT_I64_F64:
921 return LowerFPToInt(MI, DL, BB, TII, false, true, true,
922 WebAssembly::I64_TRUNC_S_F64);
923 case WebAssembly::FP_TO_UINT_I64_F64:
924 return LowerFPToInt(MI, DL, BB, TII, true, true, true,
925 WebAssembly::I64_TRUNC_U_F64);
926 case WebAssembly::MEMCPY_A32:
927 return LowerMemcpy(MI, DL, BB, TII, false);
928 case WebAssembly::MEMCPY_A64:
929 return LowerMemcpy(MI, DL, BB, TII, true);
930 case WebAssembly::MEMSET_A32:
931 return LowerMemset(MI, DL, BB, TII, false);
932 case WebAssembly::MEMSET_A64:
933 return LowerMemset(MI, DL, BB, TII, true);
934 case WebAssembly::CALL_RESULTS:
935 case WebAssembly::RET_CALL_RESULTS:
936 return LowerCallResults(MI, DL, BB, Subtarget, TII);
937 }
938}
939
940const char *
941WebAssemblyTargetLowering::getTargetNodeName(unsigned Opcode) const {
942 switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) {
944 break;
945#define HANDLE_NODETYPE(NODE) \
946 case WebAssemblyISD::NODE: \
947 return "WebAssemblyISD::" #NODE;
948#include "WebAssemblyISD.def"
949#undef HANDLE_NODETYPE
950 }
951 return nullptr;
952}
953
954std::pair<unsigned, const TargetRegisterClass *>
955WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
956 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
957 // First, see if this is a constraint that directly corresponds to a
958 // WebAssembly register class.
959 if (Constraint.size() == 1) {
960 switch (Constraint[0]) {
961 case 'r':
962 assert(VT != MVT::iPTR && "Pointer MVT not expected here");
963 if (Subtarget->hasSIMD128() && VT.isVector()) {
964 if (VT.getSizeInBits() == 128)
965 return std::make_pair(0U, &WebAssembly::V128RegClass);
966 }
967 if (VT.isInteger() && !VT.isVector()) {
968 if (VT.getSizeInBits() <= 32)
969 return std::make_pair(0U, &WebAssembly::I32RegClass);
970 if (VT.getSizeInBits() <= 64)
971 return std::make_pair(0U, &WebAssembly::I64RegClass);
972 }
973 if (VT.isFloatingPoint() && !VT.isVector()) {
974 switch (VT.getSizeInBits()) {
975 case 32:
976 return std::make_pair(0U, &WebAssembly::F32RegClass);
977 case 64:
978 return std::make_pair(0U, &WebAssembly::F64RegClass);
979 default:
980 break;
981 }
982 }
983 break;
984 default:
985 break;
986 }
987 }
988
990}
991
992bool WebAssemblyTargetLowering::isCheapToSpeculateCttz(Type *Ty) const {
993 // Assume ctz is a relatively cheap operation.
994 return true;
995}
996
997bool WebAssemblyTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
998 // Assume clz is a relatively cheap operation.
999 return true;
1000}
1001
1002bool WebAssemblyTargetLowering::isLegalAddressingMode(const DataLayout &DL,
1003 const AddrMode &AM,
1004 Type *Ty, unsigned AS,
1005 Instruction *I) const {
1006 // WebAssembly offsets are added as unsigned without wrapping. The
1007 // isLegalAddressingMode gives us no way to determine if wrapping could be
1008 // happening, so we approximate this by accepting only non-negative offsets.
1009 if (AM.BaseOffs < 0)
1010 return false;
1011
1012 // WebAssembly has no scale register operands.
1013 if (AM.Scale != 0)
1014 return false;
1015
1016 // Everything else is legal.
1017 return true;
1018}
1019
1020bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses(
1021 EVT /*VT*/, unsigned /*AddrSpace*/, Align /*Align*/,
1022 MachineMemOperand::Flags /*Flags*/, unsigned *Fast) const {
1023 // WebAssembly supports unaligned accesses, though it should be declared
1024 // with the p2align attribute on loads and stores which do so, and there
1025 // may be a performance impact. We tell LLVM they're "fast" because
1026 // for the kinds of things that LLVM uses this for (merging adjacent stores
1027 // of constants, etc.), WebAssembly implementations will either want the
1028 // unaligned access or they'll split anyway.
1029 if (Fast)
1030 *Fast = 1;
1031 return true;
1032}
1033
1034bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
1035 AttributeList Attr) const {
1036 // The current thinking is that wasm engines will perform this optimization,
1037 // so we can save on code size.
1038 return true;
1039}
1040
1041bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
1042 EVT ExtT = ExtVal.getValueType();
1043 EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0);
1044 return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
1045 (ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
1046 (ExtT == MVT::v2i64 && MemT == MVT::v2i32);
1047}
1048
1049bool WebAssemblyTargetLowering::isOffsetFoldingLegal(
1050 const GlobalAddressSDNode *GA) const {
1051 // Wasm doesn't support function addresses with offsets
1052 const GlobalValue *GV = GA->getGlobal();
1054}
1055
1056EVT WebAssemblyTargetLowering::getSetCCResultType(const DataLayout &DL,
1057 LLVMContext &C,
1058 EVT VT) const {
1059 if (VT.isVector())
1061
1062 // So far, all branch instructions in Wasm take an I32 condition.
1063 // The default TargetLowering::getSetCCResultType returns the pointer size,
1064 // which would be useful to reduce instruction counts when testing
1065 // against 64-bit pointers/values if at some point Wasm supports that.
1066 return EVT::getIntegerVT(C, 32);
1067}
1068
1069bool WebAssemblyTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
1070 const CallInst &I,
1071 MachineFunction &MF,
1072 unsigned Intrinsic) const {
1073 switch (Intrinsic) {
1074 case Intrinsic::wasm_memory_atomic_notify:
1076 Info.memVT = MVT::i32;
1077 Info.ptrVal = I.getArgOperand(0);
1078 Info.offset = 0;
1079 Info.align = Align(4);
1080 // atomic.notify instruction does not really load the memory specified with
1081 // this argument, but MachineMemOperand should either be load or store, so
1082 // we set this to a load.
1083 // FIXME Volatile isn't really correct, but currently all LLVM atomic
1084 // instructions are treated as volatiles in the backend, so we should be
1085 // consistent. The same applies for wasm_atomic_wait intrinsics too.
1087 return true;
1088 case Intrinsic::wasm_memory_atomic_wait32:
1090 Info.memVT = MVT::i32;
1091 Info.ptrVal = I.getArgOperand(0);
1092 Info.offset = 0;
1093 Info.align = Align(4);
1095 return true;
1096 case Intrinsic::wasm_memory_atomic_wait64:
1098 Info.memVT = MVT::i64;
1099 Info.ptrVal = I.getArgOperand(0);
1100 Info.offset = 0;
1101 Info.align = Align(8);
1103 return true;
1104 case Intrinsic::wasm_loadf16_f32:
1106 Info.memVT = MVT::f16;
1107 Info.ptrVal = I.getArgOperand(0);
1108 Info.offset = 0;
1109 Info.align = Align(2);
1111 return true;
1112 case Intrinsic::wasm_storef16_f32:
1114 Info.memVT = MVT::f16;
1115 Info.ptrVal = I.getArgOperand(1);
1116 Info.offset = 0;
1117 Info.align = Align(2);
1119 return true;
1120 default:
1121 return false;
1122 }
1123}
1124
1125void WebAssemblyTargetLowering::computeKnownBitsForTargetNode(
1126 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
1127 const SelectionDAG &DAG, unsigned Depth) const {
1128 switch (Op.getOpcode()) {
1129 default:
1130 break;
1132 unsigned IntNo = Op.getConstantOperandVal(0);
1133 switch (IntNo) {
1134 default:
1135 break;
1136 case Intrinsic::wasm_bitmask: {
1137 unsigned BitWidth = Known.getBitWidth();
1138 EVT VT = Op.getOperand(1).getSimpleValueType();
1139 unsigned PossibleBits = VT.getVectorNumElements();
1140 APInt ZeroMask = APInt::getHighBitsSet(BitWidth, BitWidth - PossibleBits);
1141 Known.Zero |= ZeroMask;
1142 break;
1143 }
1144 }
1145 break;
1146 }
1147
1148 // For 128-bit addition if the upper bits are all zero then it's known that
1149 // the upper bits of the result will have all bits guaranteed zero except the
1150 // first.
1151 case WebAssemblyISD::I64_ADD128:
1152 if (Op.getResNo() == 1) {
1153 SDValue LHS_HI = Op.getOperand(1);
1154 SDValue RHS_HI = Op.getOperand(3);
1155 if (isNullConstant(LHS_HI) && isNullConstant(RHS_HI))
1156 Known.Zero.setBitsFrom(1);
1157 }
1158 break;
1159 }
1160}
1161
1163WebAssemblyTargetLowering::getPreferredVectorAction(MVT VT) const {
1164 if (VT.isFixedLengthVector()) {
1165 MVT EltVT = VT.getVectorElementType();
1166 // We have legal vector types with these lane types, so widening the
1167 // vector would let us use some of the lanes directly without having to
1168 // extend or truncate values.
1169 if (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
1170 EltVT == MVT::i64 || EltVT == MVT::f32 || EltVT == MVT::f64)
1171 return TypeWidenVector;
1172 }
1173
1175}
1176
1177bool WebAssemblyTargetLowering::isFMAFasterThanFMulAndFAdd(
1178 const MachineFunction &MF, EVT VT) const {
1179 if (!Subtarget->hasFP16() || !VT.isVector())
1180 return false;
1181
1182 EVT ScalarVT = VT.getScalarType();
1183 if (!ScalarVT.isSimple())
1184 return false;
1185
1186 return ScalarVT.getSimpleVT().SimpleTy == MVT::f16;
1187}
1188
1189bool WebAssemblyTargetLowering::shouldSimplifyDemandedVectorElts(
1190 SDValue Op, const TargetLoweringOpt &TLO) const {
1191 // ISel process runs DAGCombiner after legalization; this step is called
1192 // SelectionDAG optimization phase. This post-legalization combining process
1193 // runs DAGCombiner on each node, and if there was a change to be made,
1194 // re-runs legalization again on it and its user nodes to make sure
1195 // everythiing is in a legalized state.
1196 //
1197 // The legalization calls lowering routines, and we do our custom lowering for
1198 // build_vectors (LowerBUILD_VECTOR), which converts undef vector elements
1199 // into zeros. But there is a set of routines in DAGCombiner that turns unused
1200 // (= not demanded) nodes into undef, among which SimplifyDemandedVectorElts
1201 // turns unused vector elements into undefs. But this routine does not work
1202 // with our custom LowerBUILD_VECTOR, which turns undefs into zeros. This
1203 // combination can result in a infinite loop, in which undefs are converted to
1204 // zeros in legalization and back to undefs in combining.
1205 //
1206 // So after DAG is legalized, we prevent SimplifyDemandedVectorElts from
1207 // running for build_vectors.
1208 if (Op.getOpcode() == ISD::BUILD_VECTOR && TLO.LegalOps && TLO.LegalTys)
1209 return false;
1210 return true;
1211}
1212
1213//===----------------------------------------------------------------------===//
1214// WebAssembly Lowering private implementation.
1215//===----------------------------------------------------------------------===//
1216
1217//===----------------------------------------------------------------------===//
1218// Lowering Code
1219//===----------------------------------------------------------------------===//
1220
1221static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
1223 DAG.getContext()->diagnose(
1224 DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc()));
1225}
1226
1227// Test whether the given calling convention is supported.
1229 // We currently support the language-independent target-independent
1230 // conventions. We don't yet have a way to annotate calls with properties like
1231 // "cold", and we don't have any call-clobbered registers, so these are mostly
1232 // all handled the same.
1233 return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
1234 CallConv == CallingConv::Cold ||
1235 CallConv == CallingConv::PreserveMost ||
1236 CallConv == CallingConv::PreserveAll ||
1237 CallConv == CallingConv::CXX_FAST_TLS ||
1239 CallConv == CallingConv::Swift;
1240}
1241
1242SDValue
1243WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
1244 SmallVectorImpl<SDValue> &InVals) const {
1245 SelectionDAG &DAG = CLI.DAG;
1246 SDLoc DL = CLI.DL;
1247 SDValue Chain = CLI.Chain;
1248 SDValue Callee = CLI.Callee;
1249 MachineFunction &MF = DAG.getMachineFunction();
1250 auto Layout = MF.getDataLayout();
1251
1252 CallingConv::ID CallConv = CLI.CallConv;
1253 if (!callingConvSupported(CallConv))
1254 fail(DL, DAG,
1255 "WebAssembly doesn't support language-specific or target-specific "
1256 "calling conventions yet");
1257 if (CLI.IsPatchPoint)
1258 fail(DL, DAG, "WebAssembly doesn't support patch point yet");
1259
1260 if (CLI.IsTailCall) {
1261 auto NoTail = [&](const char *Msg) {
1262 if (CLI.CB && CLI.CB->isMustTailCall())
1263 fail(DL, DAG, Msg);
1264 CLI.IsTailCall = false;
1265 };
1266
1267 if (!Subtarget->hasTailCall())
1268 NoTail("WebAssembly 'tail-call' feature not enabled");
1269
1270 // Varargs calls cannot be tail calls because the buffer is on the stack
1271 if (CLI.IsVarArg)
1272 NoTail("WebAssembly does not support varargs tail calls");
1273
1274 // Do not tail call unless caller and callee return types match
1275 const Function &F = MF.getFunction();
1276 const TargetMachine &TM = getTargetMachine();
1277 Type *RetTy = F.getReturnType();
1278 SmallVector<MVT, 4> CallerRetTys;
1279 SmallVector<MVT, 4> CalleeRetTys;
1280 computeLegalValueVTs(F, TM, RetTy, CallerRetTys);
1281 computeLegalValueVTs(F, TM, CLI.RetTy, CalleeRetTys);
1282 bool TypesMatch = CallerRetTys.size() == CalleeRetTys.size() &&
1283 std::equal(CallerRetTys.begin(), CallerRetTys.end(),
1284 CalleeRetTys.begin());
1285 if (!TypesMatch)
1286 NoTail("WebAssembly tail call requires caller and callee return types to "
1287 "match");
1288
1289 // If pointers to local stack values are passed, we cannot tail call
1290 if (CLI.CB) {
1291 for (auto &Arg : CLI.CB->args()) {
1292 Value *Val = Arg.get();
1293 // Trace the value back through pointer operations
1294 while (true) {
1295 Value *Src = Val->stripPointerCastsAndAliases();
1296 if (auto *GEP = dyn_cast<GetElementPtrInst>(Src))
1297 Src = GEP->getPointerOperand();
1298 if (Val == Src)
1299 break;
1300 Val = Src;
1301 }
1302 if (isa<AllocaInst>(Val)) {
1303 NoTail(
1304 "WebAssembly does not support tail calling with stack arguments");
1305 break;
1306 }
1307 }
1308 }
1309 }
1310
1311 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
1312 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
1313 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
1314
1315 // The generic code may have added an sret argument. If we're lowering an
1316 // invoke function, the ABI requires that the function pointer be the first
1317 // argument, so we may have to swap the arguments.
1318 if (CallConv == CallingConv::WASM_EmscriptenInvoke && Outs.size() >= 2 &&
1319 Outs[0].Flags.isSRet()) {
1320 std::swap(Outs[0], Outs[1]);
1321 std::swap(OutVals[0], OutVals[1]);
1322 }
1323
1324 bool HasSwiftSelfArg = false;
1325 bool HasSwiftErrorArg = false;
1326 unsigned NumFixedArgs = 0;
1327 for (unsigned I = 0; I < Outs.size(); ++I) {
1328 const ISD::OutputArg &Out = Outs[I];
1329 SDValue &OutVal = OutVals[I];
1330 HasSwiftSelfArg |= Out.Flags.isSwiftSelf();
1331 HasSwiftErrorArg |= Out.Flags.isSwiftError();
1332 if (Out.Flags.isNest())
1333 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1334 if (Out.Flags.isInAlloca())
1335 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1336 if (Out.Flags.isInConsecutiveRegs())
1337 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1339 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1340 if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
1341 auto &MFI = MF.getFrameInfo();
1342 int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
1344 /*isSS=*/false);
1345 SDValue SizeNode =
1346 DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
1347 SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1348 Chain = DAG.getMemcpy(Chain, DL, FINode, OutVal, SizeNode,
1350 /*isVolatile*/ false, /*AlwaysInline=*/false,
1351 /*CI=*/nullptr, std::nullopt, MachinePointerInfo(),
1352 MachinePointerInfo());
1353 OutVal = FINode;
1354 }
1355 // Count the number of fixed args *after* legalization.
1356 NumFixedArgs += !Out.Flags.isVarArg();
1357 }
1358
1359 bool IsVarArg = CLI.IsVarArg;
1360 auto PtrVT = getPointerTy(Layout);
1361
1362 // For swiftcc, emit additional swiftself and swifterror arguments
1363 // if there aren't. These additional arguments are also added for callee
1364 // signature They are necessary to match callee and caller signature for
1365 // indirect call.
1366 if (CallConv == CallingConv::Swift) {
1367 Type *PtrTy = PointerType::getUnqual(*DAG.getContext());
1368 if (!HasSwiftSelfArg) {
1369 NumFixedArgs++;
1370 ISD::ArgFlagsTy Flags;
1371 Flags.setSwiftSelf();
1372 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1373 CLI.Outs.push_back(Arg);
1374 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1375 CLI.OutVals.push_back(ArgVal);
1376 }
1377 if (!HasSwiftErrorArg) {
1378 NumFixedArgs++;
1379 ISD::ArgFlagsTy Flags;
1380 Flags.setSwiftError();
1381 ISD::OutputArg Arg(Flags, PtrVT, EVT(PtrVT), PtrTy, 0, 0);
1382 CLI.Outs.push_back(Arg);
1383 SDValue ArgVal = DAG.getUNDEF(PtrVT);
1384 CLI.OutVals.push_back(ArgVal);
1385 }
1386 }
1387
1388 // Analyze operands of the call, assigning locations to each operand.
1390 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
1391
1392 if (IsVarArg) {
1393 // Outgoing non-fixed arguments are placed in a buffer. First
1394 // compute their offsets and the total amount of buffer space needed.
1395 for (unsigned I = NumFixedArgs; I < Outs.size(); ++I) {
1396 const ISD::OutputArg &Out = Outs[I];
1397 SDValue &Arg = OutVals[I];
1398 EVT VT = Arg.getValueType();
1399 assert(VT != MVT::iPTR && "Legalized args should be concrete");
1400 Type *Ty = VT.getTypeForEVT(*DAG.getContext());
1401 Align Alignment =
1402 std::max(Out.Flags.getNonZeroOrigAlign(), Layout.getABITypeAlign(Ty));
1403 unsigned Offset =
1404 CCInfo.AllocateStack(Layout.getTypeAllocSize(Ty), Alignment);
1405 CCInfo.addLoc(CCValAssign::getMem(ArgLocs.size(), VT.getSimpleVT(),
1406 Offset, VT.getSimpleVT(),
1408 }
1409 }
1410
1411 unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
1412
1413 SDValue FINode;
1414 if (IsVarArg && NumBytes) {
1415 // For non-fixed arguments, next emit stores to store the argument values
1416 // to the stack buffer at the offsets computed above.
1417 MaybeAlign StackAlign = Layout.getStackAlignment();
1418 assert(StackAlign && "data layout string is missing stack alignment");
1419 int FI = MF.getFrameInfo().CreateStackObject(NumBytes, *StackAlign,
1420 /*isSS=*/false);
1421 unsigned ValNo = 0;
1423 for (SDValue Arg : drop_begin(OutVals, NumFixedArgs)) {
1424 assert(ArgLocs[ValNo].getValNo() == ValNo &&
1425 "ArgLocs should remain in order and only hold varargs args");
1426 unsigned Offset = ArgLocs[ValNo++].getLocMemOffset();
1427 FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
1428 SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, FINode,
1429 DAG.getConstant(Offset, DL, PtrVT));
1430 Chains.push_back(
1431 DAG.getStore(Chain, DL, Arg, Add,
1433 }
1434 if (!Chains.empty())
1435 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
1436 } else if (IsVarArg) {
1437 FINode = DAG.getIntPtrConstant(0, DL);
1438 }
1439
1440 if (Callee->getOpcode() == ISD::GlobalAddress) {
1441 // If the callee is a GlobalAddress node (quite common, every direct call
1442 // is) turn it into a TargetGlobalAddress node so that LowerGlobalAddress
1443 // doesn't at MO_GOT which is not needed for direct calls.
1444 GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Callee);
1447 GA->getOffset());
1448 Callee = DAG.getNode(WebAssemblyISD::Wrapper, DL,
1449 getPointerTy(DAG.getDataLayout()), Callee);
1450 }
1451
1452 // Compute the operands for the CALLn node.
1454 Ops.push_back(Chain);
1455 Ops.push_back(Callee);
1456
1457 // Add all fixed arguments. Note that for non-varargs calls, NumFixedArgs
1458 // isn't reliable.
1459 Ops.append(OutVals.begin(),
1460 IsVarArg ? OutVals.begin() + NumFixedArgs : OutVals.end());
1461 // Add a pointer to the vararg buffer.
1462 if (IsVarArg)
1463 Ops.push_back(FINode);
1464
1465 SmallVector<EVT, 8> InTys;
1466 for (const auto &In : Ins) {
1467 assert(!In.Flags.isByVal() && "byval is not valid for return values");
1468 assert(!In.Flags.isNest() && "nest is not valid for return values");
1469 if (In.Flags.isInAlloca())
1470 fail(DL, DAG, "WebAssembly hasn't implemented inalloca return values");
1471 if (In.Flags.isInConsecutiveRegs())
1472 fail(DL, DAG, "WebAssembly hasn't implemented cons regs return values");
1473 if (In.Flags.isInConsecutiveRegsLast())
1474 fail(DL, DAG,
1475 "WebAssembly hasn't implemented cons regs last return values");
1476 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1477 // registers.
1478 InTys.push_back(In.VT);
1479 }
1480
1481 // Lastly, if this is a call to a funcref we need to add an instruction
1482 // table.set to the chain and transform the call.
1484 CLI.CB->getCalledOperand()->getType())) {
1485 // In the absence of function references proposal where a funcref call is
1486 // lowered to call_ref, using reference types we generate a table.set to set
1487 // the funcref to a special table used solely for this purpose, followed by
1488 // a call_indirect. Here we just generate the table set, and return the
1489 // SDValue of the table.set so that LowerCall can finalize the lowering by
1490 // generating the call_indirect.
1491 SDValue Chain = Ops[0];
1492
1494 MF.getContext(), Subtarget);
1495 SDValue Sym = DAG.getMCSymbol(Table, PtrVT);
1496 SDValue TableSlot = DAG.getConstant(0, DL, MVT::i32);
1497 SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
1498 SDValue TableSet = DAG.getMemIntrinsicNode(
1499 WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
1500 MVT::funcref,
1501 // Machine Mem Operand args
1502 MachinePointerInfo(
1504 CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()),
1506
1507 Ops[0] = TableSet; // The new chain is the TableSet itself
1508 }
1509
1510 if (CLI.IsTailCall) {
1511 // ret_calls do not return values to the current frame
1512 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1513 return DAG.getNode(WebAssemblyISD::RET_CALL, DL, NodeTys, Ops);
1514 }
1515
1516 InTys.push_back(MVT::Other);
1517 SDVTList InTyList = DAG.getVTList(InTys);
1518 SDValue Res = DAG.getNode(WebAssemblyISD::CALL, DL, InTyList, Ops);
1519
1520 for (size_t I = 0; I < Ins.size(); ++I)
1521 InVals.push_back(Res.getValue(I));
1522
1523 // Return the chain
1524 return Res.getValue(Ins.size());
1525}
1526
1527bool WebAssemblyTargetLowering::CanLowerReturn(
1528 CallingConv::ID /*CallConv*/, MachineFunction & /*MF*/, bool /*IsVarArg*/,
1529 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext & /*Context*/,
1530 const Type *RetTy) const {
1531 // WebAssembly can only handle returning tuples with multivalue enabled
1532 return WebAssembly::canLowerReturn(Outs.size(), Subtarget);
1533}
1534
1535SDValue WebAssemblyTargetLowering::LowerReturn(
1536 SDValue Chain, CallingConv::ID CallConv, bool /*IsVarArg*/,
1538 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
1539 SelectionDAG &DAG) const {
1540 assert(WebAssembly::canLowerReturn(Outs.size(), Subtarget) &&
1541 "MVP WebAssembly can only return up to one value");
1542 if (!callingConvSupported(CallConv))
1543 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1544
1545 SmallVector<SDValue, 4> RetOps(1, Chain);
1546 RetOps.append(OutVals.begin(), OutVals.end());
1547 Chain = DAG.getNode(WebAssemblyISD::RETURN, DL, MVT::Other, RetOps);
1548
1549 // Record the number and types of the return values.
1550 for (const ISD::OutputArg &Out : Outs) {
1551 assert(!Out.Flags.isByVal() && "byval is not valid for return values");
1552 assert(!Out.Flags.isNest() && "nest is not valid for return values");
1553 assert(!Out.Flags.isVarArg() && "non-fixed return value is not valid");
1554 if (Out.Flags.isInAlloca())
1555 fail(DL, DAG, "WebAssembly hasn't implemented inalloca results");
1556 if (Out.Flags.isInConsecutiveRegs())
1557 fail(DL, DAG, "WebAssembly hasn't implemented cons regs results");
1559 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last results");
1560 }
1561
1562 return Chain;
1563}
1564
1565SDValue WebAssemblyTargetLowering::LowerFormalArguments(
1566 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
1567 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
1568 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
1569 if (!callingConvSupported(CallConv))
1570 fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
1571
1572 MachineFunction &MF = DAG.getMachineFunction();
1573 auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
1574
1575 // Set up the incoming ARGUMENTS value, which serves to represent the liveness
1576 // of the incoming values before they're represented by virtual registers.
1577 MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
1578
1579 bool HasSwiftErrorArg = false;
1580 bool HasSwiftSelfArg = false;
1581 for (const ISD::InputArg &In : Ins) {
1582 HasSwiftSelfArg |= In.Flags.isSwiftSelf();
1583 HasSwiftErrorArg |= In.Flags.isSwiftError();
1584 if (In.Flags.isInAlloca())
1585 fail(DL, DAG, "WebAssembly hasn't implemented inalloca arguments");
1586 if (In.Flags.isNest())
1587 fail(DL, DAG, "WebAssembly hasn't implemented nest arguments");
1588 if (In.Flags.isInConsecutiveRegs())
1589 fail(DL, DAG, "WebAssembly hasn't implemented cons regs arguments");
1590 if (In.Flags.isInConsecutiveRegsLast())
1591 fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
1592 // Ignore In.getNonZeroOrigAlign() because all our arguments are passed in
1593 // registers.
1594 InVals.push_back(In.Used ? DAG.getNode(WebAssemblyISD::ARGUMENT, DL, In.VT,
1595 DAG.getTargetConstant(InVals.size(),
1596 DL, MVT::i32))
1597 : DAG.getUNDEF(In.VT));
1598
1599 // Record the number and types of arguments.
1600 MFI->addParam(In.VT);
1601 }
1602
1603 // For swiftcc, emit additional swiftself and swifterror arguments
1604 // if there aren't. These additional arguments are also added for callee
1605 // signature They are necessary to match callee and caller signature for
1606 // indirect call.
1607 auto PtrVT = getPointerTy(MF.getDataLayout());
1608 if (CallConv == CallingConv::Swift) {
1609 if (!HasSwiftSelfArg) {
1610 MFI->addParam(PtrVT);
1611 }
1612 if (!HasSwiftErrorArg) {
1613 MFI->addParam(PtrVT);
1614 }
1615 }
1616 // Varargs are copied into a buffer allocated by the caller, and a pointer to
1617 // the buffer is passed as an argument.
1618 if (IsVarArg) {
1619 MVT PtrVT = getPointerTy(MF.getDataLayout());
1620 Register VarargVreg =
1622 MFI->setVarargBufferVreg(VarargVreg);
1623 Chain = DAG.getCopyToReg(
1624 Chain, DL, VarargVreg,
1625 DAG.getNode(WebAssemblyISD::ARGUMENT, DL, PtrVT,
1626 DAG.getTargetConstant(Ins.size(), DL, MVT::i32)));
1627 MFI->addParam(PtrVT);
1628 }
1629
1630 // Record the number and types of arguments and results.
1631 SmallVector<MVT, 4> Params;
1634 MF.getFunction(), DAG.getTarget(), Params, Results);
1635 for (MVT VT : Results)
1636 MFI->addResult(VT);
1637 // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
1638 // the param logic here with ComputeSignatureVTs
1639 assert(MFI->getParams().size() == Params.size() &&
1640 std::equal(MFI->getParams().begin(), MFI->getParams().end(),
1641 Params.begin()));
1642
1643 return Chain;
1644}
1645
1646void WebAssemblyTargetLowering::ReplaceNodeResults(
1648 switch (N->getOpcode()) {
1650 // Do not add any results, signifying that N should not be custom lowered
1651 // after all. This happens because simd128 turns on custom lowering for
1652 // SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1653 // illegal type.
1654 break;
1657 // Do not add any results, signifying that N should not be custom lowered.
1658 // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
1659 break;
1660 case ISD::ADD:
1661 case ISD::SUB:
1662 Results.push_back(Replace128Op(N, DAG));
1663 break;
1664 default:
1666 "ReplaceNodeResults not implemented for this op for WebAssembly!");
1667 }
1668}
1669
1670//===----------------------------------------------------------------------===//
1671// Custom lowering hooks.
1672//===----------------------------------------------------------------------===//
1673
1674SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1675 SelectionDAG &DAG) const {
1676 SDLoc DL(Op);
1677 switch (Op.getOpcode()) {
1678 default:
1679 llvm_unreachable("unimplemented operation lowering");
1680 return SDValue();
1681 case ISD::FrameIndex:
1682 return LowerFrameIndex(Op, DAG);
1683 case ISD::GlobalAddress:
1684 return LowerGlobalAddress(Op, DAG);
1686 return LowerGlobalTLSAddress(Op, DAG);
1688 return LowerExternalSymbol(Op, DAG);
1689 case ISD::JumpTable:
1690 return LowerJumpTable(Op, DAG);
1691 case ISD::BR_JT:
1692 return LowerBR_JT(Op, DAG);
1693 case ISD::VASTART:
1694 return LowerVASTART(Op, DAG);
1695 case ISD::BlockAddress:
1696 case ISD::BRIND:
1697 fail(DL, DAG, "WebAssembly hasn't implemented computed gotos");
1698 return SDValue();
1699 case ISD::RETURNADDR:
1700 return LowerRETURNADDR(Op, DAG);
1701 case ISD::FRAMEADDR:
1702 return LowerFRAMEADDR(Op, DAG);
1703 case ISD::CopyToReg:
1704 return LowerCopyToReg(Op, DAG);
1707 return LowerAccessVectorElement(Op, DAG);
1711 return LowerIntrinsic(Op, DAG);
1713 return LowerSIGN_EXTEND_INREG(Op, DAG);
1716 return LowerEXTEND_VECTOR_INREG(Op, DAG);
1717 case ISD::BUILD_VECTOR:
1718 return LowerBUILD_VECTOR(Op, DAG);
1720 return LowerVECTOR_SHUFFLE(Op, DAG);
1721 case ISD::SETCC:
1722 return LowerSETCC(Op, DAG);
1723 case ISD::SHL:
1724 case ISD::SRA:
1725 case ISD::SRL:
1726 return LowerShift(Op, DAG);
1729 return LowerFP_TO_INT_SAT(Op, DAG);
1730 case ISD::LOAD:
1731 return LowerLoad(Op, DAG);
1732 case ISD::STORE:
1733 return LowerStore(Op, DAG);
1734 case ISD::CTPOP:
1735 case ISD::CTLZ:
1736 case ISD::CTTZ:
1737 return DAG.UnrollVectorOp(Op.getNode());
1738 case ISD::CLEAR_CACHE:
1739 report_fatal_error("llvm.clear_cache is not supported on wasm");
1740 case ISD::SMUL_LOHI:
1741 case ISD::UMUL_LOHI:
1742 return LowerMUL_LOHI(Op, DAG);
1743 case ISD::UADDO:
1744 return LowerUADDO(Op, DAG);
1745 }
1746}
1747
1751
1752 return false;
1753}
1754
1755static std::optional<unsigned> IsWebAssemblyLocal(SDValue Op,
1756 SelectionDAG &DAG) {
1758 if (!FI)
1759 return std::nullopt;
1760
1761 auto &MF = DAG.getMachineFunction();
1763}
1764
1765SDValue WebAssemblyTargetLowering::LowerStore(SDValue Op,
1766 SelectionDAG &DAG) const {
1767 SDLoc DL(Op);
1768 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
1769 const SDValue &Value = SN->getValue();
1770 const SDValue &Base = SN->getBasePtr();
1771 const SDValue &Offset = SN->getOffset();
1772
1774 if (!Offset->isUndef())
1775 report_fatal_error("unexpected offset when storing to webassembly global",
1776 false);
1777
1778 SDVTList Tys = DAG.getVTList(MVT::Other);
1779 SDValue Ops[] = {SN->getChain(), Value, Base};
1780 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_SET, DL, Tys, Ops,
1781 SN->getMemoryVT(), SN->getMemOperand());
1782 }
1783
1784 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1785 if (!Offset->isUndef())
1786 report_fatal_error("unexpected offset when storing to webassembly local",
1787 false);
1788
1789 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1790 SDVTList Tys = DAG.getVTList(MVT::Other); // The chain.
1791 SDValue Ops[] = {SN->getChain(), Idx, Value};
1792 return DAG.getNode(WebAssemblyISD::LOCAL_SET, DL, Tys, Ops);
1793 }
1794
1797 "Encountered an unlowerable store to the wasm_var address space",
1798 false);
1799
1800 return Op;
1801}
1802
1803SDValue WebAssemblyTargetLowering::LowerLoad(SDValue Op,
1804 SelectionDAG &DAG) const {
1805 SDLoc DL(Op);
1806 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
1807 const SDValue &Base = LN->getBasePtr();
1808 const SDValue &Offset = LN->getOffset();
1809
1811 if (!Offset->isUndef())
1813 "unexpected offset when loading from webassembly global", false);
1814
1815 SDVTList Tys = DAG.getVTList(LN->getValueType(0), MVT::Other);
1816 SDValue Ops[] = {LN->getChain(), Base};
1817 return DAG.getMemIntrinsicNode(WebAssemblyISD::GLOBAL_GET, DL, Tys, Ops,
1818 LN->getMemoryVT(), LN->getMemOperand());
1819 }
1820
1821 if (std::optional<unsigned> Local = IsWebAssemblyLocal(Base, DAG)) {
1822 if (!Offset->isUndef())
1824 "unexpected offset when loading from webassembly local", false);
1825
1826 SDValue Idx = DAG.getTargetConstant(*Local, Base, MVT::i32);
1827 EVT LocalVT = LN->getValueType(0);
1828 SDValue LocalGet = DAG.getNode(WebAssemblyISD::LOCAL_GET, DL, LocalVT,
1829 {LN->getChain(), Idx});
1830 SDValue Result = DAG.getMergeValues({LocalGet, LN->getChain()}, DL);
1831 assert(Result->getNumValues() == 2 && "Loads must carry a chain!");
1832 return Result;
1833 }
1834
1837 "Encountered an unlowerable load from the wasm_var address space",
1838 false);
1839
1840 return Op;
1841}
1842
1843SDValue WebAssemblyTargetLowering::LowerMUL_LOHI(SDValue Op,
1844 SelectionDAG &DAG) const {
1845 assert(Subtarget->hasWideArithmetic());
1846 assert(Op.getValueType() == MVT::i64);
1847 SDLoc DL(Op);
1848 unsigned Opcode;
1849 switch (Op.getOpcode()) {
1850 case ISD::UMUL_LOHI:
1851 Opcode = WebAssemblyISD::I64_MUL_WIDE_U;
1852 break;
1853 case ISD::SMUL_LOHI:
1854 Opcode = WebAssemblyISD::I64_MUL_WIDE_S;
1855 break;
1856 default:
1857 llvm_unreachable("unexpected opcode");
1858 }
1859 SDValue LHS = Op.getOperand(0);
1860 SDValue RHS = Op.getOperand(1);
1861 SDValue Lo =
1862 DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64), LHS, RHS);
1863 SDValue Hi(Lo.getNode(), 1);
1864 SDValue Ops[] = {Lo, Hi};
1865 return DAG.getMergeValues(Ops, DL);
1866}
1867
1868// Lowers `UADDO` intrinsics to an `i64.add128` instruction when it's enabled.
1869//
1870// This enables generating a single wasm instruction for this operation where
1871// the upper half of both operands are constant zeros. The upper half of the
1872// result is then whether the overflow happened.
1873SDValue WebAssemblyTargetLowering::LowerUADDO(SDValue Op,
1874 SelectionDAG &DAG) const {
1875 assert(Subtarget->hasWideArithmetic());
1876 assert(Op.getValueType() == MVT::i64);
1877 assert(Op.getOpcode() == ISD::UADDO);
1878 SDLoc DL(Op);
1879 SDValue LHS = Op.getOperand(0);
1880 SDValue RHS = Op.getOperand(1);
1881 SDValue Zero = DAG.getConstant(0, DL, MVT::i64);
1882 SDValue Result =
1883 DAG.getNode(WebAssemblyISD::I64_ADD128, DL,
1884 DAG.getVTList(MVT::i64, MVT::i64), LHS, Zero, RHS, Zero);
1885 SDValue CarryI64(Result.getNode(), 1);
1886 SDValue CarryI32 = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, CarryI64);
1887 SDValue Ops[] = {Result, CarryI32};
1888 return DAG.getMergeValues(Ops, DL);
1889}
1890
1891SDValue WebAssemblyTargetLowering::Replace128Op(SDNode *N,
1892 SelectionDAG &DAG) const {
1893 assert(Subtarget->hasWideArithmetic());
1894 assert(N->getValueType(0) == MVT::i128);
1895 SDLoc DL(N);
1896 unsigned Opcode;
1897 switch (N->getOpcode()) {
1898 case ISD::ADD:
1899 Opcode = WebAssemblyISD::I64_ADD128;
1900 break;
1901 case ISD::SUB:
1902 Opcode = WebAssemblyISD::I64_SUB128;
1903 break;
1904 default:
1905 llvm_unreachable("unexpected opcode");
1906 }
1907 SDValue LHS = N->getOperand(0);
1908 SDValue RHS = N->getOperand(1);
1909
1910 SDValue C0 = DAG.getConstant(0, DL, MVT::i64);
1911 SDValue C1 = DAG.getConstant(1, DL, MVT::i64);
1912 SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C0);
1913 SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, LHS, C1);
1914 SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C0);
1915 SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i64, RHS, C1);
1916 SDValue Result_LO = DAG.getNode(Opcode, DL, DAG.getVTList(MVT::i64, MVT::i64),
1917 LHS_0, LHS_1, RHS_0, RHS_1);
1918 SDValue Result_HI(Result_LO.getNode(), 1);
1919 return DAG.getNode(ISD::BUILD_PAIR, DL, N->getVTList(), Result_LO, Result_HI);
1920}
1921
1922SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
1923 SelectionDAG &DAG) const {
1924 SDValue Src = Op.getOperand(2);
1925 if (isa<FrameIndexSDNode>(Src.getNode())) {
1926 // CopyToReg nodes don't support FrameIndex operands. Other targets select
1927 // the FI to some LEA-like instruction, but since we don't have that, we
1928 // need to insert some kind of instruction that can take an FI operand and
1929 // produces a value usable by CopyToReg (i.e. in a vreg). So insert a dummy
1930 // local.copy between Op and its FI operand.
1931 SDValue Chain = Op.getOperand(0);
1932 SDLoc DL(Op);
1933 Register Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
1934 EVT VT = Src.getValueType();
1935 SDValue Copy(DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
1936 : WebAssembly::COPY_I64,
1937 DL, VT, Src),
1938 0);
1939 return Op.getNode()->getNumValues() == 1
1940 ? DAG.getCopyToReg(Chain, DL, Reg, Copy)
1941 : DAG.getCopyToReg(Chain, DL, Reg, Copy,
1942 Op.getNumOperands() == 4 ? Op.getOperand(3)
1943 : SDValue());
1944 }
1945 return SDValue();
1946}
1947
1948SDValue WebAssemblyTargetLowering::LowerFrameIndex(SDValue Op,
1949 SelectionDAG &DAG) const {
1950 int FI = cast<FrameIndexSDNode>(Op)->getIndex();
1951 return DAG.getTargetFrameIndex(FI, Op.getValueType());
1952}
1953
1954SDValue WebAssemblyTargetLowering::LowerRETURNADDR(SDValue Op,
1955 SelectionDAG &DAG) const {
1956 SDLoc DL(Op);
1957
1958 if (!Subtarget->getTargetTriple().isOSEmscripten()) {
1959 fail(DL, DAG,
1960 "Non-Emscripten WebAssembly hasn't implemented "
1961 "__builtin_return_address");
1962 return SDValue();
1963 }
1964
1965 unsigned Depth = Op.getConstantOperandVal(0);
1966 MakeLibCallOptions CallOptions;
1967 return makeLibCall(DAG, RTLIB::RETURN_ADDRESS, Op.getValueType(),
1968 {DAG.getConstant(Depth, DL, MVT::i32)}, CallOptions, DL)
1969 .first;
1970}
1971
1972SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
1973 SelectionDAG &DAG) const {
1974 // Non-zero depths are not supported by WebAssembly currently. Use the
1975 // legalizer's default expansion, which is to return 0 (what this function is
1976 // documented to do).
1977 if (Op.getConstantOperandVal(0) > 0)
1978 return SDValue();
1979
1981 EVT VT = Op.getValueType();
1982 Register FP =
1983 Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
1984 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
1985}
1986
1987SDValue
1988WebAssemblyTargetLowering::LowerGlobalTLSAddress(SDValue Op,
1989 SelectionDAG &DAG) const {
1990 SDLoc DL(Op);
1991 const auto *GA = cast<GlobalAddressSDNode>(Op);
1992
1993 MachineFunction &MF = DAG.getMachineFunction();
1994 if (!MF.getSubtarget<WebAssemblySubtarget>().hasBulkMemory())
1995 report_fatal_error("cannot use thread-local storage without bulk memory",
1996 false);
1997
1998 const GlobalValue *GV = GA->getGlobal();
1999
2000 // Currently only Emscripten supports dynamic linking with threads. Therefore,
2001 // on other targets, if we have thread-local storage, only the local-exec
2002 // model is possible.
2003 auto model = Subtarget->getTargetTriple().isOSEmscripten()
2004 ? GV->getThreadLocalMode()
2006
2007 // Unsupported TLS modes
2010
2011 if (model == GlobalValue::LocalExecTLSModel ||
2014 getTargetMachine().shouldAssumeDSOLocal(GV))) {
2015 // For DSO-local TLS variables we use offset from __tls_base
2016
2017 MVT PtrVT = getPointerTy(DAG.getDataLayout());
2018 auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
2019 : WebAssembly::GLOBAL_GET_I32;
2020 const char *BaseName = MF.createExternalSymbolName("__tls_base");
2021
2023 DAG.getMachineNode(GlobalGet, DL, PtrVT,
2024 DAG.getTargetExternalSymbol(BaseName, PtrVT)),
2025 0);
2026
2027 SDValue TLSOffset = DAG.getTargetGlobalAddress(
2028 GV, DL, PtrVT, GA->getOffset(), WebAssemblyII::MO_TLS_BASE_REL);
2029 SDValue SymOffset =
2030 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, TLSOffset);
2031
2032 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymOffset);
2033 }
2034
2036
2037 EVT VT = Op.getValueType();
2038 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2039 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2040 GA->getOffset(),
2042}
2043
2044SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
2045 SelectionDAG &DAG) const {
2046 SDLoc DL(Op);
2047 const auto *GA = cast<GlobalAddressSDNode>(Op);
2048 EVT VT = Op.getValueType();
2049 assert(GA->getTargetFlags() == 0 &&
2050 "Unexpected target flags on generic GlobalAddressSDNode");
2052 fail(DL, DAG, "Invalid address space for WebAssembly target");
2053
2054 unsigned OperandFlags = 0;
2055 const GlobalValue *GV = GA->getGlobal();
2056 // Since WebAssembly tables cannot yet be shared accross modules, we don't
2057 // need special treatment for tables in PIC mode.
2058 if (isPositionIndependent() &&
2060 if (getTargetMachine().shouldAssumeDSOLocal(GV)) {
2061 MachineFunction &MF = DAG.getMachineFunction();
2062 MVT PtrVT = getPointerTy(MF.getDataLayout());
2063 const char *BaseName;
2064 if (GV->getValueType()->isFunctionTy()) {
2065 BaseName = MF.createExternalSymbolName("__table_base");
2067 } else {
2068 BaseName = MF.createExternalSymbolName("__memory_base");
2070 }
2072 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2073 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2074
2075 SDValue SymAddr = DAG.getNode(
2076 WebAssemblyISD::WrapperREL, DL, VT,
2077 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
2078 OperandFlags));
2079
2080 return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
2081 }
2083 }
2084
2085 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2086 DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT,
2087 GA->getOffset(), OperandFlags));
2088}
2089
2090SDValue
2091WebAssemblyTargetLowering::LowerExternalSymbol(SDValue Op,
2092 SelectionDAG &DAG) const {
2093 SDLoc DL(Op);
2094 const auto *ES = cast<ExternalSymbolSDNode>(Op);
2095 EVT VT = Op.getValueType();
2096 assert(ES->getTargetFlags() == 0 &&
2097 "Unexpected target flags on generic ExternalSymbolSDNode");
2098 return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
2099 DAG.getTargetExternalSymbol(ES->getSymbol(), VT));
2100}
2101
2102SDValue WebAssemblyTargetLowering::LowerJumpTable(SDValue Op,
2103 SelectionDAG &DAG) const {
2104 // There's no need for a Wrapper node because we always incorporate a jump
2105 // table operand into a BR_TABLE instruction, rather than ever
2106 // materializing it in a register.
2107 const JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
2108 return DAG.getTargetJumpTable(JT->getIndex(), Op.getValueType(),
2109 JT->getTargetFlags());
2110}
2111
2112SDValue WebAssemblyTargetLowering::LowerBR_JT(SDValue Op,
2113 SelectionDAG &DAG) const {
2114 SDLoc DL(Op);
2115 SDValue Chain = Op.getOperand(0);
2116 const auto *JT = cast<JumpTableSDNode>(Op.getOperand(1));
2117 SDValue Index = Op.getOperand(2);
2118 assert(JT->getTargetFlags() == 0 && "WebAssembly doesn't set target flags");
2119
2121 Ops.push_back(Chain);
2122 Ops.push_back(Index);
2123
2124 MachineJumpTableInfo *MJTI = DAG.getMachineFunction().getJumpTableInfo();
2125 const auto &MBBs = MJTI->getJumpTables()[JT->getIndex()].MBBs;
2126
2127 // Add an operand for each case.
2128 for (auto *MBB : MBBs)
2129 Ops.push_back(DAG.getBasicBlock(MBB));
2130
2131 // Add the first MBB as a dummy default target for now. This will be replaced
2132 // with the proper default target (and the preceding range check eliminated)
2133 // if possible by WebAssemblyFixBrTableDefaults.
2134 Ops.push_back(DAG.getBasicBlock(*MBBs.begin()));
2135 return DAG.getNode(WebAssemblyISD::BR_TABLE, DL, MVT::Other, Ops);
2136}
2137
2138SDValue WebAssemblyTargetLowering::LowerVASTART(SDValue Op,
2139 SelectionDAG &DAG) const {
2140 SDLoc DL(Op);
2141 EVT PtrVT = getPointerTy(DAG.getMachineFunction().getDataLayout());
2142
2143 auto *MFI = DAG.getMachineFunction().getInfo<WebAssemblyFunctionInfo>();
2144 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
2145
2146 SDValue ArgN = DAG.getCopyFromReg(DAG.getEntryNode(), DL,
2147 MFI->getVarargBufferVreg(), PtrVT);
2148 return DAG.getStore(Op.getOperand(0), DL, ArgN, Op.getOperand(1),
2149 MachinePointerInfo(SV));
2150}
2151
2152SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
2153 SelectionDAG &DAG) const {
2154 MachineFunction &MF = DAG.getMachineFunction();
2155 unsigned IntNo;
2156 switch (Op.getOpcode()) {
2159 IntNo = Op.getConstantOperandVal(1);
2160 break;
2162 IntNo = Op.getConstantOperandVal(0);
2163 break;
2164 default:
2165 llvm_unreachable("Invalid intrinsic");
2166 }
2167 SDLoc DL(Op);
2168
2169 switch (IntNo) {
2170 default:
2171 return SDValue(); // Don't custom lower most intrinsics.
2172
2173 case Intrinsic::wasm_lsda: {
2174 auto PtrVT = getPointerTy(MF.getDataLayout());
2175 const char *SymName = MF.createExternalSymbolName(
2176 "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
2177 if (isPositionIndependent()) {
2179 SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
2180 const char *BaseName = MF.createExternalSymbolName("__memory_base");
2182 DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
2183 DAG.getTargetExternalSymbol(BaseName, PtrVT));
2184 SDValue SymAddr =
2185 DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
2186 return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
2187 }
2188 SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
2189 return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
2190 }
2191
2192 case Intrinsic::wasm_shuffle: {
2193 // Drop in-chain and replace undefs, but otherwise pass through unchanged
2194 SDValue Ops[18];
2195 size_t OpIdx = 0;
2196 Ops[OpIdx++] = Op.getOperand(1);
2197 Ops[OpIdx++] = Op.getOperand(2);
2198 while (OpIdx < 18) {
2199 const SDValue &MaskIdx = Op.getOperand(OpIdx + 1);
2200 if (MaskIdx.isUndef() || MaskIdx.getNode()->getAsZExtVal() >= 32) {
2201 bool isTarget = MaskIdx.getNode()->getOpcode() == ISD::TargetConstant;
2202 Ops[OpIdx++] = DAG.getConstant(0, DL, MVT::i32, isTarget);
2203 } else {
2204 Ops[OpIdx++] = MaskIdx;
2205 }
2206 }
2207 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2208 }
2209
2210 case Intrinsic::thread_pointer: {
2211 MVT PtrVT = getPointerTy(DAG.getDataLayout());
2212 auto GlobalGet = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
2213 : WebAssembly::GLOBAL_GET_I32;
2214 const char *TlsBase = MF.createExternalSymbolName("__tls_base");
2215 return SDValue(
2216 DAG.getMachineNode(GlobalGet, DL, PtrVT,
2217 DAG.getTargetExternalSymbol(TlsBase, PtrVT)),
2218 0);
2219 }
2220 }
2221}
2222
2223SDValue
2224WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
2225 SelectionDAG &DAG) const {
2226 SDLoc DL(Op);
2227 // If sign extension operations are disabled, allow sext_inreg only if operand
2228 // is a vector extract of an i8 or i16 lane. SIMD does not depend on sign
2229 // extension operations, but allowing sext_inreg in this context lets us have
2230 // simple patterns to select extract_lane_s instructions. Expanding sext_inreg
2231 // everywhere would be simpler in this file, but would necessitate large and
2232 // brittle patterns to undo the expansion and select extract_lane_s
2233 // instructions.
2234 assert(!Subtarget->hasSignExt() && Subtarget->hasSIMD128());
2235 if (Op.getOperand(0).getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2236 return SDValue();
2237
2238 const SDValue &Extract = Op.getOperand(0);
2239 MVT VecT = Extract.getOperand(0).getSimpleValueType();
2240 if (VecT.getVectorElementType().getSizeInBits() > 32)
2241 return SDValue();
2242 MVT ExtractedLaneT =
2243 cast<VTSDNode>(Op.getOperand(1).getNode())->getVT().getSimpleVT();
2244 MVT ExtractedVecT =
2245 MVT::getVectorVT(ExtractedLaneT, 128 / ExtractedLaneT.getSizeInBits());
2246 if (ExtractedVecT == VecT)
2247 return Op;
2248
2249 // Bitcast vector to appropriate type to ensure ISel pattern coverage
2250 const SDNode *Index = Extract.getOperand(1).getNode();
2251 if (!isa<ConstantSDNode>(Index))
2252 return SDValue();
2253 unsigned IndexVal = Index->getAsZExtVal();
2254 unsigned Scale =
2255 ExtractedVecT.getVectorNumElements() / VecT.getVectorNumElements();
2256 assert(Scale > 1);
2257 SDValue NewIndex =
2258 DAG.getConstant(IndexVal * Scale, DL, Index->getValueType(0));
2259 SDValue NewExtract = DAG.getNode(
2261 DAG.getBitcast(ExtractedVecT, Extract.getOperand(0)), NewIndex);
2262 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Op.getValueType(), NewExtract,
2263 Op.getOperand(1));
2264}
2265
2266static SDValue GetExtendHigh(SDValue Op, unsigned UserOpc, EVT VT,
2267 SelectionDAG &DAG) {
2268 if (Op.getOpcode() != ISD::VECTOR_SHUFFLE)
2269 return SDValue();
2270
2271 assert((UserOpc == WebAssemblyISD::EXTEND_LOW_U ||
2272 UserOpc == WebAssemblyISD::EXTEND_LOW_S) &&
2273 "expected extend_low");
2274 auto *Shuffle = cast<ShuffleVectorSDNode>(Op.getNode());
2275
2276 ArrayRef<int> Mask = Shuffle->getMask();
2277 // Look for a shuffle which moves from the high half to the low half.
2278 size_t FirstIdx = Mask.size() / 2;
2279 for (size_t i = 0; i < Mask.size() / 2; ++i) {
2280 if (Mask[i] != static_cast<int>(FirstIdx + i)) {
2281 return SDValue();
2282 }
2283 }
2284
2285 SDLoc DL(Op);
2286 unsigned Opc = UserOpc == WebAssemblyISD::EXTEND_LOW_S
2287 ? WebAssemblyISD::EXTEND_HIGH_S
2288 : WebAssemblyISD::EXTEND_HIGH_U;
2289 return DAG.getNode(Opc, DL, VT, Shuffle->getOperand(0));
2290}
2291
2292SDValue
2293WebAssemblyTargetLowering::LowerEXTEND_VECTOR_INREG(SDValue Op,
2294 SelectionDAG &DAG) const {
2295 SDLoc DL(Op);
2296 EVT VT = Op.getValueType();
2297 SDValue Src = Op.getOperand(0);
2298 EVT SrcVT = Src.getValueType();
2299
2300 if (SrcVT.getVectorElementType() == MVT::i1 ||
2301 SrcVT.getVectorElementType() == MVT::i64)
2302 return SDValue();
2303
2304 assert(VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits() == 0 &&
2305 "Unexpected extension factor.");
2306 unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits();
2307
2308 if (Scale != 2 && Scale != 4 && Scale != 8)
2309 return SDValue();
2310
2311 unsigned Ext;
2312 switch (Op.getOpcode()) {
2314 Ext = WebAssemblyISD::EXTEND_LOW_U;
2315 break;
2317 Ext = WebAssemblyISD::EXTEND_LOW_S;
2318 break;
2319 }
2320
2321 if (Scale == 2) {
2322 // See if we can use EXTEND_HIGH.
2323 if (auto ExtendHigh = GetExtendHigh(Op.getOperand(0), Ext, VT, DAG))
2324 return ExtendHigh;
2325 }
2326
2327 SDValue Ret = Src;
2328 while (Scale != 1) {
2329 Ret = DAG.getNode(Ext, DL,
2330 Ret.getValueType()
2331 .widenIntegerVectorElementType(*DAG.getContext())
2332 .getHalfNumVectorElementsVT(*DAG.getContext()),
2333 Ret);
2334 Scale /= 2;
2335 }
2336 assert(Ret.getValueType() == VT);
2337 return Ret;
2338}
2339
2341 SDLoc DL(Op);
2342 if (Op.getValueType() != MVT::v2f64)
2343 return SDValue();
2344
2345 auto GetConvertedLane = [](SDValue Op, unsigned &Opcode, SDValue &SrcVec,
2346 unsigned &Index) -> bool {
2347 switch (Op.getOpcode()) {
2348 case ISD::SINT_TO_FP:
2349 Opcode = WebAssemblyISD::CONVERT_LOW_S;
2350 break;
2351 case ISD::UINT_TO_FP:
2352 Opcode = WebAssemblyISD::CONVERT_LOW_U;
2353 break;
2354 case ISD::FP_EXTEND:
2355 Opcode = WebAssemblyISD::PROMOTE_LOW;
2356 break;
2357 default:
2358 return false;
2359 }
2360
2361 auto ExtractVector = Op.getOperand(0);
2362 if (ExtractVector.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2363 return false;
2364
2365 if (!isa<ConstantSDNode>(ExtractVector.getOperand(1).getNode()))
2366 return false;
2367
2368 SrcVec = ExtractVector.getOperand(0);
2369 Index = ExtractVector.getConstantOperandVal(1);
2370 return true;
2371 };
2372
2373 unsigned LHSOpcode, RHSOpcode, LHSIndex, RHSIndex;
2374 SDValue LHSSrcVec, RHSSrcVec;
2375 if (!GetConvertedLane(Op.getOperand(0), LHSOpcode, LHSSrcVec, LHSIndex) ||
2376 !GetConvertedLane(Op.getOperand(1), RHSOpcode, RHSSrcVec, RHSIndex))
2377 return SDValue();
2378
2379 if (LHSOpcode != RHSOpcode)
2380 return SDValue();
2381
2382 MVT ExpectedSrcVT;
2383 switch (LHSOpcode) {
2384 case WebAssemblyISD::CONVERT_LOW_S:
2385 case WebAssemblyISD::CONVERT_LOW_U:
2386 ExpectedSrcVT = MVT::v4i32;
2387 break;
2388 case WebAssemblyISD::PROMOTE_LOW:
2389 ExpectedSrcVT = MVT::v4f32;
2390 break;
2391 }
2392 if (LHSSrcVec.getValueType() != ExpectedSrcVT)
2393 return SDValue();
2394
2395 auto Src = LHSSrcVec;
2396 if (LHSIndex != 0 || RHSIndex != 1 || LHSSrcVec != RHSSrcVec) {
2397 // Shuffle the source vector so that the converted lanes are the low lanes.
2398 Src = DAG.getVectorShuffle(
2399 ExpectedSrcVT, DL, LHSSrcVec, RHSSrcVec,
2400 {static_cast<int>(LHSIndex), static_cast<int>(RHSIndex) + 4, -1, -1});
2401 }
2402 return DAG.getNode(LHSOpcode, DL, MVT::v2f64, Src);
2403}
2404
2405SDValue WebAssemblyTargetLowering::LowerBUILD_VECTOR(SDValue Op,
2406 SelectionDAG &DAG) const {
2407 MVT VT = Op.getSimpleValueType();
2408 if (VT == MVT::v8f16) {
2409 // BUILD_VECTOR can't handle FP16 operands since Wasm doesn't have a scaler
2410 // FP16 type, so cast them to I16s.
2411 MVT IVT = VT.changeVectorElementType(MVT::i16);
2413 for (unsigned I = 0, E = Op.getNumOperands(); I < E; ++I)
2414 NewOps.push_back(DAG.getBitcast(MVT::i16, Op.getOperand(I)));
2415 SDValue Res = DAG.getNode(ISD::BUILD_VECTOR, SDLoc(), IVT, NewOps);
2416 return DAG.getBitcast(VT, Res);
2417 }
2418
2419 if (auto ConvertLow = LowerConvertLow(Op, DAG))
2420 return ConvertLow;
2421
2422 SDLoc DL(Op);
2423 const EVT VecT = Op.getValueType();
2424 const EVT LaneT = Op.getOperand(0).getValueType();
2425 const size_t Lanes = Op.getNumOperands();
2426 bool CanSwizzle = VecT == MVT::v16i8;
2427
2428 // BUILD_VECTORs are lowered to the instruction that initializes the highest
2429 // possible number of lanes at once followed by a sequence of replace_lane
2430 // instructions to individually initialize any remaining lanes.
2431
2432 // TODO: Tune this. For example, lanewise swizzling is very expensive, so
2433 // swizzled lanes should be given greater weight.
2434
2435 // TODO: Investigate looping rather than always extracting/replacing specific
2436 // lanes to fill gaps.
2437
2438 auto IsConstant = [](const SDValue &V) {
2439 return V.getOpcode() == ISD::Constant || V.getOpcode() == ISD::ConstantFP;
2440 };
2441
2442 // Returns the source vector and index vector pair if they exist. Checks for:
2443 // (extract_vector_elt
2444 // $src,
2445 // (sign_extend_inreg (extract_vector_elt $indices, $i))
2446 // )
2447 auto GetSwizzleSrcs = [](size_t I, const SDValue &Lane) {
2448 auto Bail = std::make_pair(SDValue(), SDValue());
2449 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2450 return Bail;
2451 const SDValue &SwizzleSrc = Lane->getOperand(0);
2452 const SDValue &IndexExt = Lane->getOperand(1);
2453 if (IndexExt->getOpcode() != ISD::SIGN_EXTEND_INREG)
2454 return Bail;
2455 const SDValue &Index = IndexExt->getOperand(0);
2456 if (Index->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2457 return Bail;
2458 const SDValue &SwizzleIndices = Index->getOperand(0);
2459 if (SwizzleSrc.getValueType() != MVT::v16i8 ||
2460 SwizzleIndices.getValueType() != MVT::v16i8 ||
2461 Index->getOperand(1)->getOpcode() != ISD::Constant ||
2462 Index->getConstantOperandVal(1) != I)
2463 return Bail;
2464 return std::make_pair(SwizzleSrc, SwizzleIndices);
2465 };
2466
2467 // If the lane is extracted from another vector at a constant index, return
2468 // that vector. The source vector must not have more lanes than the dest
2469 // because the shufflevector indices are in terms of the destination lanes and
2470 // would not be able to address the smaller individual source lanes.
2471 auto GetShuffleSrc = [&](const SDValue &Lane) {
2472 if (Lane->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
2473 return SDValue();
2474 if (!isa<ConstantSDNode>(Lane->getOperand(1).getNode()))
2475 return SDValue();
2476 if (Lane->getOperand(0).getValueType().getVectorNumElements() >
2477 VecT.getVectorNumElements())
2478 return SDValue();
2479 return Lane->getOperand(0);
2480 };
2481
2482 using ValueEntry = std::pair<SDValue, size_t>;
2483 SmallVector<ValueEntry, 16> SplatValueCounts;
2484
2485 using SwizzleEntry = std::pair<std::pair<SDValue, SDValue>, size_t>;
2486 SmallVector<SwizzleEntry, 16> SwizzleCounts;
2487
2488 using ShuffleEntry = std::pair<SDValue, size_t>;
2489 SmallVector<ShuffleEntry, 16> ShuffleCounts;
2490
2491 auto AddCount = [](auto &Counts, const auto &Val) {
2492 auto CountIt =
2493 llvm::find_if(Counts, [&Val](auto E) { return E.first == Val; });
2494 if (CountIt == Counts.end()) {
2495 Counts.emplace_back(Val, 1);
2496 } else {
2497 CountIt->second++;
2498 }
2499 };
2500
2501 auto GetMostCommon = [](auto &Counts) {
2502 auto CommonIt = llvm::max_element(Counts, llvm::less_second());
2503 assert(CommonIt != Counts.end() && "Unexpected all-undef build_vector");
2504 return *CommonIt;
2505 };
2506
2507 size_t NumConstantLanes = 0;
2508
2509 // Count eligible lanes for each type of vector creation op
2510 for (size_t I = 0; I < Lanes; ++I) {
2511 const SDValue &Lane = Op->getOperand(I);
2512 if (Lane.isUndef())
2513 continue;
2514
2515 AddCount(SplatValueCounts, Lane);
2516
2517 if (IsConstant(Lane))
2518 NumConstantLanes++;
2519 if (auto ShuffleSrc = GetShuffleSrc(Lane))
2520 AddCount(ShuffleCounts, ShuffleSrc);
2521 if (CanSwizzle) {
2522 auto SwizzleSrcs = GetSwizzleSrcs(I, Lane);
2523 if (SwizzleSrcs.first)
2524 AddCount(SwizzleCounts, SwizzleSrcs);
2525 }
2526 }
2527
2528 SDValue SplatValue;
2529 size_t NumSplatLanes;
2530 std::tie(SplatValue, NumSplatLanes) = GetMostCommon(SplatValueCounts);
2531
2532 SDValue SwizzleSrc;
2533 SDValue SwizzleIndices;
2534 size_t NumSwizzleLanes = 0;
2535 if (SwizzleCounts.size())
2536 std::forward_as_tuple(std::tie(SwizzleSrc, SwizzleIndices),
2537 NumSwizzleLanes) = GetMostCommon(SwizzleCounts);
2538
2539 // Shuffles can draw from up to two vectors, so find the two most common
2540 // sources.
2541 SDValue ShuffleSrc1, ShuffleSrc2;
2542 size_t NumShuffleLanes = 0;
2543 if (ShuffleCounts.size()) {
2544 std::tie(ShuffleSrc1, NumShuffleLanes) = GetMostCommon(ShuffleCounts);
2545 llvm::erase_if(ShuffleCounts,
2546 [&](const auto &Pair) { return Pair.first == ShuffleSrc1; });
2547 }
2548 if (ShuffleCounts.size()) {
2549 size_t AdditionalShuffleLanes;
2550 std::tie(ShuffleSrc2, AdditionalShuffleLanes) =
2551 GetMostCommon(ShuffleCounts);
2552 NumShuffleLanes += AdditionalShuffleLanes;
2553 }
2554
2555 // Predicate returning true if the lane is properly initialized by the
2556 // original instruction
2557 std::function<bool(size_t, const SDValue &)> IsLaneConstructed;
2559 // Prefer swizzles over shuffles over vector consts over splats
2560 if (NumSwizzleLanes >= NumShuffleLanes &&
2561 NumSwizzleLanes >= NumConstantLanes && NumSwizzleLanes >= NumSplatLanes) {
2562 Result = DAG.getNode(WebAssemblyISD::SWIZZLE, DL, VecT, SwizzleSrc,
2563 SwizzleIndices);
2564 auto Swizzled = std::make_pair(SwizzleSrc, SwizzleIndices);
2565 IsLaneConstructed = [&, Swizzled](size_t I, const SDValue &Lane) {
2566 return Swizzled == GetSwizzleSrcs(I, Lane);
2567 };
2568 } else if (NumShuffleLanes >= NumConstantLanes &&
2569 NumShuffleLanes >= NumSplatLanes) {
2570 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits() / 8;
2571 size_t DestLaneCount = VecT.getVectorNumElements();
2572 size_t Scale1 = 1;
2573 size_t Scale2 = 1;
2574 SDValue Src1 = ShuffleSrc1;
2575 SDValue Src2 = ShuffleSrc2 ? ShuffleSrc2 : DAG.getUNDEF(VecT);
2576 if (Src1.getValueType() != VecT) {
2577 size_t LaneSize =
2579 assert(LaneSize > DestLaneSize);
2580 Scale1 = LaneSize / DestLaneSize;
2581 Src1 = DAG.getBitcast(VecT, Src1);
2582 }
2583 if (Src2.getValueType() != VecT) {
2584 size_t LaneSize =
2586 assert(LaneSize > DestLaneSize);
2587 Scale2 = LaneSize / DestLaneSize;
2588 Src2 = DAG.getBitcast(VecT, Src2);
2589 }
2590
2591 int Mask[16];
2592 assert(DestLaneCount <= 16);
2593 for (size_t I = 0; I < DestLaneCount; ++I) {
2594 const SDValue &Lane = Op->getOperand(I);
2595 SDValue Src = GetShuffleSrc(Lane);
2596 if (Src == ShuffleSrc1) {
2597 Mask[I] = Lane->getConstantOperandVal(1) * Scale1;
2598 } else if (Src && Src == ShuffleSrc2) {
2599 Mask[I] = DestLaneCount + Lane->getConstantOperandVal(1) * Scale2;
2600 } else {
2601 Mask[I] = -1;
2602 }
2603 }
2604 ArrayRef<int> MaskRef(Mask, DestLaneCount);
2605 Result = DAG.getVectorShuffle(VecT, DL, Src1, Src2, MaskRef);
2606 IsLaneConstructed = [&](size_t, const SDValue &Lane) {
2607 auto Src = GetShuffleSrc(Lane);
2608 return Src == ShuffleSrc1 || (Src && Src == ShuffleSrc2);
2609 };
2610 } else if (NumConstantLanes >= NumSplatLanes) {
2611 SmallVector<SDValue, 16> ConstLanes;
2612 for (const SDValue &Lane : Op->op_values()) {
2613 if (IsConstant(Lane)) {
2614 // Values may need to be fixed so that they will sign extend to be
2615 // within the expected range during ISel. Check whether the value is in
2616 // bounds based on the lane bit width and if it is out of bounds, lop
2617 // off the extra bits and subtract 2^n to reflect giving the high bit
2618 // value -2^(n-1) rather than +2^(n-1). Skip the i64 case because it
2619 // cannot possibly be out of range.
2620 auto *Const = dyn_cast<ConstantSDNode>(Lane.getNode());
2621 int64_t Val = Const ? Const->getSExtValue() : 0;
2622 uint64_t LaneBits = 128 / Lanes;
2623 assert((LaneBits == 64 || Val >= -(1ll << (LaneBits - 1))) &&
2624 "Unexpected out of bounds negative value");
2625 if (Const && LaneBits != 64 && Val > (1ll << (LaneBits - 1)) - 1) {
2626 uint64_t Mask = (1ll << LaneBits) - 1;
2627 auto NewVal = (((uint64_t)Val & Mask) - (1ll << LaneBits)) & Mask;
2628 ConstLanes.push_back(DAG.getConstant(NewVal, SDLoc(Lane), LaneT));
2629 } else {
2630 ConstLanes.push_back(Lane);
2631 }
2632 } else if (LaneT.isFloatingPoint()) {
2633 ConstLanes.push_back(DAG.getConstantFP(0, DL, LaneT));
2634 } else {
2635 ConstLanes.push_back(DAG.getConstant(0, DL, LaneT));
2636 }
2637 }
2638 Result = DAG.getBuildVector(VecT, DL, ConstLanes);
2639 IsLaneConstructed = [&IsConstant](size_t _, const SDValue &Lane) {
2640 return IsConstant(Lane);
2641 };
2642 } else {
2643 size_t DestLaneSize = VecT.getVectorElementType().getFixedSizeInBits();
2644 if (NumSplatLanes == 1 && Op->getOperand(0) == SplatValue &&
2645 (DestLaneSize == 32 || DestLaneSize == 64)) {
2646 // Could be selected to load_zero.
2647 Result = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecT, SplatValue);
2648 } else {
2649 // Use a splat (which might be selected as a load splat)
2650 Result = DAG.getSplatBuildVector(VecT, DL, SplatValue);
2651 }
2652 IsLaneConstructed = [&SplatValue](size_t _, const SDValue &Lane) {
2653 return Lane == SplatValue;
2654 };
2655 }
2656
2657 assert(Result);
2658 assert(IsLaneConstructed);
2659
2660 // Add replace_lane instructions for any unhandled values
2661 for (size_t I = 0; I < Lanes; ++I) {
2662 const SDValue &Lane = Op->getOperand(I);
2663 if (!Lane.isUndef() && !IsLaneConstructed(I, Lane))
2664 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VecT, Result, Lane,
2665 DAG.getConstant(I, DL, MVT::i32));
2666 }
2667
2668 return Result;
2669}
2670
2671SDValue
2672WebAssemblyTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2673 SelectionDAG &DAG) const {
2674 SDLoc DL(Op);
2675 ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op.getNode())->getMask();
2676 MVT VecType = Op.getOperand(0).getSimpleValueType();
2677 assert(VecType.is128BitVector() && "Unexpected shuffle vector type");
2678 size_t LaneBytes = VecType.getVectorElementType().getSizeInBits() / 8;
2679
2680 // Space for two vector args and sixteen mask indices
2681 SDValue Ops[18];
2682 size_t OpIdx = 0;
2683 Ops[OpIdx++] = Op.getOperand(0);
2684 Ops[OpIdx++] = Op.getOperand(1);
2685
2686 // Expand mask indices to byte indices and materialize them as operands
2687 for (int M : Mask) {
2688 for (size_t J = 0; J < LaneBytes; ++J) {
2689 // Lower undefs (represented by -1 in mask) to {0..J}, which use a
2690 // whole lane of vector input, to allow further reduction at VM. E.g.
2691 // match an 8x16 byte shuffle to an equivalent cheaper 32x4 shuffle.
2692 uint64_t ByteIndex = M == -1 ? J : (uint64_t)M * LaneBytes + J;
2693 Ops[OpIdx++] = DAG.getConstant(ByteIndex, DL, MVT::i32);
2694 }
2695 }
2696
2697 return DAG.getNode(WebAssemblyISD::SHUFFLE, DL, Op.getValueType(), Ops);
2698}
2699
2700SDValue WebAssemblyTargetLowering::LowerSETCC(SDValue Op,
2701 SelectionDAG &DAG) const {
2702 SDLoc DL(Op);
2703 // The legalizer does not know how to expand the unsupported comparison modes
2704 // of i64x2 vectors, so we manually unroll them here.
2705 assert(Op->getOperand(0)->getSimpleValueType(0) == MVT::v2i64);
2707 DAG.ExtractVectorElements(Op->getOperand(0), LHS);
2708 DAG.ExtractVectorElements(Op->getOperand(1), RHS);
2709 const SDValue &CC = Op->getOperand(2);
2710 auto MakeLane = [&](unsigned I) {
2711 return DAG.getNode(ISD::SELECT_CC, DL, MVT::i64, LHS[I], RHS[I],
2712 DAG.getConstant(uint64_t(-1), DL, MVT::i64),
2713 DAG.getConstant(uint64_t(0), DL, MVT::i64), CC);
2714 };
2715 return DAG.getBuildVector(Op->getValueType(0), DL,
2716 {MakeLane(0), MakeLane(1)});
2717}
2718
2719SDValue
2720WebAssemblyTargetLowering::LowerAccessVectorElement(SDValue Op,
2721 SelectionDAG &DAG) const {
2722 // Allow constant lane indices, expand variable lane indices
2723 SDNode *IdxNode = Op.getOperand(Op.getNumOperands() - 1).getNode();
2724 if (isa<ConstantSDNode>(IdxNode)) {
2725 // Ensure the index type is i32 to match the tablegen patterns
2726 uint64_t Idx = IdxNode->getAsZExtVal();
2727 SmallVector<SDValue, 3> Ops(Op.getNode()->ops());
2728 Ops[Op.getNumOperands() - 1] =
2729 DAG.getConstant(Idx, SDLoc(IdxNode), MVT::i32);
2730 return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Ops);
2731 }
2732 // Perform default expansion
2733 return SDValue();
2734}
2735
2737 EVT LaneT = Op.getSimpleValueType().getVectorElementType();
2738 // 32-bit and 64-bit unrolled shifts will have proper semantics
2739 if (LaneT.bitsGE(MVT::i32))
2740 return DAG.UnrollVectorOp(Op.getNode());
2741 // Otherwise mask the shift value to get proper semantics from 32-bit shift
2742 SDLoc DL(Op);
2743 size_t NumLanes = Op.getSimpleValueType().getVectorNumElements();
2744 SDValue Mask = DAG.getConstant(LaneT.getSizeInBits() - 1, DL, MVT::i32);
2745 unsigned ShiftOpcode = Op.getOpcode();
2746 SmallVector<SDValue, 16> ShiftedElements;
2747 DAG.ExtractVectorElements(Op.getOperand(0), ShiftedElements, 0, 0, MVT::i32);
2748 SmallVector<SDValue, 16> ShiftElements;
2749 DAG.ExtractVectorElements(Op.getOperand(1), ShiftElements, 0, 0, MVT::i32);
2750 SmallVector<SDValue, 16> UnrolledOps;
2751 for (size_t i = 0; i < NumLanes; ++i) {
2752 SDValue MaskedShiftValue =
2753 DAG.getNode(ISD::AND, DL, MVT::i32, ShiftElements[i], Mask);
2754 SDValue ShiftedValue = ShiftedElements[i];
2755 if (ShiftOpcode == ISD::SRA)
2756 ShiftedValue = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32,
2757 ShiftedValue, DAG.getValueType(LaneT));
2758 UnrolledOps.push_back(
2759 DAG.getNode(ShiftOpcode, DL, MVT::i32, ShiftedValue, MaskedShiftValue));
2760 }
2761 return DAG.getBuildVector(Op.getValueType(), DL, UnrolledOps);
2762}
2763
2764SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op,
2765 SelectionDAG &DAG) const {
2766 SDLoc DL(Op);
2767
2768 // Only manually lower vector shifts
2769 assert(Op.getSimpleValueType().isVector());
2770
2771 uint64_t LaneBits = Op.getValueType().getScalarSizeInBits();
2772 auto ShiftVal = Op.getOperand(1);
2773
2774 // Try to skip bitmask operation since it is implied inside shift instruction
2775 auto SkipImpliedMask = [](SDValue MaskOp, uint64_t MaskBits) {
2776 if (MaskOp.getOpcode() != ISD::AND)
2777 return MaskOp;
2778 SDValue LHS = MaskOp.getOperand(0);
2779 SDValue RHS = MaskOp.getOperand(1);
2780 if (MaskOp.getValueType().isVector()) {
2781 APInt MaskVal;
2782 if (!ISD::isConstantSplatVector(RHS.getNode(), MaskVal))
2783 std::swap(LHS, RHS);
2784
2785 if (ISD::isConstantSplatVector(RHS.getNode(), MaskVal) &&
2786 MaskVal == MaskBits)
2787 MaskOp = LHS;
2788 } else {
2789 if (!isa<ConstantSDNode>(RHS.getNode()))
2790 std::swap(LHS, RHS);
2791
2792 auto ConstantRHS = dyn_cast<ConstantSDNode>(RHS.getNode());
2793 if (ConstantRHS && ConstantRHS->getAPIntValue() == MaskBits)
2794 MaskOp = LHS;
2795 }
2796
2797 return MaskOp;
2798 };
2799
2800 // Skip vector and operation
2801 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2802 ShiftVal = DAG.getSplatValue(ShiftVal);
2803 if (!ShiftVal)
2804 return unrollVectorShift(Op, DAG);
2805
2806 // Skip scalar and operation
2807 ShiftVal = SkipImpliedMask(ShiftVal, LaneBits - 1);
2808 // Use anyext because none of the high bits can affect the shift
2809 ShiftVal = DAG.getAnyExtOrTrunc(ShiftVal, DL, MVT::i32);
2810
2811 unsigned Opcode;
2812 switch (Op.getOpcode()) {
2813 case ISD::SHL:
2814 Opcode = WebAssemblyISD::VEC_SHL;
2815 break;
2816 case ISD::SRA:
2817 Opcode = WebAssemblyISD::VEC_SHR_S;
2818 break;
2819 case ISD::SRL:
2820 Opcode = WebAssemblyISD::VEC_SHR_U;
2821 break;
2822 default:
2823 llvm_unreachable("unexpected opcode");
2824 }
2825
2826 return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), ShiftVal);
2827}
2828
2829SDValue WebAssemblyTargetLowering::LowerFP_TO_INT_SAT(SDValue Op,
2830 SelectionDAG &DAG) const {
2831 EVT ResT = Op.getValueType();
2832 EVT SatVT = cast<VTSDNode>(Op.getOperand(1))->getVT();
2833
2834 if ((ResT == MVT::i32 || ResT == MVT::i64) &&
2835 (SatVT == MVT::i32 || SatVT == MVT::i64))
2836 return Op;
2837
2838 if (ResT == MVT::v4i32 && SatVT == MVT::i32)
2839 return Op;
2840
2841 if (ResT == MVT::v8i16 && SatVT == MVT::i16)
2842 return Op;
2843
2844 return SDValue();
2845}
2846
2847//===----------------------------------------------------------------------===//
2848// Custom DAG combine hooks
2849//===----------------------------------------------------------------------===//
2850static SDValue
2852 auto &DAG = DCI.DAG;
2853 auto Shuffle = cast<ShuffleVectorSDNode>(N);
2854
2855 // Hoist vector bitcasts that don't change the number of lanes out of unary
2856 // shuffles, where they are less likely to get in the way of other combines.
2857 // (shuffle (vNxT1 (bitcast (vNxT0 x))), undef, mask) ->
2858 // (vNxT1 (bitcast (vNxT0 (shuffle x, undef, mask))))
2859 SDValue Bitcast = N->getOperand(0);
2860 if (Bitcast.getOpcode() != ISD::BITCAST)
2861 return SDValue();
2862 if (!N->getOperand(1).isUndef())
2863 return SDValue();
2864 SDValue CastOp = Bitcast.getOperand(0);
2865 EVT SrcType = CastOp.getValueType();
2866 EVT DstType = Bitcast.getValueType();
2867 if (!SrcType.is128BitVector() ||
2868 SrcType.getVectorNumElements() != DstType.getVectorNumElements())
2869 return SDValue();
2870 SDValue NewShuffle = DAG.getVectorShuffle(
2871 SrcType, SDLoc(N), CastOp, DAG.getUNDEF(SrcType), Shuffle->getMask());
2872 return DAG.getBitcast(DstType, NewShuffle);
2873}
2874
2875/// Convert ({u,s}itofp vec) --> ({u,s}itofp ({s,z}ext vec)) so it doesn't get
2876/// split up into scalar instructions during legalization, and the vector
2877/// extending instructions are selected in performVectorExtendCombine below.
2878static SDValue
2881 auto &DAG = DCI.DAG;
2882 assert(N->getOpcode() == ISD::UINT_TO_FP ||
2883 N->getOpcode() == ISD::SINT_TO_FP);
2884
2885 EVT InVT = N->getOperand(0)->getValueType(0);
2886 EVT ResVT = N->getValueType(0);
2887 MVT ExtVT;
2888 if (ResVT == MVT::v4f32 && (InVT == MVT::v4i16 || InVT == MVT::v4i8))
2889 ExtVT = MVT::v4i32;
2890 else if (ResVT == MVT::v2f64 && (InVT == MVT::v2i16 || InVT == MVT::v2i8))
2891 ExtVT = MVT::v2i32;
2892 else
2893 return SDValue();
2894
2895 unsigned Op =
2897 SDValue Conv = DAG.getNode(Op, SDLoc(N), ExtVT, N->getOperand(0));
2898 return DAG.getNode(N->getOpcode(), SDLoc(N), ResVT, Conv);
2899}
2900
2901static SDValue
2904 auto &DAG = DCI.DAG;
2905
2906 SDNodeFlags Flags = N->getFlags();
2907 SDValue Op0 = N->getOperand(0);
2908 EVT VT = N->getValueType(0);
2909
2910 // Optimize uitofp to sitofp when the sign bit is known to be zero.
2911 // Depending on the target (runtime) backend, this might be performance
2912 // neutral (e.g. AArch64) or a significant improvement (e.g. x86_64).
2913 if (VT.isVector() && (Flags.hasNonNeg() || DAG.SignBitIsZero(Op0))) {
2914 return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, Op0);
2915 }
2916
2917 return SDValue();
2918}
2919
2920static SDValue
2922 auto &DAG = DCI.DAG;
2923 assert(N->getOpcode() == ISD::SIGN_EXTEND ||
2924 N->getOpcode() == ISD::ZERO_EXTEND);
2925
2926 // Combine ({s,z}ext (extract_subvector src, i)) into a widening operation if
2927 // possible before the extract_subvector can be expanded.
2928 auto Extract = N->getOperand(0);
2929 if (Extract.getOpcode() != ISD::EXTRACT_SUBVECTOR)
2930 return SDValue();
2931 auto Source = Extract.getOperand(0);
2932 auto *IndexNode = dyn_cast<ConstantSDNode>(Extract.getOperand(1));
2933 if (IndexNode == nullptr)
2934 return SDValue();
2935 auto Index = IndexNode->getZExtValue();
2936
2937 // Only v8i8, v4i16, and v2i32 extracts can be widened, and only if the
2938 // extracted subvector is the low or high half of its source.
2939 EVT ResVT = N->getValueType(0);
2940 if (ResVT == MVT::v8i16) {
2941 if (Extract.getValueType() != MVT::v8i8 ||
2942 Source.getValueType() != MVT::v16i8 || (Index != 0 && Index != 8))
2943 return SDValue();
2944 } else if (ResVT == MVT::v4i32) {
2945 if (Extract.getValueType() != MVT::v4i16 ||
2946 Source.getValueType() != MVT::v8i16 || (Index != 0 && Index != 4))
2947 return SDValue();
2948 } else if (ResVT == MVT::v2i64) {
2949 if (Extract.getValueType() != MVT::v2i32 ||
2950 Source.getValueType() != MVT::v4i32 || (Index != 0 && Index != 2))
2951 return SDValue();
2952 } else {
2953 return SDValue();
2954 }
2955
2956 bool IsSext = N->getOpcode() == ISD::SIGN_EXTEND;
2957 bool IsLow = Index == 0;
2958
2959 unsigned Op = IsSext ? (IsLow ? WebAssemblyISD::EXTEND_LOW_S
2960 : WebAssemblyISD::EXTEND_HIGH_S)
2961 : (IsLow ? WebAssemblyISD::EXTEND_LOW_U
2962 : WebAssemblyISD::EXTEND_HIGH_U);
2963
2964 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
2965}
2966
2967static SDValue
2969 auto &DAG = DCI.DAG;
2970
2971 auto GetWasmConversionOp = [](unsigned Op) {
2972 switch (Op) {
2974 return WebAssemblyISD::TRUNC_SAT_ZERO_S;
2976 return WebAssemblyISD::TRUNC_SAT_ZERO_U;
2977 case ISD::FP_ROUND:
2978 return WebAssemblyISD::DEMOTE_ZERO;
2979 }
2980 llvm_unreachable("unexpected op");
2981 };
2982
2983 auto IsZeroSplat = [](SDValue SplatVal) {
2984 auto *Splat = dyn_cast<BuildVectorSDNode>(SplatVal.getNode());
2985 APInt SplatValue, SplatUndef;
2986 unsigned SplatBitSize;
2987 bool HasAnyUndefs;
2988 // Endianness doesn't matter in this context because we are looking for
2989 // an all-zero value.
2990 return Splat &&
2991 Splat->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
2992 HasAnyUndefs) &&
2993 SplatValue == 0;
2994 };
2995
2996 if (N->getOpcode() == ISD::CONCAT_VECTORS) {
2997 // Combine this:
2998 //
2999 // (concat_vectors (v2i32 (fp_to_{s,u}int_sat $x, 32)), (v2i32 (splat 0)))
3000 //
3001 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3002 //
3003 // Or this:
3004 //
3005 // (concat_vectors (v2f32 (fp_round (v2f64 $x))), (v2f32 (splat 0)))
3006 //
3007 // into (f32x4.demote_zero_f64x2 $x).
3008 EVT ResVT;
3009 EVT ExpectedConversionType;
3010 auto Conversion = N->getOperand(0);
3011 auto ConversionOp = Conversion.getOpcode();
3012 switch (ConversionOp) {
3015 ResVT = MVT::v4i32;
3016 ExpectedConversionType = MVT::v2i32;
3017 break;
3018 case ISD::FP_ROUND:
3019 ResVT = MVT::v4f32;
3020 ExpectedConversionType = MVT::v2f32;
3021 break;
3022 default:
3023 return SDValue();
3024 }
3025
3026 if (N->getValueType(0) != ResVT)
3027 return SDValue();
3028
3029 if (Conversion.getValueType() != ExpectedConversionType)
3030 return SDValue();
3031
3032 auto Source = Conversion.getOperand(0);
3033 if (Source.getValueType() != MVT::v2f64)
3034 return SDValue();
3035
3036 if (!IsZeroSplat(N->getOperand(1)) ||
3037 N->getOperand(1).getValueType() != ExpectedConversionType)
3038 return SDValue();
3039
3040 unsigned Op = GetWasmConversionOp(ConversionOp);
3041 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
3042 }
3043
3044 // Combine this:
3045 //
3046 // (fp_to_{s,u}int_sat (concat_vectors $x, (v2f64 (splat 0))), 32)
3047 //
3048 // into (i32x4.trunc_sat_f64x2_zero_{s,u} $x).
3049 //
3050 // Or this:
3051 //
3052 // (v4f32 (fp_round (concat_vectors $x, (v2f64 (splat 0)))))
3053 //
3054 // into (f32x4.demote_zero_f64x2 $x).
3055 EVT ResVT;
3056 auto ConversionOp = N->getOpcode();
3057 switch (ConversionOp) {
3060 ResVT = MVT::v4i32;
3061 break;
3062 case ISD::FP_ROUND:
3063 ResVT = MVT::v4f32;
3064 break;
3065 default:
3066 llvm_unreachable("unexpected op");
3067 }
3068
3069 if (N->getValueType(0) != ResVT)
3070 return SDValue();
3071
3072 auto Concat = N->getOperand(0);
3073 if (Concat.getValueType() != MVT::v4f64)
3074 return SDValue();
3075
3076 auto Source = Concat.getOperand(0);
3077 if (Source.getValueType() != MVT::v2f64)
3078 return SDValue();
3079
3080 if (!IsZeroSplat(Concat.getOperand(1)) ||
3081 Concat.getOperand(1).getValueType() != MVT::v2f64)
3082 return SDValue();
3083
3084 unsigned Op = GetWasmConversionOp(ConversionOp);
3085 return DAG.getNode(Op, SDLoc(N), ResVT, Source);
3086}
3087
3088// Helper to extract VectorWidth bits from Vec, starting from IdxVal.
3089static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
3090 const SDLoc &DL, unsigned VectorWidth) {
3091 EVT VT = Vec.getValueType();
3092 EVT ElVT = VT.getVectorElementType();
3093 unsigned Factor = VT.getSizeInBits() / VectorWidth;
3094 EVT ResultVT = EVT::getVectorVT(*DAG.getContext(), ElVT,
3095 VT.getVectorNumElements() / Factor);
3096
3097 // Extract the relevant VectorWidth bits. Generate an EXTRACT_SUBVECTOR
3098 unsigned ElemsPerChunk = VectorWidth / ElVT.getSizeInBits();
3099 assert(isPowerOf2_32(ElemsPerChunk) && "Elements per chunk not power of 2");
3100
3101 // This is the index of the first element of the VectorWidth-bit chunk
3102 // we want. Since ElemsPerChunk is a power of 2 just need to clear bits.
3103 IdxVal &= ~(ElemsPerChunk - 1);
3104
3105 // If the input is a buildvector just emit a smaller one.
3106 if (Vec.getOpcode() == ISD::BUILD_VECTOR)
3107 return DAG.getBuildVector(ResultVT, DL,
3108 Vec->ops().slice(IdxVal, ElemsPerChunk));
3109
3110 SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, DL);
3111 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ResultVT, Vec, VecIdx);
3112}
3113
3114// Helper to recursively truncate vector elements in half with NARROW_U. DstVT
3115// is the expected destination value type after recursion. In is the initial
3116// input. Note that the input should have enough leading zero bits to prevent
3117// NARROW_U from saturating results.
3119 SelectionDAG &DAG) {
3120 EVT SrcVT = In.getValueType();
3121
3122 // No truncation required, we might get here due to recursive calls.
3123 if (SrcVT == DstVT)
3124 return In;
3125
3126 unsigned SrcSizeInBits = SrcVT.getSizeInBits();
3127 unsigned NumElems = SrcVT.getVectorNumElements();
3128 if (!isPowerOf2_32(NumElems))
3129 return SDValue();
3130 assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
3131 assert(SrcSizeInBits > DstVT.getSizeInBits() && "Illegal truncation");
3132
3133 LLVMContext &Ctx = *DAG.getContext();
3134 EVT PackedSVT = EVT::getIntegerVT(Ctx, SrcVT.getScalarSizeInBits() / 2);
3135
3136 // Narrow to the largest type possible:
3137 // vXi64/vXi32 -> i16x8.narrow_i32x4_u and vXi16 -> i8x16.narrow_i16x8_u.
3138 EVT InVT = MVT::i16, OutVT = MVT::i8;
3139 if (SrcVT.getScalarSizeInBits() > 16) {
3140 InVT = MVT::i32;
3141 OutVT = MVT::i16;
3142 }
3143 unsigned SubSizeInBits = SrcSizeInBits / 2;
3144 InVT = EVT::getVectorVT(Ctx, InVT, SubSizeInBits / InVT.getSizeInBits());
3145 OutVT = EVT::getVectorVT(Ctx, OutVT, SubSizeInBits / OutVT.getSizeInBits());
3146
3147 // Split lower/upper subvectors.
3148 SDValue Lo = extractSubVector(In, 0, DAG, DL, SubSizeInBits);
3149 SDValue Hi = extractSubVector(In, NumElems / 2, DAG, DL, SubSizeInBits);
3150
3151 // 256bit -> 128bit truncate - Narrow lower/upper 128-bit subvectors.
3152 if (SrcVT.is256BitVector() && DstVT.is128BitVector()) {
3153 Lo = DAG.getBitcast(InVT, Lo);
3154 Hi = DAG.getBitcast(InVT, Hi);
3155 SDValue Res = DAG.getNode(WebAssemblyISD::NARROW_U, DL, OutVT, Lo, Hi);
3156 return DAG.getBitcast(DstVT, Res);
3157 }
3158
3159 // Recursively narrow lower/upper subvectors, concat result and narrow again.
3160 EVT PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems / 2);
3161 Lo = truncateVectorWithNARROW(PackedVT, Lo, DL, DAG);
3162 Hi = truncateVectorWithNARROW(PackedVT, Hi, DL, DAG);
3163
3164 PackedVT = EVT::getVectorVT(Ctx, PackedSVT, NumElems);
3165 SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
3166 return truncateVectorWithNARROW(DstVT, Res, DL, DAG);
3167}
3168
3171 auto &DAG = DCI.DAG;
3172
3173 SDValue In = N->getOperand(0);
3174 EVT InVT = In.getValueType();
3175 if (!InVT.isSimple())
3176 return SDValue();
3177
3178 EVT OutVT = N->getValueType(0);
3179 if (!OutVT.isVector())
3180 return SDValue();
3181
3182 EVT OutSVT = OutVT.getVectorElementType();
3183 EVT InSVT = InVT.getVectorElementType();
3184 // Currently only cover truncate to v16i8 or v8i16.
3185 if (!((InSVT == MVT::i16 || InSVT == MVT::i32 || InSVT == MVT::i64) &&
3186 (OutSVT == MVT::i8 || OutSVT == MVT::i16) && OutVT.is128BitVector()))
3187 return SDValue();
3188
3189 SDLoc DL(N);
3191 OutVT.getScalarSizeInBits());
3192 In = DAG.getNode(ISD::AND, DL, InVT, In, DAG.getConstant(Mask, DL, InVT));
3193 return truncateVectorWithNARROW(OutVT, In, DL, DAG);
3194}
3195
3198 using namespace llvm::SDPatternMatch;
3199 auto &DAG = DCI.DAG;
3200 SDLoc DL(N);
3201 SDValue Src = N->getOperand(0);
3202 EVT VT = N->getValueType(0);
3203 EVT SrcVT = Src.getValueType();
3204
3205 if (!(DCI.isBeforeLegalize() && VT.isScalarInteger() &&
3206 SrcVT.isFixedLengthVector() && SrcVT.getScalarType() == MVT::i1))
3207 return SDValue();
3208
3209 unsigned NumElts = SrcVT.getVectorNumElements();
3210 EVT Width = MVT::getIntegerVT(128 / NumElts);
3211
3212 // bitcast <N x i1> to iN, where N = 2, 4, 8, 16 (legal)
3213 // ==> bitmask
3214 if (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16) {
3215 return DAG.getZExtOrTrunc(
3216 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3217 {DAG.getConstant(Intrinsic::wasm_bitmask, DL, MVT::i32),
3218 DAG.getSExtOrTrunc(N->getOperand(0), DL,
3219 SrcVT.changeVectorElementType(Width))}),
3220 DL, VT);
3221 }
3222
3223 // bitcast <N x i1>(setcc ...) to concat iN, where N = 32 and 64 (illegal)
3224 if (NumElts == 32 || NumElts == 64) {
3225 // Strategy: We will setcc them seperately in v16i8 -> v16i1
3226 // Bitcast them to i16, extend them to either i32 or i64.
3227 // Add them together, shifting left 1 by 1.
3228 SDValue Concat, SetCCVector;
3229 ISD::CondCode SetCond;
3230
3231 if (!sd_match(N, m_BitCast(m_c_SetCC(m_Value(Concat), m_Value(SetCCVector),
3232 m_CondCode(SetCond)))))
3233 return SDValue();
3234 if (Concat.getOpcode() != ISD::CONCAT_VECTORS)
3235 return SDValue();
3236
3237 uint64_t ElementWidth =
3239
3240 SmallVector<SDValue> VectorsToShuffle;
3241 for (size_t I = 0; I < Concat->ops().size(); I++) {
3242 VectorsToShuffle.push_back(DAG.getBitcast(
3243 MVT::i16,
3244 DAG.getSetCC(DL, MVT::v16i1, Concat->ops()[I],
3245 extractSubVector(SetCCVector, I * (128 / ElementWidth),
3246 DAG, DL, 128),
3247 SetCond)));
3248 }
3249
3250 MVT ReturnType = VectorsToShuffle.size() == 2 ? MVT::i32 : MVT::i64;
3251 SDValue ReturningInteger = DAG.getConstant(0, DL, ReturnType);
3252
3253 for (SDValue V : VectorsToShuffle) {
3254 ReturningInteger = DAG.getNode(
3255 ISD::SHL, DL, ReturnType,
3256 {DAG.getShiftAmountConstant(16, ReturnType, DL), ReturningInteger});
3257
3258 SDValue ExtendedV = DAG.getZExtOrTrunc(V, DL, ReturnType);
3259 ReturningInteger =
3260 DAG.getNode(ISD::ADD, DL, ReturnType, {ReturningInteger, ExtendedV});
3261 }
3262
3263 return ReturningInteger;
3264 }
3265
3266 return SDValue();
3267}
3268
3270 // any_true (setcc <X>, 0, eq) => (not (all_true X))
3271 // all_true (setcc <X>, 0, eq) => (not (any_true X))
3272 // any_true (setcc <X>, 0, ne) => (any_true X)
3273 // all_true (setcc <X>, 0, ne) => (all_true X)
3274 assert(N->getOpcode() == ISD::INTRINSIC_WO_CHAIN);
3275 using namespace llvm::SDPatternMatch;
3276
3277 SDValue LHS;
3278 if (N->getNumOperands() < 2 ||
3279 !sd_match(N->getOperand(1),
3281 return SDValue();
3282 EVT LT = LHS.getValueType();
3283 if (LT.getScalarSizeInBits() > 128 / LT.getVectorNumElements())
3284 return SDValue();
3285
3286 auto CombineSetCC = [&N, &DAG](Intrinsic::WASMIntrinsics InPre,
3287 ISD::CondCode SetType,
3288 Intrinsic::WASMIntrinsics InPost) {
3289 if (N->getConstantOperandVal(0) != InPre)
3290 return SDValue();
3291
3292 SDValue LHS;
3293 if (!sd_match(N->getOperand(1), m_c_SetCC(m_Value(LHS), m_Zero(),
3294 m_SpecificCondCode(SetType))))
3295 return SDValue();
3296
3297 SDLoc DL(N);
3298 SDValue Ret = DAG.getZExtOrTrunc(
3299 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3300 {DAG.getConstant(InPost, DL, MVT::i32), LHS}),
3301 DL, MVT::i1);
3302 if (SetType == ISD::SETEQ)
3303 Ret = DAG.getNOT(DL, Ret, MVT::i1);
3304 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3305 };
3306
3307 if (SDValue AnyTrueEQ = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETEQ,
3308 Intrinsic::wasm_alltrue))
3309 return AnyTrueEQ;
3310 if (SDValue AllTrueEQ = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETEQ,
3311 Intrinsic::wasm_anytrue))
3312 return AllTrueEQ;
3313 if (SDValue AnyTrueNE = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETNE,
3314 Intrinsic::wasm_anytrue))
3315 return AnyTrueNE;
3316 if (SDValue AllTrueNE = CombineSetCC(Intrinsic::wasm_alltrue, ISD::SETNE,
3317 Intrinsic::wasm_alltrue))
3318 return AllTrueNE;
3319
3320 return SDValue();
3321}
3322
3323template <int MatchRHS, ISD::CondCode MatchCond, bool RequiresNegate,
3324 Intrinsic::ID Intrin>
3326 SDValue LHS = N->getOperand(0);
3327 SDValue RHS = N->getOperand(1);
3328 SDValue Cond = N->getOperand(2);
3329 if (MatchCond != cast<CondCodeSDNode>(Cond)->get())
3330 return SDValue();
3331
3332 if (MatchRHS != cast<ConstantSDNode>(RHS)->getSExtValue())
3333 return SDValue();
3334
3335 SDLoc DL(N);
3336 SDValue Ret = DAG.getZExtOrTrunc(
3337 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3338 {DAG.getConstant(Intrin, DL, MVT::i32),
3339 DAG.getSExtOrTrunc(LHS->getOperand(0), DL, VecVT)}),
3340 DL, MVT::i1);
3341 if (RequiresNegate)
3342 Ret = DAG.getNOT(DL, Ret, MVT::i1);
3343 return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
3344}
3345
3346/// Try to convert a i128 comparison to a v16i8 comparison before type
3347/// legalization splits it up into chunks
3348static SDValue
3350 const WebAssemblySubtarget *Subtarget) {
3351
3352 SDLoc DL(N);
3353 SDValue X = N->getOperand(0);
3354 SDValue Y = N->getOperand(1);
3355 EVT VT = N->getValueType(0);
3356 EVT OpVT = X.getValueType();
3357
3358 SelectionDAG &DAG = DCI.DAG;
3360 Attribute::NoImplicitFloat))
3361 return SDValue();
3362
3363 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
3364 // We're looking for an oversized integer equality comparison with SIMD
3365 if (!OpVT.isScalarInteger() || !OpVT.isByteSized() || OpVT != MVT::i128 ||
3366 !Subtarget->hasSIMD128() || !isIntEqualitySetCC(CC))
3367 return SDValue();
3368
3369 // Don't perform this combine if constructing the vector will be expensive.
3370 auto IsVectorBitCastCheap = [](SDValue X) {
3372 return isa<ConstantSDNode>(X) || X.getOpcode() == ISD::LOAD;
3373 };
3374
3375 if (!IsVectorBitCastCheap(X) || !IsVectorBitCastCheap(Y))
3376 return SDValue();
3377
3378 SDValue VecX = DAG.getBitcast(MVT::v16i8, X);
3379 SDValue VecY = DAG.getBitcast(MVT::v16i8, Y);
3380 SDValue Cmp = DAG.getSetCC(DL, MVT::v16i8, VecX, VecY, CC);
3381
3382 SDValue Intr =
3383 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
3384 {DAG.getConstant(CC == ISD::SETEQ ? Intrinsic::wasm_alltrue
3385 : Intrinsic::wasm_anytrue,
3386 DL, MVT::i32),
3387 Cmp});
3388
3389 return DAG.getSetCC(DL, VT, Intr, DAG.getConstant(0, DL, MVT::i32),
3390 ISD::SETNE);
3391}
3392
3395 const WebAssemblySubtarget *Subtarget) {
3396 if (!DCI.isBeforeLegalize())
3397 return SDValue();
3398
3399 EVT VT = N->getValueType(0);
3400 if (!VT.isScalarInteger())
3401 return SDValue();
3402
3403 if (SDValue V = combineVectorSizedSetCCEquality(N, DCI, Subtarget))
3404 return V;
3405
3406 SDValue LHS = N->getOperand(0);
3407 if (LHS->getOpcode() != ISD::BITCAST)
3408 return SDValue();
3409
3410 EVT FromVT = LHS->getOperand(0).getValueType();
3411 if (!FromVT.isFixedLengthVector() || FromVT.getVectorElementType() != MVT::i1)
3412 return SDValue();
3413
3414 unsigned NumElts = FromVT.getVectorNumElements();
3415 if (NumElts != 2 && NumElts != 4 && NumElts != 8 && NumElts != 16)
3416 return SDValue();
3417
3418 if (!cast<ConstantSDNode>(N->getOperand(1)))
3419 return SDValue();
3420
3421 EVT VecVT = FromVT.changeVectorElementType(MVT::getIntegerVT(128 / NumElts));
3422 auto &DAG = DCI.DAG;
3423 // setcc (iN (bitcast (vNi1 X))), 0, ne
3424 // ==> any_true (vNi1 X)
3426 N, VecVT, DAG)) {
3427 return Match;
3428 }
3429 // setcc (iN (bitcast (vNi1 X))), 0, eq
3430 // ==> xor (any_true (vNi1 X)), -1
3432 N, VecVT, DAG)) {
3433 return Match;
3434 }
3435 // setcc (iN (bitcast (vNi1 X))), -1, eq
3436 // ==> all_true (vNi1 X)
3438 N, VecVT, DAG)) {
3439 return Match;
3440 }
3441 // setcc (iN (bitcast (vNi1 X))), -1, ne
3442 // ==> xor (all_true (vNi1 X)), -1
3444 N, VecVT, DAG)) {
3445 return Match;
3446 }
3447 return SDValue();
3448}
3449
3451 EVT VT = N->getValueType(0);
3452 if (VT != MVT::v8i32 && VT != MVT::v16i32)
3453 return SDValue();
3454
3455 // Mul with extending inputs.
3456 SDValue LHS = N->getOperand(0);
3457 SDValue RHS = N->getOperand(1);
3458 if (LHS.getOpcode() != RHS.getOpcode())
3459 return SDValue();
3460
3461 if (LHS.getOpcode() != ISD::SIGN_EXTEND &&
3462 LHS.getOpcode() != ISD::ZERO_EXTEND)
3463 return SDValue();
3464
3465 if (LHS->getOperand(0).getValueType() != RHS->getOperand(0).getValueType())
3466 return SDValue();
3467
3468 EVT FromVT = LHS->getOperand(0).getValueType();
3469 EVT EltTy = FromVT.getVectorElementType();
3470 if (EltTy != MVT::i8)
3471 return SDValue();
3472
3473 // For an input DAG that looks like this
3474 // %a = input_type
3475 // %b = input_type
3476 // %lhs = extend %a to output_type
3477 // %rhs = extend %b to output_type
3478 // %mul = mul %lhs, %rhs
3479
3480 // input_type | output_type | instructions
3481 // v16i8 | v16i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3482 // | | %high = i16x8.extmul_high_i8x16_, %a, %b
3483 // | | %low_low = i32x4.ext_low_i16x8_ %low
3484 // | | %low_high = i32x4.ext_high_i16x8_ %low
3485 // | | %high_low = i32x4.ext_low_i16x8_ %high
3486 // | | %high_high = i32x4.ext_high_i16x8_ %high
3487 // | | %res = concat_vector(...)
3488 // v8i8 | v8i32 | %low = i16x8.extmul_low_i8x16_ %a, %b
3489 // | | %low_low = i32x4.ext_low_i16x8_ %low
3490 // | | %low_high = i32x4.ext_high_i16x8_ %low
3491 // | | %res = concat_vector(%low_low, %low_high)
3492
3493 SDLoc DL(N);
3494 unsigned NumElts = VT.getVectorNumElements();
3495 SDValue ExtendInLHS = LHS->getOperand(0);
3496 SDValue ExtendInRHS = RHS->getOperand(0);
3497 bool IsSigned = LHS->getOpcode() == ISD::SIGN_EXTEND;
3498 unsigned ExtendLowOpc =
3499 IsSigned ? WebAssemblyISD::EXTEND_LOW_S : WebAssemblyISD::EXTEND_LOW_U;
3500 unsigned ExtendHighOpc =
3501 IsSigned ? WebAssemblyISD::EXTEND_HIGH_S : WebAssemblyISD::EXTEND_HIGH_U;
3502
3503 auto GetExtendLow = [&DAG, &DL, &ExtendLowOpc](EVT VT, SDValue Op) {
3504 return DAG.getNode(ExtendLowOpc, DL, VT, Op);
3505 };
3506 auto GetExtendHigh = [&DAG, &DL, &ExtendHighOpc](EVT VT, SDValue Op) {
3507 return DAG.getNode(ExtendHighOpc, DL, VT, Op);
3508 };
3509
3510 if (NumElts == 16) {
3511 SDValue LowLHS = GetExtendLow(MVT::v8i16, ExtendInLHS);
3512 SDValue LowRHS = GetExtendLow(MVT::v8i16, ExtendInRHS);
3513 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3514 SDValue HighLHS = GetExtendHigh(MVT::v8i16, ExtendInLHS);
3515 SDValue HighRHS = GetExtendHigh(MVT::v8i16, ExtendInRHS);
3516 SDValue MulHigh = DAG.getNode(ISD::MUL, DL, MVT::v8i16, HighLHS, HighRHS);
3517 SDValue SubVectors[] = {
3518 GetExtendLow(MVT::v4i32, MulLow),
3519 GetExtendHigh(MVT::v4i32, MulLow),
3520 GetExtendLow(MVT::v4i32, MulHigh),
3521 GetExtendHigh(MVT::v4i32, MulHigh),
3522 };
3523 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, SubVectors);
3524 } else {
3525 assert(NumElts == 8);
3526 SDValue LowLHS = DAG.getNode(LHS->getOpcode(), DL, MVT::v8i16, ExtendInLHS);
3527 SDValue LowRHS = DAG.getNode(RHS->getOpcode(), DL, MVT::v8i16, ExtendInRHS);
3528 SDValue MulLow = DAG.getNode(ISD::MUL, DL, MVT::v8i16, LowLHS, LowRHS);
3529 SDValue Lo = GetExtendLow(MVT::v4i32, MulLow);
3530 SDValue Hi = GetExtendHigh(MVT::v4i32, MulLow);
3531 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Lo, Hi);
3532 }
3533 return SDValue();
3534}
3535
3538 assert(N->getOpcode() == ISD::MUL);
3539 EVT VT = N->getValueType(0);
3540 if (!VT.isVector())
3541 return SDValue();
3542
3543 if (auto Res = TryWideExtMulCombine(N, DCI.DAG))
3544 return Res;
3545
3546 // We don't natively support v16i8 or v8i8 mul, but we do support v8i16. So,
3547 // extend them to v8i16. Only do this before legalization in case a narrow
3548 // vector is widened and may be simplified later.
3549 if (!DCI.isBeforeLegalize() || (VT != MVT::v8i8 && VT != MVT::v16i8))
3550 return SDValue();
3551
3552 SDLoc DL(N);
3553 SelectionDAG &DAG = DCI.DAG;
3554 SDValue LHS = N->getOperand(0);
3555 SDValue RHS = N->getOperand(1);
3556 EVT MulVT = MVT::v8i16;
3557
3558 if (VT == MVT::v8i8) {
3559 SDValue PromotedLHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, LHS,
3560 DAG.getUNDEF(MVT::v8i8));
3561 SDValue PromotedRHS = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v16i8, RHS,
3562 DAG.getUNDEF(MVT::v8i8));
3563 SDValue LowLHS =
3564 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedLHS);
3565 SDValue LowRHS =
3566 DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, PromotedRHS);
3567 SDValue MulLow = DAG.getBitcast(
3568 MVT::v16i8, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3569 // Take the low byte of each lane.
3570 SDValue Shuffle = DAG.getVectorShuffle(
3571 MVT::v16i8, DL, MulLow, DAG.getUNDEF(MVT::v16i8),
3572 {0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1});
3573 return extractSubVector(Shuffle, 0, DAG, DL, 64);
3574 } else {
3575 assert(VT == MVT::v16i8 && "Expected v16i8");
3576 SDValue LowLHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, LHS);
3577 SDValue LowRHS = DAG.getNode(WebAssemblyISD::EXTEND_LOW_U, DL, MulVT, RHS);
3578 SDValue HighLHS =
3579 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, LHS);
3580 SDValue HighRHS =
3581 DAG.getNode(WebAssemblyISD::EXTEND_HIGH_U, DL, MulVT, RHS);
3582
3583 SDValue MulLow =
3584 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, LowLHS, LowRHS));
3585 SDValue MulHigh =
3586 DAG.getBitcast(VT, DAG.getNode(ISD::MUL, DL, MulVT, HighLHS, HighRHS));
3587
3588 // Take the low byte of each lane.
3589 return DAG.getVectorShuffle(
3590 VT, DL, MulLow, MulHigh,
3591 {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30});
3592 }
3593}
3594
3595SDValue
3596WebAssemblyTargetLowering::PerformDAGCombine(SDNode *N,
3597 DAGCombinerInfo &DCI) const {
3598 switch (N->getOpcode()) {
3599 default:
3600 return SDValue();
3601 case ISD::BITCAST:
3602 return performBitcastCombine(N, DCI);
3603 case ISD::SETCC:
3604 return performSETCCCombine(N, DCI, Subtarget);
3606 return performVECTOR_SHUFFLECombine(N, DCI);
3607 case ISD::SIGN_EXTEND:
3608 case ISD::ZERO_EXTEND:
3609 return performVectorExtendCombine(N, DCI);
3610 case ISD::UINT_TO_FP:
3611 if (auto ExtCombine = performVectorExtendToFPCombine(N, DCI))
3612 return ExtCombine;
3613 return performVectorNonNegToFPCombine(N, DCI);
3614 case ISD::SINT_TO_FP:
3615 return performVectorExtendToFPCombine(N, DCI);
3618 case ISD::FP_ROUND:
3620 return performVectorTruncZeroCombine(N, DCI);
3621 case ISD::TRUNCATE:
3622 return performTruncateCombine(N, DCI);
3624 return performAnyAllCombine(N, DCI.DAG);
3625 case ISD::MUL:
3626 return performMulCombine(N, DCI);
3627 }
3628}
unsigned const MachineRegisterInfo * MRI
static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const AArch64Subtarget *Subtarget)
static SDValue performTruncateCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
return SDValue()
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
Function Alias Analysis Results
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
Definition CSEInfo.cpp:27
Hexagon Common GEP
const HexagonInstrInfo * TII
#define _
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
MachineInstr unsigned OpIdx
static SDValue performVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget, const RISCVTargetLowering &TLI)
static SDValue combineVectorSizedSetCCEquality(EVT VT, SDValue X, SDValue Y, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
Try to map an integer comparison with size > XLEN to vector instructions before type legalization spl...
const SmallVectorImpl< MachineOperand > & Cond
Contains matchers for matching SelectionDAG nodes and values.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
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 SDValue TryWideExtMulCombine(SDNode *N, SelectionDAG &DAG)
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 performVectorNonNegToFPCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue unrollVectorShift(SDValue Op, SelectionDAG &DAG)
static SDValue performAnyAllCombine(SDNode *N, SelectionDAG &DAG)
static MachineBasicBlock * LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, const WebAssemblySubtarget *Subtarget, const TargetInstrInfo &TII)
static SDValue TryMatchTrue(SDNode *N, EVT VecVT, SelectionDAG &DAG)
static SDValue GetExtendHigh(SDValue Op, unsigned UserOpc, EVT VT, SelectionDAG &DAG)
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
void setBitsFrom(unsigned loBit)
Set the top bits starting from loBit.
Definition APInt.h:1385
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,...
@ Add
*p = old + v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
BinOp getOperation() const
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
This class represents a function call, abstracting a target machine's calling convention.
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:124
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:209
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:359
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:727
LLVM_ABI unsigned getAddressSpace() const
const GlobalValue * getGlobal() const
ThreadLocalMode getThreadLocalMode() const
Type * getValueType() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
Describe properties that are true of each instruction in the target description file.
void setNoStrip() const
Machine Value Type.
bool is128BitVector() const
Return true if this is a 128-bit vector type.
@ INVALID_SIMPLE_VALUE_TYPE
static auto integer_fixedlen_vector_valuetypes()
SimpleValueType SimpleTy
MVT changeVectorElementType(MVT EltVT) const
Return a VT for a vector type whose attributes match ourselves with the exception of the element type...
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
static auto integer_valuetypes()
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool isFixedLengthVector() const
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
unsigned getFunctionNumber() const
getFunctionNumber - Return a unique ID for the current function.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
const char * createExternalSymbolName(StringRef Name)
Allocate a string and populate it with the given external symbol name.
MCContext & getContext() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
const MachineInstrBuilder & 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.
mop_range defs()
Returns all explicit operands that are register definitions.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
mop_range uses()
Returns all operands which may be register uses.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
const std::vector< MachineJumpTableEntry > & getJumpTables() const
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void addLiveIn(MCRegister Reg, Register vreg=Register())
addLiveIn - Add the specified register as a live-in.
unsigned getAddressSpace() const
Return the address space for the associated pointer.
MachineMemOperand * getMemOperand() const
Return 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.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getSplatValue(SDValue V, bool LegalTypes=false)
If V is a splat vector, return its scalar source operand by extracting that element from the source v...
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI void ExtractVectorElements(SDValue Op, SmallVectorImpl< SDValue > &Args, unsigned Start=0, unsigned Count=0, EVT EltVT=EVT())
Append the extracted elements from Start to Count out of the vector Op in Args.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false)
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
LLVM_ABI SDValue UnrollVectorOp(SDNode *N, unsigned ResNE=0)
Utility function used by legalize and lowering to "unroll" a vector operation by splitting out the sc...
LLVM_ABI SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget=false)
Create a ConstantFPSDNode wrapping a constant value.
LLVM_ABI SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
LLVM_ABI 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)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
const DataLayout & getDataLayout() const
SDValue getTargetFrameIndex(int FI, EVT VT)
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
LLVM_ABI 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.
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
LLVM_ABI SDValue getBasicBlock(MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
LLVM_ABI SDValue getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either any-extending or truncat...
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
MachineFunction & getMachineFunction() const
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
LLVM_ABI SDValue getMCSymbol(MCSymbol *Sym, EVT VT)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
const SDValue & getBasePtr() const
const SDValue & getOffset() const
const SDValue & getValue() const
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:146
TargetInstrInfo - Interface to description of machine instruction set.
Provides information about what library functions are available for the current target.
void setBooleanVectorContents(BooleanContent Ty)
Specify how the target extends the result of a vector boolean value from a vector of i1 to a wider ty...
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
const TargetMachine & getTargetMachine() const
unsigned MaxLoadsPerMemcmp
Specify maximum number of load instructions per memcmp call.
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
virtual TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const
Return the preferred vector type legalization action.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setMinimumJumpTableEntries(unsigned Val)
Indicate the minimum number of blocks to generate jump tables.
void setPartialReduceMLAAction(unsigned Opc, MVT AccVT, MVT InputVT, LegalizeAction Action)
Indicate how a PARTIAL_REDUCE_U/SMLA node with Acc type AccVT and Input type InputVT should be treate...
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
unsigned MaxLoadsPerMemcmpOptSize
Likewise for functions with the OptSize attribute.
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
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...
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.
TargetLowering(const TargetLowering &)=delete
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.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isFunctionTy() const
True if this is an instance of FunctionType.
Definition Type.h:258
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:285
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM_ABI const Value * stripPointerCastsAndAliases() const
Strip off pointer casts, all-zero GEPs, address space casts, and aliases.
Definition Value.cpp:705
static std::optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)
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:123
#define INT64_MIN
Definition DataTypes.h:74
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Swift
Calling convention for Swift.
Definition CallingConv.h:69
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ CXX_FAST_TLS
Used for access functions.
Definition CallingConv.h:72
@ WASM_EmscriptenInvoke
For emscripten __invoke_* functions.
@ Cold
Attempts to make code in the caller as efficient as possible under the assumption that the call is no...
Definition CallingConv.h:47
@ PreserveAll
Used for runtime calls that preserves (almost) all registers.
Definition CallingConv.h:66
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ 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:807
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:270
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:771
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:289
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:259
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:511
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:215
@ GlobalAddress
Definition ISDOpcodes.h:88
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:868
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:577
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:744
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition ISDOpcodes.h:898
@ SDIVREM
SDIVREM/UDIVREM - Divide two integers and produce both a quotient and remainder result.
Definition ISDOpcodes.h:275
@ FMULADD
FMULADD - Performs a * b + c, with, or without, intermediate rounding.
Definition ISDOpcodes.h:521
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:249
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:89
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:832
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:662
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:369
@ EXTRACT_ELEMENT
EXTRACT_ELEMENT - This is used to get the lower or upper (determined by a Constant,...
Definition ISDOpcodes.h:242
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition ISDOpcodes.h:669
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:701
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:762
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:642
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:607
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:569
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:219
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:838
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition ISDOpcodes.h:799
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:876
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:724
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:110
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:914
@ TargetConstant
TargetConstant* - Like Constant*, but the DAG does not do any folding, simplification,...
Definition ISDOpcodes.h:174
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:736
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:200
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:299
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:558
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:53
@ ExternalSymbol
Definition ISDOpcodes.h:93
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:947
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:909
@ 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:933
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:844
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition ISDOpcodes.h:821
@ FCOPYSIGN
FCOPYSIGN(X, Y) - Return the value of X with the sign of Y.
Definition ISDOpcodes.h:527
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:360
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:208
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:549
LLVM_ABI bool isConstantSplatVector(const SDNode *N, APInt &SplatValue)
Node predicates.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
OperandFlags
These are flags set on operands, but should be considered private, all access should go through the M...
Definition MCInstrDesc.h:51
CastOperator_match< OpTy, Instruction::BitCast > m_BitCast(const OpTy &Op)
Matches BitCast.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P)
CondCode_match m_SpecificCondCode(ISD::CondCode CC)
Match a conditional code SDNode with a specific ISD::CondCode.
CondCode_match m_CondCode()
Match any conditional code SDNode.
TernaryOpc_match< T0_P, T1_P, T2_P, true, false > m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
bool 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)
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition MathExtras.h:355
@ Offset
Definition DWP.cpp:477
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc, const Function &ContextFunc, const TargetMachine &TM, SmallVectorImpl< MVT > &Params, SmallVectorImpl< MVT > &Results)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1655
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:644
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:288
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:548
@ Add
Sum of integers.
DWARFExpression::Operation Op
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Definition STLExtras.h:2030
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:560
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:1758
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:2120
void computeLegalValueVTs(const WebAssemblyTargetLowering &TLI, LLVMContext &Ctx, const DataLayout &DL, Type *Ty, SmallVectorImpl< MVT > &ValueVTs)
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:384
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:869
#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:373
bool isByteSized() const
Return true if the bit size is a multiple of 8.
Definition ValueTypes.h:243
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:385
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:316
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:381
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:323
bool bitsGE(EVT VT) const
Return true if this has no less bits than VT.
Definition ValueTypes.h:292
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:212
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:328
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:157
EVT changeVectorElementType(EVT EltVT) const
Return a VT for a vector type whose attributes match ourselves with the exception of the element type...
Definition ValueTypes.h:102
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:336
Align getNonZeroOrigAlign() const
unsigned getByValSize() const
bool isInConsecutiveRegsLast() const
Align getNonZeroByValAlign() const
unsigned getBitWidth() const
Get the bit width of this value.
Definition KnownBits.h:44
Matching combinators.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
These are IR-level optimization flags that may be propagated to SDNodes.
This structure is used to pass arguments to makeLibCall function.