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