LLVM 24.0.0git
LoongArchISelLowering.cpp
Go to the documentation of this file.
1//=- LoongArchISelLowering.cpp - LoongArch 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// This file defines the interfaces that LoongArch uses to lower LLVM code into
10// a selection DAG.
11//
12//===----------------------------------------------------------------------===//
13
15#include "LoongArch.h"
19#include "LoongArchSubtarget.h"
23#include "llvm/ADT/SmallSet.h"
24#include "llvm/ADT/Statistic.h"
30#include "llvm/IR/IRBuilder.h"
32#include "llvm/IR/IntrinsicsLoongArch.h"
34#include "llvm/Support/Debug.h"
39
40using namespace llvm;
41
42#define DEBUG_TYPE "loongarch-isel-lowering"
43
44STATISTIC(NumTailCalls, "Number of tail calls");
45
54
56 "loongarch-materialize-float-imm", cl::Hidden,
57 cl::desc("Maximum number of instructions used (including code sequence "
58 "to generate the value and moving the value to FPR) when "
59 "materializing floating-point immediates (default = 3)"),
61 cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"),
63 "Materialize FP immediate within 2 instructions"),
65 "Materialize FP immediate within 3 instructions"),
67 "Materialize FP immediate within 4 instructions"),
69 "Materialize FP immediate within 5 instructions"),
71 "Materialize FP immediate within 6 instructions "
72 "(behaves same as 5 on loongarch64)")));
73
74static cl::opt<bool> ZeroDivCheck("loongarch-check-zero-division", cl::Hidden,
75 cl::desc("Trap on integer division by zero."),
76 cl::init(false));
77
79 const LoongArchSubtarget &STI)
80 : TargetLowering(TM, STI), Subtarget(STI) {
81
82 MVT GRLenVT = Subtarget.getGRLenVT();
83
84 // Set up the register classes.
85
86 addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
87 if (Subtarget.hasBasicF())
88 addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
89 if (Subtarget.hasBasicD())
90 addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
91
92 static const MVT::SimpleValueType LSXVTs[] = {
93 MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64};
94 static const MVT::SimpleValueType LASXVTs[] = {
95 MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v8f32, MVT::v4f64};
96
97 if (Subtarget.hasExtLSX())
98 for (MVT VT : LSXVTs)
99 addRegisterClass(VT, &LoongArch::LSX128RegClass);
100
101 if (Subtarget.hasExtLASX())
102 for (MVT VT : LASXVTs)
103 addRegisterClass(VT, &LoongArch::LASX256RegClass);
104
105 // Set operations for LA32 and LA64.
106
108 MVT::i1, Promote);
109
114 if (Subtarget.hasBasicF())
118
121 GRLenVT, Custom);
122
124
129
131 setOperationAction(ISD::TRAP, MVT::Other, Legal);
132
136
138
139 // BITREV/REVB requires the 32S feature.
140 if (STI.has32S()) {
141 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
142 // we get to know which of sll and revb.2h is faster.
145
146 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
147 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
148 // and i32 could still be byte-swapped relatively cheaply.
150 } else {
158 }
159
166
169
170 // Set operations for LA64 only.
171
172 if (Subtarget.is64Bit()) {
190
194 Custom);
196 }
197
198 // Set operations for LA32 only.
199
200 if (!Subtarget.is64Bit()) {
206 if (Subtarget.hasBasicD())
208 }
209
211
212 static const ISD::CondCode FPCCToExpand[] = {
215
216 // Set operations for 'F' feature.
217
218 if (Subtarget.hasBasicF()) {
219 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
220 setTruncStoreAction(MVT::f32, MVT::f16, Expand);
221 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::bf16, Expand);
222 setTruncStoreAction(MVT::f32, MVT::bf16, Expand);
223 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
224
243 Subtarget.isSoftFPABI() ? LibCall : Custom);
245 Subtarget.isSoftFPABI() ? LibCall : Custom);
248 Subtarget.isSoftFPABI() ? LibCall : Custom);
251
252 if (Subtarget.is64Bit())
254
255 if (!Subtarget.hasBasicD()) {
257 if (Subtarget.is64Bit()) {
260 }
261 }
262 }
263
264 // Set operations for 'D' feature.
265
266 if (Subtarget.hasBasicD()) {
267 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
268 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
269 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::bf16, Expand);
270 setTruncStoreAction(MVT::f64, MVT::bf16, Expand);
271 setTruncStoreAction(MVT::f64, MVT::f16, Expand);
272 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
273 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
274
294 Subtarget.isSoftFPABI() ? LibCall : Custom);
297 Subtarget.isSoftFPABI() ? LibCall : Custom);
298
299 if (Subtarget.is64Bit())
301 }
302
303 // Set operations for 'LSX' feature.
304
305 if (Subtarget.hasExtLSX()) {
307 // Expand all truncating stores and extending loads.
308 for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
309 setTruncStoreAction(VT, InnerVT, Expand);
312 setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
313 }
314 // By default everything must be expanded. Then we will selectively turn
315 // on ones that can be effectively codegen'd.
316 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
318 }
319
320 for (MVT VT : LSXVTs) {
324
328
333 }
334 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
337 Legal);
339 VT, Legal);
346 Expand);
361 }
362 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
364 for (MVT VT : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
366 for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
370 }
372 for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
380 VT, Expand);
388 }
390 setOperationAction(ISD::FCEIL, {MVT::f32, MVT::f64}, Legal);
391 setOperationAction(ISD::FFLOOR, {MVT::f32, MVT::f64}, Legal);
392 setOperationAction(ISD::FTRUNC, {MVT::f32, MVT::f64}, Legal);
393 setOperationAction(ISD::FROUNDEVEN, {MVT::f32, MVT::f64}, Legal);
394
395 for (MVT VT :
396 {MVT::v16i8, MVT::v8i8, MVT::v4i8, MVT::v2i8, MVT::v8i16, MVT::v4i16,
397 MVT::v2i16, MVT::v4i32, MVT::v2i32, MVT::v2i64}) {
407 }
410 // We want to legalize this to an f64 load rather than an i64 load.
411 setOperationAction(ISD::LOAD, MVT::v2f32, Custom);
412 for (MVT VT : {MVT::v2i64, MVT::v4i32, MVT::v8i16})
414 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v16i32, MVT::v8i64,
415 MVT::v16i64})
417 }
418
419 // Set operations for 'LASX' feature.
420
421 if (Subtarget.hasExtLASX()) {
422 for (MVT VT : LASXVTs) {
426
432
436 }
437 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
440 Legal);
442 VT, Legal);
449 Expand);
465 }
466 for (MVT VT : {MVT::v32i8, MVT::v16i16, MVT::v8i32})
468 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64})
470 for (MVT VT : {MVT::v8i32, MVT::v4i64})
472 for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
476 }
477 for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
485 VT, Expand);
493 }
496 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
500 }
501 for (MVT VT :
502 {MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
505 }
506 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
508 }
509
510 // Set DAG combine for LA32 and LA64.
511 if (Subtarget.hasBasicF()) {
513 }
514
519
520 // On targets with the 32S feature, `select` is expanded into
521 // maskeqz + masknez + or (3 instructions), which is more expensive than
522 // on most other architectures where a single cmov-like instruction
523 // suffices. Enable a combine that can turn
524 // select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
525 // select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
526 // for binop in {add, or, xor, sub}, replacing the 3-insn select (plus
527 // the original binop) with a single mask instruction plus the binop.
528 if (Subtarget.has32S())
530
531 // Set DAG combine for 'LSX' feature.
532
533 if (Subtarget.hasExtLSX()) {
545 }
546
547 // Set DAG combine for 'LASX' feature.
548 if (Subtarget.hasExtLASX()) {
551 }
552
553 // Compute derived properties from the register classes.
554 computeRegisterProperties(Subtarget.getRegisterInfo());
555
557
560
561 setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
562
564
565 // Function alignments.
567 // Set preferred alignments.
568 setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
569 setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
570 setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
571
572 // cmpxchg sizes down to 8 bits become legal if LAMCAS is available.
573 if (Subtarget.hasLAMCAS())
575
576 if (Subtarget.hasSCQ()) {
579 }
580
581 // Disable strict node mutation.
582 IsStrictFPEnabled = true;
583}
584
586 const GlobalAddressSDNode *GA) const {
587 // In order to maximise the opportunity for common subexpression elimination,
588 // keep a separate ADD node for the global address offset instead of folding
589 // it in the global address node. Later peephole optimisations may choose to
590 // fold it back in when profitable.
591 return false;
592}
593
595 SelectionDAG &DAG) const {
596 switch (Op.getOpcode()) {
598 return lowerATOMIC_FENCE(Op, DAG);
600 return lowerEH_DWARF_CFA(Op, DAG);
602 return lowerGlobalAddress(Op, DAG);
604 return lowerGlobalTLSAddress(Op, DAG);
606 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
608 return lowerINTRINSIC_W_CHAIN(Op, DAG);
610 return lowerINTRINSIC_VOID(Op, DAG);
612 return lowerBlockAddress(Op, DAG);
613 case ISD::JumpTable:
614 return lowerJumpTable(Op, DAG);
615 case ISD::SHL_PARTS:
616 return lowerShiftLeftParts(Op, DAG);
617 case ISD::SRA_PARTS:
618 return lowerShiftRightParts(Op, DAG, true);
619 case ISD::SRL_PARTS:
620 return lowerShiftRightParts(Op, DAG, false);
622 return lowerConstantPool(Op, DAG);
623 case ISD::FP_TO_SINT:
624 return lowerFP_TO_SINT(Op, DAG);
625 case ISD::FP_TO_UINT:
626 return lowerFP_TO_UINT(Op, DAG);
628 return lowerFP_TO_SINT_SAT(Op, DAG);
629 case ISD::BITCAST:
630 return lowerBITCAST(Op, DAG);
631 case ISD::UINT_TO_FP:
632 return lowerUINT_TO_FP(Op, DAG);
633 case ISD::SINT_TO_FP:
634 return lowerSINT_TO_FP(Op, DAG);
635 case ISD::VASTART:
636 return lowerVASTART(Op, DAG);
637 case ISD::FRAMEADDR:
638 return lowerFRAMEADDR(Op, DAG);
639 case ISD::RETURNADDR:
640 return lowerRETURNADDR(Op, DAG);
642 return lowerSET_ROUNDING(Op, DAG);
644 return lowerGET_ROUNDING(Op, DAG);
646 return lowerWRITE_REGISTER(Op, DAG);
648 return lowerINSERT_VECTOR_ELT(Op, DAG);
650 return lowerEXTRACT_VECTOR_ELT(Op, DAG);
652 return lowerBUILD_VECTOR(Op, DAG);
654 return lowerCONCAT_VECTORS(Op, DAG);
656 return lowerVECTOR_SHUFFLE(Op, DAG);
657 case ISD::BITREVERSE:
658 return lowerBITREVERSE(Op, DAG);
660 return lowerSCALAR_TO_VECTOR(Op, DAG);
661 case ISD::PREFETCH:
662 return lowerPREFETCH(Op, DAG);
663 case ISD::SELECT:
664 return lowerSELECT(Op, DAG);
665 case ISD::BRCOND:
666 return lowerBRCOND(Op, DAG);
667 case ISD::FP_TO_FP16:
668 return lowerFP_TO_FP16(Op, DAG);
669 case ISD::FP16_TO_FP:
670 return lowerFP16_TO_FP(Op, DAG);
671 case ISD::FP_TO_BF16:
672 return lowerFP_TO_BF16(Op, DAG);
673 case ISD::BF16_TO_FP:
674 return lowerBF16_TO_FP(Op, DAG);
676 return lowerVECREDUCE_ADD(Op, DAG);
677 case ISD::ROTL:
678 case ISD::ROTR:
679 return lowerRotate(Op, DAG);
687 return lowerVECREDUCE(Op, DAG);
688 case ISD::ConstantFP:
689 return lowerConstantFP(Op, DAG);
690 case ISD::SETCC:
691 return lowerSETCC(Op, DAG);
692 case ISD::FP_ROUND:
693 return lowerFP_ROUND(Op, DAG);
694 case ISD::FP_EXTEND:
695 return lowerFP_EXTEND(Op, DAG);
697 return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
699 return lowerDYNAMIC_STACKALLOC(Op, DAG);
700 case ISD::ANY_EXTEND:
701 return lowerANY_EXTEND(Op, DAG);
702 }
703 return SDValue();
704}
705
706// Helper to attempt to return a cheaper, bit-inverted version of \p V.
708 // TODO: don't always ignore oneuse constraints.
710 EVT VT = V.getValueType();
711
712 // Match not(xor X, -1) -> X.
713 if (V.getOpcode() == ISD::XOR &&
714 (ISD::isBuildVectorAllOnes(V.getOperand(1).getNode()) ||
715 isAllOnesConstant(V.getOperand(1))))
716 return V.getOperand(0);
717
718 // Match not(extract_subvector(not(X)) -> extract_subvector(X).
719 if (V.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
720 (isNullConstant(V.getOperand(1)) || V.getOperand(0).hasOneUse())) {
721 if (SDValue Not = isNOT(V.getOperand(0), DAG)) {
722 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
723 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(Not), VT, Not,
724 V.getOperand(1));
725 }
726 }
727
728 // Match not(SplatVector(not(X)) -> SplatVector(X).
729 if (V.getOpcode() == ISD::BUILD_VECTOR) {
730 if (SDValue SplatValue =
731 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
732 if (!V->isOnlyUserOf(SplatValue.getNode()))
733 return SDValue();
734
735 if (SDValue Not = isNOT(SplatValue, DAG)) {
736 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
737 return DAG.getSplat(VT, SDLoc(Not), Not);
738 }
739 }
740 }
741
742 // Match not(or(not(X),not(Y))) -> and(X, Y).
743 if (V.getOpcode() == ISD::OR && DAG.getTargetLoweringInfo().isTypeLegal(VT) &&
744 V.getOperand(0).hasOneUse() && V.getOperand(1).hasOneUse()) {
745 // TODO: Handle cases with single NOT operand -> VANDN
746 if (SDValue Op1 = isNOT(V.getOperand(1), DAG))
747 if (SDValue Op0 = isNOT(V.getOperand(0), DAG))
748 return DAG.getNode(ISD::AND, SDLoc(V), VT, DAG.getBitcast(VT, Op0),
749 DAG.getBitcast(VT, Op1));
750 }
751
752 // TODO: Add more matching patterns. Such as,
753 // not(concat_vectors(not(X), not(Y))) -> concat_vectors(X, Y).
754 // not(slt(C, X)) -> slt(X - 1, C)
755 return SDValue();
756}
757
758// Combine two ISD::FP_ROUND / LoongArchISD::VFCVT nodes with same type to
759// LoongArchISD::VFCVT. For example:
760// x1 = fp_round x, 0
761// y1 = fp_round y, 0
762// z = concat_vectors x1, y1
763// Or
764// x1 = LoongArch::VFCVT undef, x
765// y1 = LoongArch::VFCVT undef, y
766// z = LoongArchISD::VPACKEV y1, x1; or LoongArchISD::VPERMI y1, x1, 68
767// can be combined to:
768// z = LoongArch::VFCVT y, x
771 assert(((N->getOpcode() == ISD::CONCAT_VECTORS && N->getNumOperands() == 2) ||
772 (N->getOpcode() == LoongArchISD::VPACKEV) ||
773 (N->getOpcode() == LoongArchISD::VPERMI)) &&
774 "Invalid Node");
775
776 SDValue Op0 = peekThroughBitcasts(N->getOperand(0));
777 SDValue Op1 = peekThroughBitcasts(N->getOperand(1));
778 unsigned Opcode0 = Op0.getOpcode();
779 unsigned Opcode1 = Op1.getOpcode();
780 if (Opcode0 != Opcode1)
781 return SDValue();
782
783 if (Opcode0 != ISD::FP_ROUND && Opcode0 != LoongArchISD::VFCVT)
784 return SDValue();
785
786 // Check if two nodes have only one use.
787 if (!Op0.hasOneUse() || !Op1.hasOneUse())
788 return SDValue();
789
790 EVT VT = N.getValueType();
791 EVT SVT0 = Op0.getValueType();
792 EVT SVT1 = Op1.getValueType();
793 // Check if two nodes have the same result type.
794 if (SVT0 != SVT1)
795 return SDValue();
796
797 // Check if two nodes have the same operand type.
798 EVT SSVT0 = Op0.getOperand(0).getValueType();
799 EVT SSVT1 = Op1.getOperand(0).getValueType();
800 if (SSVT0 != SSVT1)
801 return SDValue();
802
803 if (N->getOpcode() == ISD::CONCAT_VECTORS && Opcode0 == ISD::FP_ROUND) {
804 if (Subtarget.hasExtLASX() && VT.is256BitVector() && SVT0 == MVT::v4f32 &&
805 SSVT0 == MVT::v4f64) {
806 // A vector_shuffle is required in the final step, as xvfcvt instruction
807 // operates on each 128-bit segament as a lane.
808 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v8f32,
809 Op1.getOperand(0), Op0.getOperand(0));
810 SDValue Undef = DAG.getUNDEF(Res.getValueType());
811 // After VFCVT, the high part of Res comes from the high parts of Op0 and
812 // Op1, and the low part comes from the low parts of Op0 and Op1. However,
813 // the desired order requires Op0 to fully occupy the lower half and Op1
814 // the upper half of Res. The Mask reorders the elements of Res to achieve
815 // this:
816 // - The first four elements (0, 1, 4, 5) come from Op0.
817 // - The next four elements (2, 3, 6, 7) come from Op1.
818 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
819 Res = DAG.getVectorShuffle(Res.getValueType(), DL, Res, Undef, Mask);
820 return DAG.getBitcast(VT, Res);
821 }
822 }
823
824 if ((N->getOpcode() == LoongArchISD::VPACKEV ||
825 N->getOpcode() == LoongArchISD::VPERMI) &&
826 Opcode0 == LoongArchISD::VFCVT) {
827 // For VPACKEV or VPERMI, check if the first operation of VFCVT is undef.
828 if (!Op0.getOperand(0).isUndef() || !Op1.getOperand(0).isUndef())
829 return SDValue();
830
831 if (!Subtarget.hasExtLSX() || SVT0 != MVT::v4f32 || SSVT0 != MVT::v2f64)
832 return SDValue();
833
834 if (N->getOpcode() == LoongArchISD::VPACKEV &&
835 (VT == MVT::v2i64 || VT == MVT::v2f64)) {
836 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32,
837 Op0.getOperand(1), Op1.getOperand(1));
838 return DAG.getBitcast(VT, Res);
839 }
840
841 if (N->getOpcode() == LoongArchISD::VPERMI && VT == MVT::v4f32) {
842 int64_t Imm = cast<ConstantSDNode>(N->getOperand(2))->getSExtValue();
843 if (Imm != 68)
844 return SDValue();
845 return DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Op0.getOperand(1),
846 Op1.getOperand(1));
847 }
848 }
849
850 return SDValue();
851}
852
853SDValue LoongArchTargetLowering::lowerFP_ROUND(SDValue Op,
854 SelectionDAG &DAG) const {
855 SDLoc DL(Op);
856 SDValue In = Op.getOperand(0);
857 MVT VT = Op.getSimpleValueType();
858 MVT SVT = In.getSimpleValueType();
859
860 if (VT == MVT::v4f32 && SVT == MVT::v4f64) {
861 SDValue Lo, Hi;
862 std::tie(Lo, Hi) = DAG.SplitVector(In, DL);
863 return DAG.getNode(LoongArchISD::VFCVT, DL, VT, Hi, Lo);
864 }
865
866 return SDValue();
867}
868
869SDValue LoongArchTargetLowering::lowerFP_EXTEND(SDValue Op,
870 SelectionDAG &DAG) const {
871
872 SDLoc DL(Op);
873 EVT VT = Op.getValueType();
874 SDValue Src = Op->getOperand(0);
875 EVT SVT = Src.getValueType();
876
877 bool V2F32ToV2F64 =
878 VT == MVT::v2f64 && SVT == MVT::v2f32 && Subtarget.hasExtLSX();
879 bool V4F32ToV4F64 =
880 VT == MVT::v4f64 && SVT == MVT::v4f32 && Subtarget.hasExtLASX();
881 if (!V2F32ToV2F64 && !V4F32ToV4F64)
882 return SDValue();
883
884 // Check if Op is the high part of vector.
885 auto CheckVecHighPart = [](SDValue Op) {
887 if (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
888 SDValue SOp = Op.getOperand(0);
889 EVT SVT = SOp.getValueType();
890 if (!SVT.isVector() || (SVT.getVectorNumElements() % 2 != 0))
891 return SDValue();
892
893 const uint64_t Imm = Op.getConstantOperandVal(1);
894 if (Imm == SVT.getVectorNumElements() / 2)
895 return SOp;
896 return SDValue();
897 }
898 return SDValue();
899 };
900
901 unsigned Opcode;
902 SDValue VFCVTOp;
903 EVT WideOpVT = SVT.getSimpleVT().getDoubleNumVectorElementsVT();
904 SDValue ZeroIdx = DAG.getVectorIdxConstant(0, DL);
905
906 // If the operand of ISD::FP_EXTEND comes from the high part of vector,
907 // generate LoongArchISD::VFCVTH, otherwise LoongArchISD::VFCVTL.
908 if (SDValue V = CheckVecHighPart(Src)) {
909 assert(V.getValueSizeInBits() == WideOpVT.getSizeInBits() &&
910 "Unexpected wide vector");
911 Opcode = LoongArchISD::VFCVTH;
912 VFCVTOp = DAG.getBitcast(WideOpVT, V);
913 } else {
914 Opcode = LoongArchISD::VFCVTL;
915 VFCVTOp = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideOpVT,
916 DAG.getUNDEF(WideOpVT), Src, ZeroIdx);
917 }
918
919 // v2f64 = fp_extend v2f32
920 if (V2F32ToV2F64)
921 return DAG.getNode(Opcode, DL, VT, VFCVTOp);
922
923 // v4f64 = fp_extend v4f32
924 if (V4F32ToV4F64) {
925 // XVFCVT instruction operates on each 128-bit segment as a lane, so a
926 // vector_shuffle is required firstly.
927 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
928 SDValue Res = DAG.getVectorShuffle(WideOpVT, DL, VFCVTOp,
929 DAG.getUNDEF(WideOpVT), Mask);
930 Res = DAG.getNode(Opcode, DL, VT, Res);
931 return Res;
932 }
933
934 return SDValue();
935}
936
937SDValue LoongArchTargetLowering::lowerConstantFP(SDValue Op,
938 SelectionDAG &DAG) const {
939 EVT VT = Op.getValueType();
940 ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
941 const APFloat &FPVal = CFP->getValueAPF();
942 SDLoc DL(CFP);
943
944 assert((VT == MVT::f32 && Subtarget.hasBasicF()) ||
945 (VT == MVT::f64 && Subtarget.hasBasicD()));
946
947 // If value is 0.0 or -0.0, just ignore it.
948 if (FPVal.isZero())
949 return SDValue();
950
951 // If lsx enabled, use cheaper 'vldi' instruction if possible.
952 if (isFPImmVLDILegal(FPVal, VT))
953 return SDValue();
954
955 // The legalizer builds immediates the size of a GPR from their bits. Fall
956 // back to a load from the constant pool for expensive immediates.
957 if (VT.getSizeInBits() == Subtarget.getGRLen() ||
958 !isFPImmCheapInGPR(FPVal, VT))
959 return SDValue();
960
961 // Construct as integer, and move to float register.
962 APInt INTVal = FPVal.bitcastToAPInt();
963 if (VT == MVT::f32) {
964 assert(Subtarget.is64Bit());
965 SDValue NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
966 DAG.getConstant(INTVal, DL, MVT::i32));
967 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, VT, NewVal);
968 }
969
970 assert(VT == MVT::f64 && !Subtarget.is64Bit());
971 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
972 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
973 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
974}
975
976// Ensure SETCC result and operand have the same bit width; isel does not
977// support mismatched widths.
978SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
979 SelectionDAG &DAG) const {
980 SDLoc DL(Op);
981 EVT ResultVT = Op.getValueType();
982 EVT OperandVT = Op.getOperand(0).getValueType();
983
984 EVT SetCCResultVT =
985 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
986
987 if (ResultVT == SetCCResultVT)
988 return Op;
989
990 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
991 "SETCC operands must have the same type!");
992
993 SDValue SetCCNode =
994 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
995 Op.getOperand(1), Op.getOperand(2));
996
997 if (ResultVT.bitsGT(SetCCResultVT))
998 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
999 else if (ResultVT.bitsLT(SetCCResultVT))
1000 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
1001
1002 return SetCCNode;
1003}
1004
1005// Lower SIGN_EXTEND_VECTOR_INREG with VSLLWIL, which sign-extends the low half
1006// of the source elements (and shifts them left by 0).
1007// For example:
1008// %b = sext <8 x i8> %a to <8 x i16>
1009// can be lowered to:
1010// VSLLWIL.H.B vr1, vr1, 0
1011//
1012// VSLLWIL is slower than VILVL and VSRAI, so a 4x extension instead
1013// replicates each source element across its destination element by
1014// interleaving the source with itself twice, then shifts the copy in the top
1015// bits down arithmetically:
1016// %b = sext <4 x i8> %a to <4 x i32>
1017// can be lowered to:
1018// VILVL.B vr1, vr1, vr1
1019// VILVL.H vr1, vr1, vr1
1020// VSRAI.W vr1, vr1, 24
1021//
1022// If every extended source element is already all-ones or all-zeros, e.g. a
1023// comparison result, the interleaves alone produce the sign extension, so
1024// neither VSLLWIL nor the VSRAI is needed:
1025// %b = sext <8 x i8> %mask to <8 x i16>
1026// can be lowered to:
1027// VILVL.B vr1, vr1, vr1
1028SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1029 SDValue Op, SelectionDAG &DAG) const {
1030 SDLoc DL(Op);
1031 SDValue Src = Op.getOperand(0);
1032 MVT SrcVT = Src.getSimpleValueType();
1033 MVT DstVT = Op.getSimpleValueType();
1034 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
1035 unsigned DstEltBits = DstVT.getScalarSizeInBits();
1036
1037 // Leave larger ratios to the generic shuffle + shift expansion, which only
1038 // needs a single VEXTRINS to move the second element into place.
1039 unsigned Ratio = DstEltBits / SrcEltBits;
1040 if (!SrcVT.is128BitVector() || Ratio > 4)
1041 return SDValue();
1042
1043 // Only the low elements of the source are extended.
1044 APInt DemandedElts = APInt::getLowBitsSet(SrcVT.getVectorNumElements(),
1045 DstVT.getVectorNumElements());
1046 bool IsSignSplat = DAG.ComputeNumSignBits(Src, DemandedElts) == SrcEltBits;
1047
1048 if (Ratio == 2 && !IsSignSplat)
1049 return DAG.getNode(LoongArchISD::VSLLWIL, DL, DstVT, Src,
1050 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1051
1052 SDValue Res = Src;
1053 for (unsigned EltBits = SrcEltBits; EltBits < DstEltBits; EltBits *= 2) {
1054 MVT VT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), 128 / EltBits);
1055 Res = DAG.getBitcast(VT, Res);
1056 Res = DAG.getNode(LoongArchISD::VILVL, DL, VT, Res, Res);
1057 }
1058 Res = DAG.getBitcast(DstVT, Res);
1059 if (IsSignSplat)
1060 return Res;
1061 return DAG.getNode(ISD::SRA, DL, DstVT, Res,
1062 DAG.getConstant(DstEltBits - SrcEltBits, DL, DstVT));
1063}
1064
1065// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1066SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1067 SelectionDAG &DAG) const {
1068 assert(Subtarget.hasExtLASX());
1069 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1070 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1071 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1072 Op.getOperand(0));
1073}
1074
1075// Lower vecreduce_add using vhaddw instructions.
1076// For Example:
1077// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1078// can be lowered to:
1079// VHADDW_D_W vr0, vr0, vr0
1080// VHADDW_Q_D vr0, vr0, vr0
1081// VPICKVE2GR_D a0, vr0, 0
1082// ADDI_W a0, a0, 0
1083SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1084 SelectionDAG &DAG) const {
1085
1086 SDLoc DL(Op);
1087 MVT OpVT = Op.getSimpleValueType();
1088 SDValue Val = Op.getOperand(0);
1089
1090 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1091 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1092 unsigned ResBits = OpVT.getScalarSizeInBits();
1093
1094 unsigned LegalVecSize = 128;
1095 bool isLASX256Vector =
1096 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1097
1098 // Ensure operand type legal or enable it legal.
1099 while (!isTypeLegal(Val.getSimpleValueType())) {
1100 Val = DAG.WidenVector(Val, DL);
1101 }
1102
1103 // NumEles is designed for iterations count, v4i32 for LSX
1104 // and v8i32 for LASX should have the same count.
1105 if (isLASX256Vector) {
1106 NumEles /= 2;
1107 LegalVecSize = 256;
1108 }
1109
1110 EleBits *= 2;
1111 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1112 EleBits = std::min(EleBits, 64u);
1113 MVT IntTy = MVT::getIntegerVT(EleBits);
1114 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1115 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1116 }
1117
1118 if (isLASX256Vector) {
1119 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1120 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1121 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1122 }
1123
1124 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1125 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1126 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1127}
1128
1129// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1130// For Example:
1131// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1132// can be lowered to:
1133// VBSRL_V vr1, vr0, 8
1134// VMAX_W vr0, vr1, vr0
1135// VBSRL_V vr1, vr0, 4
1136// VMAX_W vr0, vr1, vr0
1137// VPICKVE2GR_W a0, vr0, 0
1138// For 256 bit vector, it is illegal and will be spilt into
1139// two 128 bit vector by default then processed by this.
1140SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1141 SelectionDAG &DAG) const {
1142 SDLoc DL(Op);
1143
1144 MVT OpVT = Op.getSimpleValueType();
1145 SDValue Val = Op.getOperand(0);
1146
1147 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1148 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1149
1150 // Ensure operand type legal or enable it legal.
1151 while (!isTypeLegal(Val.getSimpleValueType())) {
1152 Val = DAG.WidenVector(Val, DL);
1153 }
1154
1155 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1156 MVT VecTy = Val.getSimpleValueType();
1157 MVT GRLenVT = Subtarget.getGRLenVT();
1158
1159 for (int i = NumEles; i > 1; i /= 2) {
1160 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1161 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1162 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1163 }
1164
1165 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1166 DAG.getConstant(0, DL, GRLenVT));
1167}
1168
1169SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1170 SelectionDAG &DAG) const {
1171 unsigned IsData = Op.getConstantOperandVal(4);
1172
1173 // We don't support non-data prefetch.
1174 // Just preserve the chain.
1175 if (!IsData)
1176 return Op.getOperand(0);
1177
1178 return Op;
1179}
1180
1181SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1182 SelectionDAG &DAG) const {
1183 MVT VT = Op.getSimpleValueType();
1184 assert(VT.isVector() && "Unexpected type");
1185
1186 SDLoc DL(Op);
1187 SDValue R = Op.getOperand(0);
1188 SDValue Amt = Op.getOperand(1);
1189 unsigned Opcode = Op.getOpcode();
1190 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1191
1192 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1193 if (V.getOpcode() != ISD::BUILD_VECTOR)
1194 return false;
1195 if (SDValue SplatValue =
1196 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1197 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1198 CstSplatValue = C->getAPIntValue();
1199 return true;
1200 }
1201 }
1202 return false;
1203 };
1204
1205 // Check for constant splat rotation amount.
1206 APInt CstSplatValue;
1207 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1208 bool isROTL = Opcode == ISD::ROTL;
1209
1210 // Check for splat rotate by zero.
1211 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1212 return R;
1213
1214 // LoongArch targets always prefer ISD::ROTR.
1215 if (isROTL) {
1216 SDValue Zero = DAG.getConstant(0, DL, VT);
1217 return DAG.getNode(ISD::ROTR, DL, VT, R,
1218 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1219 }
1220
1221 // Rotate by a immediate.
1222 if (IsCstSplat) {
1223 // ISD::ROTR: Attemp to rotate by a positive immediate.
1224 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1225 if (SDValue Urem =
1226 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1227 return DAG.getNode(Opcode, DL, VT, R, Urem);
1228 }
1229
1230 return Op;
1231}
1232
1233// Return true if Val is equal to (setcc LHS, RHS, CC).
1234// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1235// Otherwise, return std::nullopt.
1236static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1237 ISD::CondCode CC, SDValue Val) {
1238 assert(Val->getOpcode() == ISD::SETCC);
1239 SDValue LHS2 = Val.getOperand(0);
1240 SDValue RHS2 = Val.getOperand(1);
1241 ISD::CondCode CC2 = Val.getOperandCondCode(2);
1242
1243 if (LHS == LHS2 && RHS == RHS2) {
1244 if (CC == CC2)
1245 return true;
1246 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1247 return false;
1248 } else if (LHS == RHS2 && RHS == LHS2) {
1250 if (CC == CC2)
1251 return true;
1252 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1253 return false;
1254 }
1255
1256 return std::nullopt;
1257}
1258
1261 SDValue CondV = N->getOperand(0);
1262 SDValue TrueV = N->getOperand(1);
1263 SDValue FalseV = N->getOperand(2);
1264 MVT VT = N->getSimpleValueType(0);
1265 SDLoc DL(N);
1266
1267 // (select c, -1, y) -> -c | y
1268 if (isAllOnesConstant(TrueV)) {
1269 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1270 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1271 }
1272 // (select c, y, -1) -> (c-1) | y
1273 if (isAllOnesConstant(FalseV)) {
1274 SDValue Neg =
1275 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1276 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1277 }
1278
1279 // (select c, 0, y) -> (c-1) & y
1280 if (isNullConstant(TrueV)) {
1281 SDValue Neg =
1282 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1283 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1284 }
1285 // (select c, y, 0) -> -c & y
1286 if (isNullConstant(FalseV)) {
1287 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1288 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1289 }
1290
1291 // select c, ~x, x --> xor -c, x
1292 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1293 const APInt &TrueVal = TrueV->getAsAPIntVal();
1294 const APInt &FalseVal = FalseV->getAsAPIntVal();
1295 if (~TrueVal == FalseVal) {
1296 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1297 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1298 }
1299 }
1300
1301 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1302 // when both truev and falsev are also setcc.
1303 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1304 FalseV.getOpcode() == ISD::SETCC) {
1305 SDValue LHS = CondV.getOperand(0);
1306 SDValue RHS = CondV.getOperand(1);
1308
1309 // (select x, x, y) -> x | y
1310 // (select !x, x, y) -> x & y
1311 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1312 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1313 DAG.getFreeze(FalseV));
1314 }
1315 // (select x, y, x) -> x & y
1316 // (select !x, y, x) -> x | y
1317 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1318 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1319 DAG.getFreeze(TrueV), FalseV);
1320 }
1321 }
1322
1323 return SDValue();
1324}
1325
1326// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1327// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1328// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1329// being `0` or `-1`. In such cases we can replace `select` with `and`.
1330// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1331// than `c0`?
1332static SDValue
1335 unsigned SelOpNo = 0;
1336 SDValue Sel = BO->getOperand(0);
1337 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1338 SelOpNo = 1;
1339 Sel = BO->getOperand(1);
1340 }
1341
1342 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1343 return SDValue();
1344
1345 unsigned ConstSelOpNo = 1;
1346 unsigned OtherSelOpNo = 2;
1347 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1348 ConstSelOpNo = 2;
1349 OtherSelOpNo = 1;
1350 }
1351 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1352 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1353 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1354 return SDValue();
1355
1356 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1357 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1358 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1359 return SDValue();
1360
1361 SDLoc DL(Sel);
1362 EVT VT = BO->getValueType(0);
1363
1364 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1365 if (SelOpNo == 1)
1366 std::swap(NewConstOps[0], NewConstOps[1]);
1367
1368 SDValue NewConstOp =
1369 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1370 if (!NewConstOp)
1371 return SDValue();
1372
1373 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1374 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1375 return SDValue();
1376
1377 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1378 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1379 if (SelOpNo == 1)
1380 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1381 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1382
1383 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1384 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1385 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1386}
1387
1388// Changes the condition code and swaps operands if necessary, so the SetCC
1389// operation matches one of the comparisons supported directly by branches
1390// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1391// compare with 1/-1.
1393 ISD::CondCode &CC, SelectionDAG &DAG) {
1394 // If this is a single bit test that can't be handled by ANDI, shift the
1395 // bit to be tested to the MSB and perform a signed compare with 0.
1396 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1397 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1398 isa<ConstantSDNode>(LHS.getOperand(1))) {
1399 uint64_t Mask = LHS.getConstantOperandVal(1);
1400 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1401 unsigned ShAmt = 0;
1402 if (isPowerOf2_64(Mask)) {
1404 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1405 } else {
1406 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1407 }
1408
1409 LHS = LHS.getOperand(0);
1410 if (ShAmt != 0)
1411 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1412 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1413 return;
1414 }
1415 }
1416
1417 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1418 int64_t C = RHSC->getSExtValue();
1419 switch (CC) {
1420 default:
1421 break;
1422 case ISD::SETGT:
1423 // Convert X > -1 to X >= 0.
1424 if (C == -1) {
1425 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1426 CC = ISD::SETGE;
1427 return;
1428 }
1429 break;
1430 case ISD::SETLT:
1431 // Convert X < 1 to 0 >= X.
1432 if (C == 1) {
1433 RHS = LHS;
1434 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1435 CC = ISD::SETGE;
1436 return;
1437 }
1438 break;
1439 }
1440 }
1441
1442 switch (CC) {
1443 default:
1444 break;
1445 case ISD::SETGT:
1446 case ISD::SETLE:
1447 case ISD::SETUGT:
1448 case ISD::SETULE:
1450 std::swap(LHS, RHS);
1451 break;
1452 }
1453}
1454
1455SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1456 SelectionDAG &DAG) const {
1457 SDValue CondV = Op.getOperand(0);
1458 SDValue TrueV = Op.getOperand(1);
1459 SDValue FalseV = Op.getOperand(2);
1460 SDLoc DL(Op);
1461 MVT VT = Op.getSimpleValueType();
1462 MVT GRLenVT = Subtarget.getGRLenVT();
1463
1464 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1465 return V;
1466
1467 if (Op.hasOneUse()) {
1468 unsigned UseOpc = Op->user_begin()->getOpcode();
1469 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1470 SDNode *BinOp = *Op->user_begin();
1471 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1472 DAG, Subtarget)) {
1473 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1474 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1475 // may return a constant node and cause crash in lowerSELECT.
1476 if (NewSel.getOpcode() == ISD::SELECT)
1477 return lowerSELECT(NewSel, DAG);
1478 return NewSel;
1479 }
1480 }
1481 }
1482
1483 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1484 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1485 // (select condv, truev, falsev)
1486 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1487 if (CondV.getOpcode() != ISD::SETCC ||
1488 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1489 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1490 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1491
1492 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1493
1494 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1495 }
1496
1497 // If the CondV is the output of a SETCC node which operates on GRLenVT
1498 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1499 // to take advantage of the integer compare+branch instructions. i.e.: (select
1500 // (setcc lhs, rhs, cc), truev, falsev)
1501 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1502 SDValue LHS = CondV.getOperand(0);
1503 SDValue RHS = CondV.getOperand(1);
1504 ISD::CondCode CCVal = CondV.getOperandCondCode(2);
1505
1506 // Special case for a select of 2 constants that have a difference of 1.
1507 // Normally this is done by DAGCombine, but if the select is introduced by
1508 // type legalization or op legalization, we miss it. Restricting to SETLT
1509 // case for now because that is what signed saturating add/sub need.
1510 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1511 // but we would probably want to swap the true/false values if the condition
1512 // is SETGE/SETLE to avoid an XORI.
1513 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1514 CCVal == ISD::SETLT) {
1515 const APInt &TrueVal = TrueV->getAsAPIntVal();
1516 const APInt &FalseVal = FalseV->getAsAPIntVal();
1517 if (TrueVal - 1 == FalseVal)
1518 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1519 if (TrueVal + 1 == FalseVal)
1520 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1521 }
1522
1523 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1524 // 1 < x ? x : 1 -> 0 < x ? x : 1
1525 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1526 RHS == TrueV && LHS == FalseV) {
1527 LHS = DAG.getConstant(0, DL, VT);
1528 // 0 <u x is the same as x != 0.
1529 if (CCVal == ISD::SETULT) {
1530 std::swap(LHS, RHS);
1531 CCVal = ISD::SETNE;
1532 }
1533 }
1534
1535 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1536 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1537 RHS == FalseV) {
1538 RHS = DAG.getConstant(0, DL, VT);
1539 }
1540
1541 SDValue TargetCC = DAG.getCondCode(CCVal);
1542
1543 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1544 // (select (setcc lhs, rhs, CC), constant, falsev)
1545 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1546 std::swap(TrueV, FalseV);
1547 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1548 }
1549
1550 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1551 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1552}
1553
1554SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1555 SelectionDAG &DAG) const {
1556 SDValue CondV = Op.getOperand(1);
1557 SDLoc DL(Op);
1558 MVT GRLenVT = Subtarget.getGRLenVT();
1559
1560 if (CondV.getOpcode() == ISD::SETCC) {
1561 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1562 SDValue LHS = CondV.getOperand(0);
1563 SDValue RHS = CondV.getOperand(1);
1564 ISD::CondCode CCVal = CondV.getOperandCondCode(2);
1565
1566 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1567
1568 SDValue TargetCC = DAG.getCondCode(CCVal);
1569 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1570 Op.getOperand(0), LHS, RHS, TargetCC,
1571 Op.getOperand(2));
1572 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1573 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1574 Op.getOperand(0), CondV, Op.getOperand(2));
1575 }
1576 }
1577
1578 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1579 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1580 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1581}
1582
1583SDValue
1584LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1585 SelectionDAG &DAG) const {
1586 SDLoc DL(Op);
1587 MVT OpVT = Op.getSimpleValueType();
1588
1589 SDValue Vector = DAG.getUNDEF(OpVT);
1590 SDValue Val = Op.getOperand(0);
1591 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1592
1593 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1594}
1595
1596SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1597 SelectionDAG &DAG) const {
1598 EVT ResTy = Op->getValueType(0);
1599 SDValue Src = Op->getOperand(0);
1600 SDLoc DL(Op);
1601
1602 // LoongArchISD::BITREV_8B is not supported on LA32.
1603 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1604 return SDValue();
1605
1606 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1607 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1608 unsigned int NewEltNum = NewVT.getVectorNumElements();
1609
1610 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1611
1613 for (unsigned int i = 0; i < NewEltNum; i++) {
1614 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1615 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1616 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1617 ? (unsigned)LoongArchISD::BITREV_8B
1618 : (unsigned)ISD::BITREVERSE;
1619 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1620 }
1621 SDValue Res =
1622 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1623
1624 switch (ResTy.getSimpleVT().SimpleTy) {
1625 default:
1626 return SDValue();
1627 case MVT::v16i8:
1628 case MVT::v32i8:
1629 return Res;
1630 case MVT::v8i16:
1631 case MVT::v16i16:
1632 case MVT::v4i32:
1633 case MVT::v8i32: {
1635 for (unsigned int i = 0; i < NewEltNum; i++)
1636 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1637 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1638 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1639 }
1640 }
1641}
1642
1643// Widen element type to get a new mask value (if possible).
1644// For example:
1645// shufflevector <4 x i32> %a, <4 x i32> %b,
1646// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1647// is equivalent to:
1648// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1649// can be lowered to:
1650// VPACKOD_D vr0, vr0, vr1
1652 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1653 unsigned EltBits = VT.getScalarSizeInBits();
1654
1655 if (EltBits > 32 || EltBits == 1)
1656 return SDValue();
1657
1658 SmallVector<int, 8> NewMask;
1659 if (widenShuffleMaskElts(Mask, NewMask)) {
1660 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1661 : MVT::getIntegerVT(EltBits * 2);
1662 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1663 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1664 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1665 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1666 return DAG.getBitcast(
1667 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1668 }
1669 }
1670
1671 return SDValue();
1672}
1673
1674/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1675/// instruction.
1676// The funciton matches elements from one of the input vector shuffled to the
1677// left or right with zeroable elements 'shifted in'. It handles both the
1678// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1679// lane.
1680// Mostly copied from X86.
1681static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1682 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1683 int MaskOffset, const APInt &Zeroable) {
1684 int Size = Mask.size();
1685 unsigned SizeInBits = Size * ScalarSizeInBits;
1686
1687 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1688 for (int i = 0; i < Size; i += Scale)
1689 for (int j = 0; j < Shift; ++j)
1690 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1691 return false;
1692
1693 return true;
1694 };
1695
1696 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1697 int Step = 1) {
1698 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1699 if (!(Mask[i] == -1 || Mask[i] == Low))
1700 return false;
1701 return true;
1702 };
1703
1704 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1705 for (int i = 0; i != Size; i += Scale) {
1706 unsigned Pos = Left ? i + Shift : i;
1707 unsigned Low = Left ? i : i + Shift;
1708 unsigned Len = Scale - Shift;
1709 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1710 return -1;
1711 }
1712
1713 int ShiftEltBits = ScalarSizeInBits * Scale;
1714 bool ByteShift = ShiftEltBits > 64;
1715 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1716 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1717 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1718
1719 // Normalize the scale for byte shifts to still produce an i64 element
1720 // type.
1721 Scale = ByteShift ? Scale / 2 : Scale;
1722
1723 // We need to round trip through the appropriate type for the shift.
1724 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1725 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1726 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1727 return (int)ShiftAmt;
1728 };
1729
1730 unsigned MaxWidth = 128;
1731 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1732 for (int Shift = 1; Shift != Scale; ++Shift)
1733 for (bool Left : {true, false})
1734 if (CheckZeros(Shift, Scale, Left)) {
1735 int ShiftAmt = MatchShift(Shift, Scale, Left);
1736 if (0 < ShiftAmt)
1737 return ShiftAmt;
1738 }
1739
1740 // no match
1741 return -1;
1742}
1743
1744/// Lower VECTOR_SHUFFLE as shift (if possible).
1745///
1746/// For example:
1747/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1748/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1749/// is lowered to:
1750/// (VBSLL_V $v0, $v0, 4)
1751///
1752/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1753/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1754/// is lowered to:
1755/// (VSLLI_D $v0, $v0, 32)
1757 MVT VT, SDValue V1, SDValue V2,
1758 SelectionDAG &DAG,
1760 const APInt &Zeroable) {
1761 int Size = Mask.size();
1762 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1763
1764 MVT ShiftVT;
1765 SDValue V = V1;
1766 unsigned Opcode;
1767
1768 // Try to match shuffle against V1 shift.
1769 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1770 Mask, 0, Zeroable);
1771
1772 // If V1 failed, try to match shuffle against V2 shift.
1773 if (ShiftAmt < 0) {
1774 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1775 Mask, Size, Zeroable);
1776 V = V2;
1777 }
1778
1779 if (ShiftAmt < 0)
1780 return SDValue();
1781
1782 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1783 "Illegal integer vector type");
1784 V = DAG.getBitcast(ShiftVT, V);
1785 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1786 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1787 return DAG.getBitcast(VT, V);
1788}
1789
1790/// Determine whether a range fits a regular pattern of values.
1791/// This function accounts for the possibility of jumping over the End iterator.
1792template <typename ValType>
1793static bool
1795 unsigned CheckStride,
1797 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1798 auto &I = Begin;
1799
1800 while (I != End) {
1801 if (*I != -1 && *I != ExpectedIndex)
1802 return false;
1803 ExpectedIndex += ExpectedIndexStride;
1804
1805 // Incrementing past End is undefined behaviour so we must increment one
1806 // step at a time and check for End at each step.
1807 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1808 ; // Empty loop body.
1809 }
1810 return true;
1811}
1812
1813/// Compute whether each element of a shuffle is zeroable.
1814///
1815/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1817 SDValue V2, APInt &KnownUndef,
1818 APInt &KnownZero) {
1819 int Size = Mask.size();
1820 KnownUndef = KnownZero = APInt::getZero(Size);
1821
1823 V2 = peekThroughBitcasts(V2);
1824
1825 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1826 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1827
1828 int VectorSizeInBits = V1.getValueSizeInBits();
1829 int ScalarSizeInBits = VectorSizeInBits / Size;
1830 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1831 (void)ScalarSizeInBits;
1832
1833 for (int i = 0; i < Size; ++i) {
1834 int M = Mask[i];
1835 if (M < 0) {
1836 KnownUndef.setBit(i);
1837 continue;
1838 }
1839 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1840 KnownZero.setBit(i);
1841 continue;
1842 }
1843 }
1844}
1845
1846/// Test whether a shuffle mask is equivalent within each sub-lane.
1847///
1848/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1849/// non-trivial to compute in the face of undef lanes. The representation is
1850/// suitable for use with existing 128-bit shuffles as entries from the second
1851/// vector have been remapped to [LaneSize, 2*LaneSize).
1852static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1853 ArrayRef<int> Mask,
1854 SmallVectorImpl<int> &RepeatedMask) {
1855 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1856 RepeatedMask.assign(LaneSize, -1);
1857 int Size = Mask.size();
1858 for (int i = 0; i < Size; ++i) {
1859 assert(Mask[i] == -1 || Mask[i] >= 0);
1860 if (Mask[i] < 0)
1861 continue;
1862 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1863 // This entry crosses lanes, so there is no way to model this shuffle.
1864 return false;
1865
1866 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1867 // Adjust second vector indices to start at LaneSize instead of Size.
1868 int LocalM =
1869 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1870 if (RepeatedMask[i % LaneSize] < 0)
1871 // This is the first non-undef entry in this slot of a 128-bit lane.
1872 RepeatedMask[i % LaneSize] = LocalM;
1873 else if (RepeatedMask[i % LaneSize] != LocalM)
1874 // Found a mismatch with the repeated mask.
1875 return false;
1876 }
1877 return true;
1878}
1879
1880/// Attempts to match vector shuffle as byte rotation.
1882 ArrayRef<int> Mask) {
1883
1884 SDValue Lo, Hi;
1885 SmallVector<int, 16> RepeatedMask;
1886
1887 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1888 return -1;
1889
1890 int NumElts = RepeatedMask.size();
1891 int Rotation = 0;
1892 int Scale = 16 / NumElts;
1893
1894 for (int i = 0; i < NumElts; ++i) {
1895 int M = RepeatedMask[i];
1896 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1897 "Unexpected mask index.");
1898 if (M < 0)
1899 continue;
1900
1901 // Determine where a rotated vector would have started.
1902 int StartIdx = i - (M % NumElts);
1903 if (StartIdx == 0)
1904 return -1;
1905
1906 // If we found the tail of a vector the rotation must be the missing
1907 // front. If we found the head of a vector, it must be how much of the
1908 // head.
1909 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1910
1911 if (Rotation == 0)
1912 Rotation = CandidateRotation;
1913 else if (Rotation != CandidateRotation)
1914 return -1;
1915
1916 // Compute which value this mask is pointing at.
1917 SDValue MaskV = M < NumElts ? V1 : V2;
1918
1919 // Compute which of the two target values this index should be assigned
1920 // to. This reflects whether the high elements are remaining or the low
1921 // elements are remaining.
1922 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1923
1924 // Either set up this value if we've not encountered it before, or check
1925 // that it remains consistent.
1926 if (!TargetV)
1927 TargetV = MaskV;
1928 else if (TargetV != MaskV)
1929 return -1;
1930 }
1931
1932 // Check that we successfully analyzed the mask, and normalize the results.
1933 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1934 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1935 if (!Lo)
1936 Lo = Hi;
1937 else if (!Hi)
1938 Hi = Lo;
1939
1940 V1 = Lo;
1941 V2 = Hi;
1942
1943 return Rotation * Scale;
1944}
1945
1946/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
1947///
1948/// For example:
1949/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
1950/// <2 x i32> <i32 3, i32 0>
1951/// is lowered to:
1952/// (VBSRL_V $v1, $v1, 8)
1953/// (VBSLL_V $v0, $v0, 8)
1954/// (VOR_V $v0, $V0, $v1)
1955static SDValue
1957 SDValue V1, SDValue V2, SelectionDAG &DAG,
1959
1960 SDValue Lo = V1, Hi = V2;
1961 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
1962 if (ByteRotation <= 0)
1963 return SDValue();
1964
1965 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
1966 Lo = DAG.getBitcast(ByteVT, Lo);
1967 Hi = DAG.getBitcast(ByteVT, Hi);
1968
1969 int LoByteShift = 16 - ByteRotation;
1970 int HiByteShift = ByteRotation;
1971 MVT GRLenVT = Subtarget.getGRLenVT();
1972
1973 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
1974 DAG.getConstant(LoByteShift, DL, GRLenVT));
1975 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
1976 DAG.getConstant(HiByteShift, DL, GRLenVT));
1977 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
1978}
1979
1980/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
1981///
1982/// For example:
1983/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1984/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
1985/// %3 = bitcast <4 x i32> %2 to <2 x i64>
1986/// is lowered to:
1987/// (VREPLI $v1, 0)
1988/// (VILVL $v0, $v1, $v0)
1990 ArrayRef<int> Mask, MVT VT,
1991 SDValue V1, SDValue V2,
1992 SelectionDAG &DAG,
1993 const APInt &Zeroable) {
1994 int Bits = VT.getSizeInBits();
1995 int EltBits = VT.getScalarSizeInBits();
1996 int NumElements = VT.getVectorNumElements();
1997
1998 if (Zeroable.isAllOnes())
1999 return DAG.getConstant(0, DL, VT);
2000
2001 // Define a helper function to check a particular ext-scale and lower to it if
2002 // valid.
2003 auto Lower = [&](int Scale) -> SDValue {
2004 SDValue InputV;
2005 bool AnyExt = true;
2006 int Offset = 0;
2007 for (int i = 0; i < NumElements; i++) {
2008 int M = Mask[i];
2009 if (M < 0)
2010 continue;
2011 if (i % Scale != 0) {
2012 // Each of the extended elements need to be zeroable.
2013 if (!Zeroable[i])
2014 return SDValue();
2015
2016 AnyExt = false;
2017 continue;
2018 }
2019
2020 // Each of the base elements needs to be consecutive indices into the
2021 // same input vector.
2022 SDValue V = M < NumElements ? V1 : V2;
2023 M = M % NumElements;
2024 if (!InputV) {
2025 InputV = V;
2026 Offset = M - (i / Scale);
2027
2028 // These offset can't be handled
2029 if (Offset % (NumElements / Scale))
2030 return SDValue();
2031 } else if (InputV != V)
2032 return SDValue();
2033
2034 if (M != (Offset + (i / Scale)))
2035 return SDValue(); // Non-consecutive strided elements.
2036 }
2037
2038 // If we fail to find an input, we have a zero-shuffle which should always
2039 // have already been handled.
2040 if (!InputV)
2041 return SDValue();
2042
2043 do {
2044 unsigned VilVLoHi = LoongArchISD::VILVL;
2045 if (Offset >= (NumElements / 2)) {
2046 VilVLoHi = LoongArchISD::VILVH;
2047 Offset -= (NumElements / 2);
2048 }
2049
2050 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2051 SDValue Ext =
2052 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2053 InputV = DAG.getBitcast(InputVT, InputV);
2054 Ext = DAG.getBitcast(InputVT, Ext);
2055 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2056 Scale /= 2;
2057 EltBits *= 2;
2058 NumElements /= 2;
2059 } while (Scale > 1);
2060 return DAG.getBitcast(VT, InputV);
2061 };
2062
2063 // Each iteration, try extending the elements half as much, but into twice as
2064 // many elements.
2065 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2066 NumExtElements *= 2) {
2067 if (SDValue V = Lower(NumElements / NumExtElements))
2068 return V;
2069 }
2070 return SDValue();
2071}
2072
2073/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2074///
2075/// VREPLVEI performs vector broadcast based on an element specified by an
2076/// integer immediate, with its mask being similar to:
2077/// <x, x, x, ...>
2078/// where x is any valid index.
2079///
2080/// When undef's appear in the mask they are treated as if they were whatever
2081/// value is necessary in order to fit the above form.
2082static SDValue
2084 SDValue V1, SelectionDAG &DAG,
2086 int SplatIndex = -1;
2087 for (const auto &M : Mask) {
2088 if (M != -1) {
2089 SplatIndex = M;
2090 break;
2091 }
2092 }
2093
2094 if (SplatIndex == -1)
2095 return DAG.getUNDEF(VT);
2096
2097 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2098 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2099 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2100 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2101 }
2102
2103 return SDValue();
2104}
2105
2106/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2107///
2108/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2109/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2110///
2111/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2112/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2113/// When undef's appear they are treated as if they were whatever value is
2114/// necessary in order to fit the above forms.
2115///
2116/// For example:
2117/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2118/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2119/// i32 7, i32 6, i32 5, i32 4>
2120/// is lowered to:
2121/// (VSHUF4I_H $v0, $v1, 27)
2122/// where the 27 comes from:
2123/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2124static SDValue
2126 SDValue V1, SDValue V2, SelectionDAG &DAG,
2128
2129 unsigned SubVecSize = 4;
2130 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2131 SubVecSize = 2;
2132
2133 int SubMask[4] = {-1, -1, -1, -1};
2134 for (unsigned i = 0; i < SubVecSize; ++i) {
2135 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2136 int M = Mask[j];
2137
2138 // Convert from vector index to 4-element subvector index
2139 // If an index refers to an element outside of the subvector then give up
2140 if (M != -1) {
2141 M -= 4 * (j / SubVecSize);
2142 if (M < 0 || M >= 4)
2143 return SDValue();
2144 }
2145
2146 // If the mask has an undef, replace it with the current index.
2147 // Note that it might still be undef if the current index is also undef
2148 if (SubMask[i] == -1)
2149 SubMask[i] = M;
2150 // Check that non-undef values are the same as in the mask. If they
2151 // aren't then give up
2152 else if (M != -1 && M != SubMask[i])
2153 return SDValue();
2154 }
2155 }
2156
2157 // Calculate the immediate. Replace any remaining undefs with zero
2158 int Imm = 0;
2159 for (int i = SubVecSize - 1; i >= 0; --i) {
2160 int M = SubMask[i];
2161
2162 if (M == -1)
2163 M = 0;
2164
2165 Imm <<= 2;
2166 Imm |= M & 0x3;
2167 }
2168
2169 MVT GRLenVT = Subtarget.getGRLenVT();
2170
2171 // Return vshuf4i.d
2172 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2173 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2174 DAG.getConstant(Imm, DL, GRLenVT));
2175
2176 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2177 DAG.getConstant(Imm, DL, GRLenVT));
2178}
2179
2180/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2181///
2182/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2183/// reverse whose mask likes:
2184/// <7, 6, 5, 4, 3, 2, 1, 0>
2185///
2186/// When undef's appear in the mask they are treated as if they were whatever
2187/// value is necessary in order to fit the above forms.
2188static SDValue
2190 SDValue V1, SelectionDAG &DAG,
2192 // Only vectors with i8/i16 elements which cannot match other patterns
2193 // directly needs to do this.
2194 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2195 VT != MVT::v16i16)
2196 return SDValue();
2197
2198 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2199 return SDValue();
2200
2201 int WidenNumElts = VT.getVectorNumElements() / 4;
2202 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2203 for (int i = 0; i < WidenNumElts; ++i)
2204 WidenMask[i] = WidenNumElts - 1 - i;
2205
2206 MVT WidenVT = MVT::getVectorVT(
2207 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2208 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2209 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2210 DAG.getUNDEF(WidenVT), WidenMask);
2211
2212 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2213 DAG.getBitcast(VT, WidenRev),
2214 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2215}
2216
2217/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2218///
2219/// VPACKEV interleaves the even elements from each vector.
2220///
2221/// It is possible to lower into VPACKEV when the mask consists of two of the
2222/// following forms interleaved:
2223/// <0, 2, 4, ...>
2224/// <n, n+2, n+4, ...>
2225/// where n is the number of elements in the vector.
2226/// For example:
2227/// <0, 0, 2, 2, 4, 4, ...>
2228/// <0, n, 2, n+2, 4, n+4, ...>
2229///
2230/// When undef's appear in the mask they are treated as if they were whatever
2231/// value is necessary in order to fit the above forms.
2233 MVT VT, SDValue V1, SDValue V2,
2234 SelectionDAG &DAG) {
2235
2236 const auto &Begin = Mask.begin();
2237 const auto &End = Mask.end();
2238 SDValue OriV1 = V1, OriV2 = V2;
2239
2240 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2241 V1 = OriV1;
2242 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2243 V1 = OriV2;
2244 else
2245 return SDValue();
2246
2247 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2248 V2 = OriV1;
2249 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2250 V2 = OriV2;
2251 else
2252 return SDValue();
2253
2254 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2255}
2256
2257/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2258///
2259/// VPACKOD interleaves the odd elements from each vector.
2260///
2261/// It is possible to lower into VPACKOD when the mask consists of two of the
2262/// following forms interleaved:
2263/// <1, 3, 5, ...>
2264/// <n+1, n+3, n+5, ...>
2265/// where n is the number of elements in the vector.
2266/// For example:
2267/// <1, 1, 3, 3, 5, 5, ...>
2268/// <1, n+1, 3, n+3, 5, n+5, ...>
2269///
2270/// When undef's appear in the mask they are treated as if they were whatever
2271/// value is necessary in order to fit the above forms.
2273 MVT VT, SDValue V1, SDValue V2,
2274 SelectionDAG &DAG) {
2275
2276 const auto &Begin = Mask.begin();
2277 const auto &End = Mask.end();
2278 SDValue OriV1 = V1, OriV2 = V2;
2279
2280 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2281 V1 = OriV1;
2282 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2283 V1 = OriV2;
2284 else
2285 return SDValue();
2286
2287 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2288 V2 = OriV1;
2289 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2290 V2 = OriV2;
2291 else
2292 return SDValue();
2293
2294 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2295}
2296
2297/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2298///
2299/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2300/// of each vector.
2301///
2302/// It is possible to lower into VILVH when the mask consists of two of the
2303/// following forms interleaved:
2304/// <x, x+1, x+2, ...>
2305/// <n+x, n+x+1, n+x+2, ...>
2306/// where n is the number of elements in the vector and x is half n.
2307/// For example:
2308/// <x, x, x+1, x+1, x+2, x+2, ...>
2309/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2310///
2311/// When undef's appear in the mask they are treated as if they were whatever
2312/// value is necessary in order to fit the above forms.
2314 MVT VT, SDValue V1, SDValue V2,
2315 SelectionDAG &DAG) {
2316
2317 const auto &Begin = Mask.begin();
2318 const auto &End = Mask.end();
2319 unsigned HalfSize = Mask.size() / 2;
2320 SDValue OriV1 = V1, OriV2 = V2;
2321
2322 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2323 V1 = OriV1;
2324 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2325 V1 = OriV2;
2326 else
2327 return SDValue();
2328
2329 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2330 V2 = OriV1;
2331 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2332 1))
2333 V2 = OriV2;
2334 else
2335 return SDValue();
2336
2337 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2338}
2339
2340/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2341///
2342/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2343/// of each vector.
2344///
2345/// It is possible to lower into VILVL when the mask consists of two of the
2346/// following forms interleaved:
2347/// <0, 1, 2, ...>
2348/// <n, n+1, n+2, ...>
2349/// where n is the number of elements in the vector.
2350/// For example:
2351/// <0, 0, 1, 1, 2, 2, ...>
2352/// <0, n, 1, n+1, 2, n+2, ...>
2353///
2354/// When undef's appear in the mask they are treated as if they were whatever
2355/// value is necessary in order to fit the above forms.
2357 MVT VT, SDValue V1, SDValue V2,
2358 SelectionDAG &DAG) {
2359
2360 const auto &Begin = Mask.begin();
2361 const auto &End = Mask.end();
2362 SDValue OriV1 = V1, OriV2 = V2;
2363
2364 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2365 V1 = OriV1;
2366 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2367 V1 = OriV2;
2368 else
2369 return SDValue();
2370
2371 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2372 V2 = OriV1;
2373 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2374 V2 = OriV2;
2375 else
2376 return SDValue();
2377
2378 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2379}
2380
2381/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2382///
2383/// VPICKEV copies the even elements of each vector into the result vector.
2384///
2385/// It is possible to lower into VPICKEV when the mask consists of two of the
2386/// following forms concatenated:
2387/// <0, 2, 4, ...>
2388/// <n, n+2, n+4, ...>
2389/// where n is the number of elements in the vector.
2390/// For example:
2391/// <0, 2, 4, ..., 0, 2, 4, ...>
2392/// <0, 2, 4, ..., n, n+2, n+4, ...>
2393///
2394/// When undef's appear in the mask they are treated as if they were whatever
2395/// value is necessary in order to fit the above forms.
2397 MVT VT, SDValue V1, SDValue V2,
2398 SelectionDAG &DAG) {
2399
2400 const auto &Begin = Mask.begin();
2401 const auto &Mid = Mask.begin() + Mask.size() / 2;
2402 const auto &End = Mask.end();
2403 SDValue OriV1 = V1, OriV2 = V2;
2404
2405 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2406 V1 = OriV1;
2407 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2408 V1 = OriV2;
2409 else
2410 return SDValue();
2411
2412 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2413 V2 = OriV1;
2414 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2415 V2 = OriV2;
2416
2417 else
2418 return SDValue();
2419
2420 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2421}
2422
2423/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2424///
2425/// VPICKOD copies the odd elements of each vector into the result vector.
2426///
2427/// It is possible to lower into VPICKOD when the mask consists of two of the
2428/// following forms concatenated:
2429/// <1, 3, 5, ...>
2430/// <n+1, n+3, n+5, ...>
2431/// where n is the number of elements in the vector.
2432/// For example:
2433/// <1, 3, 5, ..., 1, 3, 5, ...>
2434/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2435///
2436/// When undef's appear in the mask they are treated as if they were whatever
2437/// value is necessary in order to fit the above forms.
2439 MVT VT, SDValue V1, SDValue V2,
2440 SelectionDAG &DAG) {
2441
2442 const auto &Begin = Mask.begin();
2443 const auto &Mid = Mask.begin() + Mask.size() / 2;
2444 const auto &End = Mask.end();
2445 SDValue OriV1 = V1, OriV2 = V2;
2446
2447 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2448 V1 = OriV1;
2449 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2450 V1 = OriV2;
2451 else
2452 return SDValue();
2453
2454 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2455 V2 = OriV1;
2456 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2457 V2 = OriV2;
2458 else
2459 return SDValue();
2460
2461 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2462}
2463
2464/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2465///
2466/// VEXTRINS copies one element of a vector into any place of the result
2467/// vector and makes no change to the rest elements of the result vector.
2468///
2469/// It is possible to lower into VEXTRINS when the mask takes the form:
2470/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2471/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2472/// where n is the number of elements in the vector and i is in [0, n).
2473/// For example:
2474/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2475/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2476///
2477/// When undef's appear in the mask they are treated as if they were whatever
2478/// value is necessary in order to fit the above forms.
2479static SDValue
2481 SDValue V1, SDValue V2, SelectionDAG &DAG,
2483 unsigned NumElts = VT.getVectorNumElements();
2484 MVT EltVT = VT.getVectorElementType();
2485 MVT GRLenVT = Subtarget.getGRLenVT();
2486
2487 if (Mask.size() != NumElts)
2488 return SDValue();
2489
2490 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2491 int DiffCount = 0;
2492 int DiffPos = -1;
2493 for (unsigned i = 0; i < NumElts; ++i) {
2494 if (Mask[i] == -1)
2495 continue;
2496 if (Mask[i] != int(Base + i)) {
2497 ++DiffCount;
2498 DiffPos = int(i);
2499 if (DiffCount > 1)
2500 return SDValue();
2501 }
2502 }
2503
2504 // Need exactly one differing element to lower into VEXTRINS.
2505 if (DiffCount != 1)
2506 return SDValue();
2507
2508 // DiffMask must be in [0, 2N).
2509 int DiffMask = Mask[DiffPos];
2510 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2511 return SDValue();
2512
2513 // Determine source vector and source index.
2514 SDValue SrcVec;
2515 unsigned SrcIdx;
2516 if (unsigned(DiffMask) < NumElts) {
2517 SrcVec = V1;
2518 SrcIdx = unsigned(DiffMask);
2519 } else {
2520 SrcVec = V2;
2521 SrcIdx = unsigned(DiffMask) - NumElts;
2522 }
2523
2524 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2525 // patterns of VEXTRINS in tablegen.
2526 SDValue Extracted = DAG.getNode(
2527 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2528 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2529 SDValue Result =
2530 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2531 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2532
2533 return Result;
2534 };
2535
2536 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2537 if (SDValue Result = tryLowerToExtrAndIns(0))
2538 return Result;
2539 return tryLowerToExtrAndIns(NumElts);
2540}
2541
2542// Check the Mask and then build SrcVec and MaskImm infos which will
2543// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2544// On success, return true. Otherwise, return false.
2547 unsigned &MaskImm) {
2548 unsigned MaskSize = Mask.size();
2549
2550 auto isValid = [&](int M, int Off) {
2551 return (M == -1) || (M >= Off && M < Off + 4);
2552 };
2553
2554 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2555 auto immPart = [&](int M, unsigned Off) {
2556 return (M == -1 ? 0 : (M - Off)) & 0x3;
2557 };
2558 MaskImm |= immPart(MLo, Off) << (I * 2);
2559 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2560 };
2561
2562 for (unsigned i = 0; i < 4; i += 2) {
2563 int MLo = Mask[i];
2564 int MHi = Mask[i + 1];
2565
2566 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2567 auto isValid2 = [&](int &M, int M2) {
2568 // If high half index is undef, it's always valid.
2569 if (M2 == -1)
2570 return true;
2571 if (M == -1) {
2572 // If low half index is undef, use index from high half,
2573 // remapped to low half.
2574 if ((M2 % MaskSize) < 4)
2575 return false;
2576 M = M2 - 4;
2577 return true;
2578 }
2579 // Index in low half must be same as index in high half.
2580 return M2 == M + 4;
2581 };
2582 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2583 return false;
2584 }
2585
2586 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2587 SrcVec.push_back(V1);
2588 buildImm(MLo, MHi, 0, i);
2589 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2590 SrcVec.push_back(V2);
2591 buildImm(MLo, MHi, MaskSize, i);
2592 } else {
2593 return false;
2594 }
2595 }
2596
2597 return true;
2598}
2599
2600/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2601///
2602/// VPERMI selects two elements from each of the two vectors based on the
2603/// mask and places them in the corresponding positions of the result vector
2604/// in order. Only v4i32 and v4f32 types are allowed.
2605///
2606/// It is possible to lower into VPERMI when the mask consists of two of the
2607/// following forms concatenated:
2608/// <i, j, u, v>
2609/// <u, v, i, j>
2610/// where i,j are in [0,4) and u,v are in [4, 8).
2611/// For example:
2612/// <2, 3, 4, 5>
2613/// <5, 7, 0, 2>
2614///
2615/// When undef's appear in the mask they are treated as if they were whatever
2616/// value is necessary in order to fit the above forms.
2618 MVT VT, SDValue V1, SDValue V2,
2619 SelectionDAG &DAG,
2621 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2622 Mask.size() != VT.getVectorNumElements())
2623 return SDValue();
2624
2626 unsigned MaskImm = 0;
2627 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2628 return SDValue();
2629
2630 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2631 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2632}
2633
2634/// Lower VECTOR_SHUFFLE into VSHUF.
2635///
2636/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2637/// adding it as an operand to the resulting VSHUF.
2639 MVT VT, SDValue V1, SDValue V2,
2640 SelectionDAG &DAG,
2642
2644 for (auto M : Mask)
2645 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2646
2647 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2648 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2649
2650 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2651 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2652 // VSHF concatenates the vectors in a bitwise fashion:
2653 // <0b00, 0b01> + <0b10, 0b11> ->
2654 // 0b0100 + 0b1110 -> 0b01001110
2655 // <0b10, 0b11, 0b00, 0b01>
2656 // We must therefore swap the operands to get the correct result.
2657 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2658}
2659
2660/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2661///
2662/// This routine breaks down the specific type of 128-bit shuffle and
2663/// dispatches to the lowering routines accordingly.
2665 SDValue V1, SDValue V2, SelectionDAG &DAG,
2667 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2668 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2669 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2670 "Vector type is unsupported for lsx!");
2671 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2672 "Two operands have different types!");
2673 assert(VT.getVectorNumElements() == Mask.size() &&
2674 "Unexpected mask size for shuffle!");
2675 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2676
2677 APInt KnownUndef, KnownZero;
2678 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2679 APInt Zeroable = KnownUndef | KnownZero;
2680
2681 SDValue Result;
2682 // TODO: Add more comparison patterns.
2683 if (V2.isUndef()) {
2684 if ((Result =
2685 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2686 return Result;
2687 if ((Result =
2688 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2689 return Result;
2690 if ((Result =
2691 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2692 return Result;
2693
2694 // TODO: This comment may be enabled in the future to better match the
2695 // pattern for instruction selection.
2696 /* V2 = V1; */
2697 }
2698
2699 // It is recommended not to change the pattern comparison order for better
2700 // performance.
2701 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2702 return Result;
2703 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2704 return Result;
2705 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2706 return Result;
2707 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2708 return Result;
2709 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2710 return Result;
2711 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2712 return Result;
2713 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2714 (Result =
2715 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2716 return Result;
2717 if ((Result =
2718 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2719 return Result;
2720 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2721 Zeroable)))
2722 return Result;
2723 if ((Result =
2724 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2725 return Result;
2726 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2727 Zeroable)))
2728 return Result;
2729 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2730 Subtarget)))
2731 return Result;
2732 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2733 return NewShuffle;
2734 if ((Result =
2735 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2736 return Result;
2737 return SDValue();
2738}
2739
2740/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2741///
2742/// It is a XVREPLVEI when the mask is:
2743/// <x, x, x, ..., x+n, x+n, x+n, ...>
2744/// where the number of x is equal to n and n is half the length of vector.
2745///
2746/// When undef's appear in the mask they are treated as if they were whatever
2747/// value is necessary in order to fit the above form.
2748static SDValue
2750 SDValue V1, SelectionDAG &DAG,
2752 int SplatIndex = -1;
2753 for (const auto &M : Mask) {
2754 if (M != -1) {
2755 SplatIndex = M;
2756 break;
2757 }
2758 }
2759
2760 if (SplatIndex == -1)
2761 return DAG.getUNDEF(VT);
2762
2763 const auto &Begin = Mask.begin();
2764 const auto &End = Mask.end();
2765 int HalfSize = Mask.size() / 2;
2766
2767 if (SplatIndex >= HalfSize)
2768 return SDValue();
2769
2770 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2771 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2772 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2773 0)) {
2774 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2775 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2776 }
2777
2778 return SDValue();
2779}
2780
2781/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2782static SDValue
2784 SDValue V1, SDValue V2, SelectionDAG &DAG,
2786 // XVSHUF4I_D must be handled separately because it is different from other
2787 // types of [X]VSHUF4I instructions.
2788 if (Mask.size() == 4) {
2789 unsigned MaskImm = 0;
2790 for (int i = 1; i >= 0; --i) {
2791 int MLo = Mask[i];
2792 int MHi = Mask[i + 2];
2793 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2794 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2795 return SDValue();
2796 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2797 return SDValue();
2798
2799 MaskImm <<= 2;
2800 if (MLo != -1)
2801 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2802 else if (MHi != -1)
2803 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2804 }
2805
2806 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2807 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2808 }
2809
2810 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2811}
2812
2813/// Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
2814///
2815/// It is a XVREPLVE0 when the VECTOR_SHUFFLE is a broadcast of element 0,
2816/// i.e. the mask is:
2817/// <0, 0, 0, ...>
2818///
2819/// When undef's appear in the mask they are treated as if they were whatever
2820/// value is necessary in order to fit the above form.
2822 ArrayRef<int> Mask, MVT VT,
2823 SDValue V1, SelectionDAG &DAG) {
2824 if (!ShuffleVectorInst::isZeroEltSplatMask(Mask, Mask.size()))
2825 return SDValue();
2826
2827 return DAG.getNode(LoongArchISD::XVREPLVE0, DL, VT, V1);
2828}
2829
2830/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2831static SDValue
2833 SDValue V1, SDValue V2, SelectionDAG &DAG,
2835 MVT GRLenVT = Subtarget.getGRLenVT();
2836 unsigned MaskSize = Mask.size();
2837 if (MaskSize != VT.getVectorNumElements())
2838 return SDValue();
2839
2840 // Consider XVPERMI_W.
2841 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2843 unsigned MaskImm = 0;
2844 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2845 return SDValue();
2846
2847 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2848 DAG.getConstant(MaskImm, DL, GRLenVT));
2849 }
2850
2851 // Consider XVPERMI_D.
2852 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2853 unsigned MaskImm = 0;
2854 for (unsigned i = 0; i < MaskSize; ++i) {
2855 if (Mask[i] == -1)
2856 continue;
2857 if (Mask[i] >= (int)MaskSize)
2858 return SDValue();
2859 MaskImm |= Mask[i] << (i * 2);
2860 }
2861
2862 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2863 DAG.getConstant(MaskImm, DL, GRLenVT));
2864 }
2865
2866 return SDValue();
2867}
2868
2869/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2871 MVT VT, SDValue V1, SelectionDAG &DAG,
2873 // LoongArch LASX only have XVPERM_W.
2874 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2875 return SDValue();
2876
2877 unsigned NumElts = VT.getVectorNumElements();
2878 unsigned HalfSize = NumElts / 2;
2879 bool FrontLo = true, FrontHi = true;
2880 bool BackLo = true, BackHi = true;
2881
2882 auto inRange = [](int val, int low, int high) {
2883 return (val == -1) || (val >= low && val < high);
2884 };
2885
2886 for (unsigned i = 0; i < HalfSize; ++i) {
2887 int Fronti = Mask[i];
2888 int Backi = Mask[i + HalfSize];
2889
2890 FrontLo &= inRange(Fronti, 0, HalfSize);
2891 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2892 BackLo &= inRange(Backi, 0, HalfSize);
2893 BackHi &= inRange(Backi, HalfSize, NumElts);
2894 }
2895
2896 // If both the lower and upper 128-bit parts access only one half of the
2897 // vector (either lower or upper), avoid using xvperm.w. The latency of
2898 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2899 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2900 return SDValue();
2901
2903 MVT GRLenVT = Subtarget.getGRLenVT();
2904 for (unsigned i = 0; i < NumElts; ++i)
2905 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2906 : DAG.getConstant(Mask[i], DL, GRLenVT));
2907 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2908
2909 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2910}
2911
2912/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2914 MVT VT, SDValue V1, SDValue V2,
2915 SelectionDAG &DAG) {
2916 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2917}
2918
2919/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2921 MVT VT, SDValue V1, SDValue V2,
2922 SelectionDAG &DAG) {
2923 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2924}
2925
2926/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2928 MVT VT, SDValue V1, SDValue V2,
2929 SelectionDAG &DAG) {
2930
2931 const auto &Begin = Mask.begin();
2932 const auto &End = Mask.end();
2933 unsigned HalfSize = Mask.size() / 2;
2934 unsigned LeftSize = HalfSize / 2;
2935 SDValue OriV1 = V1, OriV2 = V2;
2936
2937 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2938 1) &&
2939 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2940 V1 = OriV1;
2941 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2942 Mask.size() + HalfSize - LeftSize, 1) &&
2943 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2944 Mask.size() + HalfSize + LeftSize, 1))
2945 V1 = OriV2;
2946 else
2947 return SDValue();
2948
2949 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
2950 1) &&
2951 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
2952 1))
2953 V2 = OriV1;
2954 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
2955 Mask.size() + HalfSize - LeftSize, 1) &&
2956 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2957 Mask.size() + HalfSize + LeftSize, 1))
2958 V2 = OriV2;
2959 else
2960 return SDValue();
2961
2962 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2963}
2964
2965/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
2967 MVT VT, SDValue V1, SDValue V2,
2968 SelectionDAG &DAG) {
2969
2970 const auto &Begin = Mask.begin();
2971 const auto &End = Mask.end();
2972 unsigned HalfSize = Mask.size() / 2;
2973 SDValue OriV1 = V1, OriV2 = V2;
2974
2975 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
2976 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
2977 V1 = OriV1;
2978 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
2979 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2980 Mask.size() + HalfSize, 1))
2981 V1 = OriV2;
2982 else
2983 return SDValue();
2984
2985 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
2986 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
2987 V2 = OriV1;
2988 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
2989 1) &&
2990 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2991 Mask.size() + HalfSize, 1))
2992 V2 = OriV2;
2993 else
2994 return SDValue();
2995
2996 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2997}
2998
2999/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
3001 MVT VT, SDValue V1, SDValue V2,
3002 SelectionDAG &DAG) {
3003
3004 const auto &Begin = Mask.begin();
3005 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3006 const auto &Mid = Mask.begin() + Mask.size() / 2;
3007 const auto &RightMid = Mask.end() - Mask.size() / 4;
3008 const auto &End = Mask.end();
3009 unsigned HalfSize = Mask.size() / 2;
3010 SDValue OriV1 = V1, OriV2 = V2;
3011
3012 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
3013 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
3014 V1 = OriV1;
3015 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
3016 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
3017 V1 = OriV2;
3018 else
3019 return SDValue();
3020
3021 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
3022 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
3023 V2 = OriV1;
3024 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
3025 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
3026 V2 = OriV2;
3027
3028 else
3029 return SDValue();
3030
3031 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
3032}
3033
3034/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
3036 MVT VT, SDValue V1, SDValue V2,
3037 SelectionDAG &DAG) {
3038
3039 const auto &Begin = Mask.begin();
3040 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3041 const auto &Mid = Mask.begin() + Mask.size() / 2;
3042 const auto &RightMid = Mask.end() - Mask.size() / 4;
3043 const auto &End = Mask.end();
3044 unsigned HalfSize = Mask.size() / 2;
3045 SDValue OriV1 = V1, OriV2 = V2;
3046
3047 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
3048 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
3049 V1 = OriV1;
3050 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3051 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3052 2))
3053 V1 = OriV2;
3054 else
3055 return SDValue();
3056
3057 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3058 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3059 V2 = OriV1;
3060 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3061 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3062 2))
3063 V2 = OriV2;
3064 else
3065 return SDValue();
3066
3067 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3068}
3069
3070/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3071static SDValue
3073 SDValue V1, SDValue V2, SelectionDAG &DAG,
3075 int NumElts = VT.getVectorNumElements();
3076 int HalfSize = NumElts / 2;
3077 MVT EltVT = VT.getVectorElementType();
3078 MVT GRLenVT = Subtarget.getGRLenVT();
3079
3080 if ((int)Mask.size() != NumElts)
3081 return SDValue();
3082
3083 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3084 SmallVector<int> DiffPos;
3085 for (int i = 0; i < NumElts; ++i) {
3086 if (Mask[i] == -1)
3087 continue;
3088 if (Mask[i] != Base + i) {
3089 DiffPos.push_back(i);
3090 if (DiffPos.size() > 2)
3091 return SDValue();
3092 }
3093 }
3094
3095 // Need exactly two differing element to lower into XVEXTRINS.
3096 // If only one differing element, the element at a distance of
3097 // HalfSize from it must be undef.
3098 if (DiffPos.size() == 1) {
3099 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3100 DiffPos.push_back(DiffPos[0] + HalfSize);
3101 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3102 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3103 else
3104 return SDValue();
3105 }
3106 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3107 return SDValue();
3108
3109 // DiffMask must be in its low or high part.
3110 int DiffMaskLo = Mask[DiffPos[0]];
3111 int DiffMaskHi = Mask[DiffPos[1]];
3112 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3113 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3114 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3115 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3116 return SDValue();
3117 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3118 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3119 return SDValue();
3120 if (DiffMaskHi != DiffMaskLo + HalfSize)
3121 return SDValue();
3122
3123 // Determine source vector and source index.
3124 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3125 int SrcIdxLo =
3126 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3127 bool IsEltFP = EltVT.isFloatingPoint();
3128
3129 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3130 // the patterns of XVEXTRINS in tablegen.
3131 SDValue BaseVec = (Base == 0) ? V1 : V2;
3132 SDValue EltLo =
3133 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3134 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3135 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3136 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3137 SDValue EltHi =
3138 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3139 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3140 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3141 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3142
3143 return Result;
3144 };
3145
3146 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3147 if (SDValue Result = tryLowerToExtrAndIns(0))
3148 return Result;
3149 return tryLowerToExtrAndIns(NumElts);
3150}
3151
3152/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3153static SDValue
3155 SDValue V1, SDValue V2, SelectionDAG &DAG,
3157 // LoongArch LASX only supports xvinsve0.{w/d}.
3158 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3159 VT != MVT::v4f64)
3160 return SDValue();
3161
3162 MVT GRLenVT = Subtarget.getGRLenVT();
3163 int MaskSize = Mask.size();
3164 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3165
3166 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3167 // all other elements are either 'Base + i' or undef (-1). On success, return
3168 // the index of the replaced element. Otherwise, just return -1.
3169 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3170 int Idx = -1;
3171 for (int i = 0; i < MaskSize; ++i) {
3172 if (Mask[i] == Base + i || Mask[i] == -1)
3173 continue;
3174 if (Mask[i] != Replaced)
3175 return -1;
3176 if (Idx == -1)
3177 Idx = i;
3178 else
3179 return -1;
3180 }
3181 return Idx;
3182 };
3183
3184 // Case 1: the lowest element of V2 replaces one element in V1.
3185 int Idx = checkReplaceOne(0, MaskSize);
3186 if (Idx != -1)
3187 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3188 DAG.getConstant(Idx, DL, GRLenVT));
3189
3190 // Case 2: the lowest element of V1 replaces one element in V2.
3191 Idx = checkReplaceOne(MaskSize, 0);
3192 if (Idx != -1)
3193 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3194 DAG.getConstant(Idx, DL, GRLenVT));
3195
3196 return SDValue();
3197}
3198
3199/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3201 MVT VT, SDValue V1, SDValue V2,
3202 SelectionDAG &DAG) {
3203
3204 int MaskSize = Mask.size();
3205 int HalfSize = Mask.size() / 2;
3206 const auto &Begin = Mask.begin();
3207 const auto &Mid = Mask.begin() + HalfSize;
3208 const auto &End = Mask.end();
3209
3210 // VECTOR_SHUFFLE concatenates the vectors:
3211 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3212 // shuffling ->
3213 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3214 //
3215 // XVSHUF concatenates the vectors:
3216 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3217 // shuffling ->
3218 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3219 SmallVector<SDValue, 8> MaskAlloc;
3220 for (auto it = Begin; it < Mid; it++) {
3221 if (*it < 0) // UNDEF
3222 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3223 else if ((*it >= 0 && *it < HalfSize) ||
3224 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3225 int M = *it < HalfSize ? *it : *it - HalfSize;
3226 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3227 } else
3228 return SDValue();
3229 }
3230 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3231
3232 for (auto it = Mid; it < End; it++) {
3233 if (*it < 0) // UNDEF
3234 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3235 else if ((*it >= HalfSize && *it < MaskSize) ||
3236 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3237 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3238 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3239 } else
3240 return SDValue();
3241 }
3242 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3243
3244 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3245 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3246 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3247}
3248
3249/// Shuffle vectors by lane to generate more optimized instructions.
3250/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3251///
3252/// Therefore, except for the following four cases, other cases are regarded
3253/// as cross-lane shuffles, where optimization is relatively limited.
3254///
3255/// - Shuffle high, low lanes of two inputs vector
3256/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3257/// - Shuffle low, high lanes of two inputs vector
3258/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3259/// - Shuffle low, low lanes of two inputs vector
3260/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3261/// - Shuffle high, high lanes of two inputs vector
3262/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3263///
3264/// The first case is the closest to LoongArch instructions and the other
3265/// cases need to be converted to it for processing.
3266///
3267/// This function will return true for the last three cases above and will
3268/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3269/// cross-lane shuffle cases.
3271 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3273
3274 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3275
3276 int MaskSize = Mask.size();
3277 int HalfSize = Mask.size() / 2;
3278 MVT GRLenVT = Subtarget.getGRLenVT();
3279
3280 HalfMaskType preMask = None, postMask = None;
3281
3282 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3283 return M < 0 || (M >= 0 && M < HalfSize) ||
3284 (M >= MaskSize && M < MaskSize + HalfSize);
3285 }))
3286 preMask = HighLaneTy;
3287 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3288 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3289 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3290 }))
3291 preMask = LowLaneTy;
3292
3293 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3294 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3295 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3296 }))
3297 postMask = LowLaneTy;
3298 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3299 return M < 0 || (M >= 0 && M < HalfSize) ||
3300 (M >= MaskSize && M < MaskSize + HalfSize);
3301 }))
3302 postMask = HighLaneTy;
3303
3304 // The pre-half of mask is high lane type, and the post-half of mask
3305 // is low lane type, which is closest to the LoongArch instructions.
3306 //
3307 // Note: In the LoongArch architecture, the high lane of mask corresponds
3308 // to the lower 128-bit of vector register, and the low lane of mask
3309 // corresponds the higher 128-bit of vector register.
3310 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3311 return false;
3312 }
3313 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3314 V1 = DAG.getBitcast(MVT::v4i64, V1);
3315 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3316 DAG.getConstant(0b01001110, DL, GRLenVT));
3317 V1 = DAG.getBitcast(VT, V1);
3318
3319 if (!V2.isUndef()) {
3320 V2 = DAG.getBitcast(MVT::v4i64, V2);
3321 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3322 DAG.getConstant(0b01001110, DL, GRLenVT));
3323 V2 = DAG.getBitcast(VT, V2);
3324 }
3325
3326 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3327 *it = *it < 0 ? *it : *it - HalfSize;
3328 }
3329 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3330 *it = *it < 0 ? *it : *it + HalfSize;
3331 }
3332 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3333 V1 = DAG.getBitcast(MVT::v4i64, V1);
3334 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3335 DAG.getConstant(0b11101110, DL, GRLenVT));
3336 V1 = DAG.getBitcast(VT, V1);
3337
3338 if (!V2.isUndef()) {
3339 V2 = DAG.getBitcast(MVT::v4i64, V2);
3340 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3341 DAG.getConstant(0b11101110, DL, GRLenVT));
3342 V2 = DAG.getBitcast(VT, V2);
3343 }
3344
3345 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3346 *it = *it < 0 ? *it : *it - HalfSize;
3347 }
3348 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3349 V1 = DAG.getBitcast(MVT::v4i64, V1);
3350 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3351 DAG.getConstant(0b01000100, DL, GRLenVT));
3352 V1 = DAG.getBitcast(VT, V1);
3353
3354 if (!V2.isUndef()) {
3355 V2 = DAG.getBitcast(MVT::v4i64, V2);
3356 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3357 DAG.getConstant(0b01000100, DL, GRLenVT));
3358 V2 = DAG.getBitcast(VT, V2);
3359 }
3360
3361 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3362 *it = *it < 0 ? *it : *it + HalfSize;
3363 }
3364 } else { // cross-lane
3365 return false;
3366 }
3367
3368 return true;
3369}
3370
3371/// Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
3372///
3373/// For example:
3374/// %2 = shufflevector <4 x i64> %0, <4 x i64> %1,
3375/// <4 x i32> <i32 2, i32 3, i32 4, i32 5>
3376/// is lowered to:
3377/// (XVPERMI_Q $xr1, $xr0, 33)
3378static SDValue
3380 SDValue V1, SDValue V2, SelectionDAG &DAG,
3382 // Each 128-bit lane of the result must be a whole lane of V1 or V2.
3383 SmallVector<int, 2> LaneMask;
3384 if (!widenShuffleMaskElts(Mask.size() / 2, Mask, LaneMask))
3385 return SDValue();
3386
3387 // Lanes 0-3 are V1.lo, V1.hi, V2.lo and V2.hi, the same as the XVPERMI_Q
3388 // selector with xj = V1 and xd = V2.
3389 int Lo = LaneMask[0] < 0 ? 0 : LaneMask[0];
3390 int Hi = LaneMask[1] < 0 ? 1 : LaneMask[1];
3391 return DAG.getNode(
3392 LoongArchISD::XVPERMIQ, DL, VT, V2, V1,
3393 DAG.getConstant(Lo | (Hi << 4), DL, Subtarget.getGRLenVT()));
3394}
3395
3396/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3397/// Only for 256-bit vector.
3398///
3399/// Each 128-bit lane of the result may use at most two lanes of the inputs.
3400/// These lanes are first moved into place, then shuffled within the lane.
3401///
3402/// For example:
3403/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3404/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3405/// is lowerded to:
3406/// (XVPERMI $xr2, $xr0, 78)
3407/// (XVSHUF $xr1, $xr2, $xr0)
3408/// (XVORI $xr0, $xr1, 0)
3409///
3410/// and the splice:
3411/// %2 = shufflevector <8 x i32> %0, <8 x i32> %1,
3412/// <8 x i32> <i32 7, i32 8, i32 9, i32 10,
3413/// i32 11, i32 12, i32 13, i32 14>
3414/// is lowered to:
3415/// (XVBSLL_V $xr2, $xr1, 4)
3416/// (XVPERMI_Q $xr1, $xr0, 33)
3417/// (XVBSRL_V $xr0, $xr1, 12)
3418/// (XVOR_V $xr0, $xr2, $xr0)
3420 ArrayRef<int> Mask,
3421 MVT VT, SDValue V1,
3422 SDValue V2,
3423 SelectionDAG &DAG) {
3424 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3425 int Size = Mask.size();
3426 int LaneSize = Size / 2;
3427
3428 // For each result lane, the input lanes (0/1: V1, 2/3: V2) used by the two
3429 // operands of the in-lane shuffle.
3430 int LaneSrcs[2][2] = {{-1, -1}, {-1, -1}};
3431 SmallVector<int, 32> InLaneMask(Size, -1);
3432 bool LaneCrossing = false;
3433 for (int i = 0; i < Size; ++i) {
3434 int M = Mask[i];
3435 if (M < 0)
3436 continue;
3437 int Lane = i / LaneSize;
3438 int SrcLane = M / LaneSize;
3439
3440 // Put lanes that stay in place in the first operand and the others in the
3441 // second one, so a single input becomes V1 and V1 with lanes swapped.
3442 int Op = (SrcLane % 2) != Lane;
3443 LaneCrossing |= Op;
3444 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3445 Op ^= 1;
3446 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3447 return SDValue();
3448 LaneSrcs[Lane][Op] = SrcLane;
3449 InLaneMask[i] = Op * Size + Lane * LaneSize + M % LaneSize;
3450 }
3451
3452 if (!LaneCrossing)
3453 return SDValue();
3454
3455 // Swap the operands of the high lane if that makes both lanes use the same
3456 // in-lane mask, which more patterns (e.g. XVPICKEV) can match.
3457 SmallVector<int, 16> RepeatedMask;
3458 if (!isRepeatedShuffleMask(128, VT, InLaneMask, RepeatedMask)) {
3459 SmallVector<int, 32> SwappedMask(InLaneMask);
3460 for (int i = LaneSize; i < Size; ++i)
3461 if (SwappedMask[i] >= 0)
3462 SwappedMask[i] = (SwappedMask[i] + Size) % (2 * Size);
3463 if (isRepeatedShuffleMask(128, VT, SwappedMask, RepeatedMask)) {
3464 std::swap(LaneSrcs[1][0], LaneSrcs[1][1]);
3465 InLaneMask = SwappedMask;
3466 }
3467 }
3468
3469 // Move the input lanes of each operand into place.
3470 SDValue Ops[2];
3471 for (int Op = 0; Op < 2; ++Op) {
3472 SmallVector<int, 32> LaneMask(Size, -1);
3473 for (int Lane = 0; Lane < 2; ++Lane)
3474 if (LaneSrcs[Lane][Op] >= 0)
3475 for (int i = 0; i < LaneSize; ++i)
3476 LaneMask[Lane * LaneSize + i] = LaneSrcs[Lane][Op] * LaneSize + i;
3477 Ops[Op] = DAG.getVectorShuffle(VT, DL, V1, V2, LaneMask);
3478
3479 // Exit if we got back the shuffle we started with, to avoid infinite
3480 // recursion.
3481 if (auto *SVN = dyn_cast<ShuffleVectorSDNode>(Ops[Op]))
3482 if (SVN->getMask() == Mask)
3483 return SDValue();
3484 }
3485 return DAG.getVectorShuffle(VT, DL, Ops[0], Ops[1], InLaneMask);
3486}
3487
3488/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3489///
3490/// This routine breaks down the specific type of 256-bit shuffle and
3491/// dispatches to the lowering routines accordingly.
3493 SDValue V1, SDValue V2, SelectionDAG &DAG,
3495 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3496 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3497 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3498 "Vector type is unsupported for lasx!");
3499 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3500 "Two operands have different types!");
3501 assert(VT.getVectorNumElements() == Mask.size() &&
3502 "Unexpected mask size for shuffle!");
3503 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3504 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3505
3506 APInt KnownUndef, KnownZero;
3507 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3508 APInt Zeroable = KnownUndef | KnownZero;
3509
3510 SDValue Result;
3511 // TODO: Add more comparison patterns.
3512 if (V2.isUndef()) {
3513 if ((Result =
3514 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3515 return Result;
3516 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3517 Subtarget)))
3518 return Result;
3519 if ((Result = lowerVECTOR_SHUFFLE_XVREPLVE0(DL, Mask, VT, V1, DAG)))
3520 return Result;
3521 // Try to widen vectors to gain more optimization opportunities.
3522 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3523 return NewShuffle;
3524 if ((Result =
3525 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3526 return Result;
3527 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3528 return Result;
3529 if ((Result =
3530 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3531 return Result;
3532
3533 // TODO: This comment may be enabled in the future to better match the
3534 // pattern for instruction selection.
3535 /* V2 = V1; */
3536 }
3537
3538 // It is recommended not to change the pattern comparison order for better
3539 // performance.
3540 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3541 return Result;
3542 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3543 return Result;
3544 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3545 return Result;
3546 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3547 return Result;
3548 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3549 return Result;
3550 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3551 return Result;
3552 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3553 (Result =
3554 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3555 return Result;
3556 if ((Result =
3557 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3558 return Result;
3559 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3560 Zeroable)))
3561 return Result;
3562 if ((Result =
3563 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3564 return Result;
3565 if ((Result =
3566 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3567 return Result;
3568 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3569 Subtarget)))
3570 return Result;
3571
3572 if ((Result =
3573 lowerVECTOR_SHUFFLE_XVPERMIQ(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3574 return Result;
3575
3576 // canonicalize non cross-lane shuffle vector
3577 SmallVector<int> NewMask(Mask);
3578 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3579 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3580
3581 // FIXME: Handling the remaining cases earlier can degrade performance
3582 // in some situations. Further analysis is required to enable more
3583 // effective optimizations.
3584 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT, V1,
3585 V2, DAG)))
3586 return Result;
3587
3588 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3589 return NewShuffle;
3590 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3591 return Result;
3592
3593 return SDValue();
3594}
3595
3596SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3597 SelectionDAG &DAG) const {
3598 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3599 ArrayRef<int> OrigMask = SVOp->getMask();
3600 SDValue V1 = Op.getOperand(0);
3601 SDValue V2 = Op.getOperand(1);
3602 MVT VT = Op.getSimpleValueType();
3603 int NumElements = VT.getVectorNumElements();
3604 SDLoc DL(Op);
3605
3606 bool V1IsUndef = V1.isUndef();
3607 bool V2IsUndef = V2.isUndef();
3608 if (V1IsUndef && V2IsUndef)
3609 return DAG.getUNDEF(VT);
3610
3611 // When we create a shuffle node we put the UNDEF node to second operand,
3612 // but in some cases the first operand may be transformed to UNDEF.
3613 // In this case we should just commute the node.
3614 if (V1IsUndef)
3615 return DAG.getCommutedVectorShuffle(*SVOp);
3616
3617 // Check for non-undef masks pointing at an undef vector and make the masks
3618 // undef as well. This makes it easier to match the shuffle based solely on
3619 // the mask.
3620 if (V2IsUndef &&
3621 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3622 SmallVector<int, 8> NewMask(OrigMask);
3623 for (int &M : NewMask)
3624 if (M >= NumElements)
3625 M = -1;
3626 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3627 }
3628
3629 // Check for illegal shuffle mask element index values.
3630 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3631 (void)MaskUpperLimit;
3632 assert(llvm::all_of(OrigMask,
3633 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3634 "Out of bounds shuffle index");
3635
3636 // For each vector width, delegate to a specialized lowering routine.
3637 if (VT.is128BitVector())
3638 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3639
3640 if (VT.is256BitVector())
3641 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3642
3643 return SDValue();
3644}
3645
3646SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3647 SelectionDAG &DAG) const {
3648 // Custom lower to ensure the libcall return is passed in an FPR on hard
3649 // float ABIs.
3650 SDLoc DL(Op);
3651 MakeLibCallOptions CallOptions;
3652 SDValue Op0 = Op.getOperand(0);
3653 SDValue Chain = SDValue();
3654 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3655 SDValue Res;
3656 std::tie(Res, Chain) =
3657 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3658 if (Subtarget.is64Bit())
3659 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3660 return DAG.getBitcast(MVT::i32, Res);
3661}
3662
3663SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3664 SelectionDAG &DAG) const {
3665 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3666 // float ABIs.
3667 SDLoc DL(Op);
3668 MakeLibCallOptions CallOptions;
3669 SDValue Op0 = Op.getOperand(0);
3670 SDValue Chain = SDValue();
3671 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3672 DL, MVT::f32, Op0)
3673 : DAG.getBitcast(MVT::f32, Op0);
3674 SDValue Res;
3675 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3676 CallOptions, DL, Chain);
3677 return Res;
3678}
3679
3680SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3681 SelectionDAG &DAG) const {
3682 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3683 SDLoc DL(Op);
3684 MakeLibCallOptions CallOptions;
3685 RTLIB::Libcall LC =
3686 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3687 SDValue Res =
3688 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3689 if (Subtarget.is64Bit())
3690 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3691 return DAG.getBitcast(MVT::i32, Res);
3692}
3693
3694SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3695 SelectionDAG &DAG) const {
3696 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3697 MVT VT = Op.getSimpleValueType();
3698 SDLoc DL(Op);
3699 Op = DAG.getNode(
3700 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3701 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3702 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3703 DL, MVT::f32, Op)
3704 : DAG.getBitcast(MVT::f32, Op);
3705 if (VT != MVT::f32)
3706 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3707 return Res;
3708}
3709
3710// Lower BUILD_VECTOR as broadcast load (if possible).
3711// For example:
3712// %a = load i8, ptr %ptr
3713// %b = build_vector %a, %a, %a, %a
3714// is lowered to :
3715// (VLDREPL_B $a0, 0)
3717 const SDLoc &DL,
3718 SelectionDAG &DAG) {
3719 MVT VT = BVOp->getSimpleValueType(0);
3720 int NumOps = BVOp->getNumOperands();
3721
3722 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3723 "Unsupported vector type for broadcast.");
3724
3725 SDValue IdentitySrc;
3726 bool IsIdeneity = true;
3727
3728 for (int i = 0; i != NumOps; i++) {
3729 SDValue Op = BVOp->getOperand(i);
3730 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3731 IsIdeneity = false;
3732 break;
3733 }
3734 IdentitySrc = BVOp->getOperand(0);
3735 }
3736
3737 // make sure that this load is valid and only has one user.
3738 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3739 return SDValue();
3740
3741 auto *LN = cast<LoadSDNode>(IdentitySrc);
3742 auto ExtType = LN->getExtensionType();
3743
3744 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3745 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3746 // Indexed loads and stores are not supported on LoongArch.
3747 assert(LN->isUnindexed() && "Unexpected indexed load.");
3748
3749 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3750 // The offset operand of unindexed load is always undefined, so there is
3751 // no need to pass it to VLDREPL.
3752 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3753 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3754 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3755 return BCast;
3756 }
3757 return SDValue();
3758}
3759
3760// Sequentially insert elements from Ops into Vector, from low to high indices.
3761// Note: Ops can have fewer elements than Vector.
3764 EVT ResTy) {
3765 assert(Ops.size() <= ResTy.getVectorNumElements());
3766
3767 SDValue Op0 = Ops[0];
3768 if (!Op0.isUndef())
3769 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3770 for (unsigned i = 1; i < Ops.size(); ++i) {
3771 SDValue Opi = Ops[i];
3772 if (Opi.isUndef())
3773 continue;
3774 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3775 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3776 }
3777}
3778
3779// Build a ResTy subvector from Node, taking NumElts elements starting at index
3780// 'first'.
3782 SelectionDAG &DAG, SDLoc DL,
3784 EVT ResTy, unsigned first) {
3785 unsigned NumElts = ResTy.getVectorNumElements();
3786
3787 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3788
3789 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3790 Node->op_begin() + first + NumElts);
3791 SDValue Vector = DAG.getUNDEF(ResTy);
3792 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3793 return Vector;
3794}
3795
3796SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3797 SelectionDAG &DAG) const {
3798 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3799 MVT VT = Node->getSimpleValueType(0);
3800 EVT ResTy = Op->getValueType(0);
3801 unsigned NumElts = ResTy.getVectorNumElements();
3802 SDLoc DL(Op);
3803 APInt SplatValue, SplatUndef;
3804 unsigned SplatBitSize;
3805 bool HasAnyUndefs;
3806 bool IsConstant = false;
3807 bool UseSameConstant = true;
3808 SDValue ConstantValue;
3809 bool Is128Vec = ResTy.is128BitVector();
3810 bool Is256Vec = ResTy.is256BitVector();
3811
3812 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3813 (!Subtarget.hasExtLASX() || !Is256Vec))
3814 return SDValue();
3815
3816 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3817 return Result;
3818
3819 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3820 /*MinSplatBits=*/8) &&
3821 SplatBitSize <= 64) {
3822 // We can only cope with 8, 16, 32, or 64-bit elements.
3823 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3824 SplatBitSize != 64)
3825 return SDValue();
3826
3827 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3828 // We can only handle 64-bit elements that are within
3829 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3830 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3831 if (!SplatValue.isSignedIntN(10) &&
3832 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3833 return SDValue();
3834 if ((Is128Vec && ResTy == MVT::v4i32) ||
3835 (Is256Vec && ResTy == MVT::v8i32))
3836 return Op;
3837 }
3838
3839 EVT ViaVecTy;
3840
3841 switch (SplatBitSize) {
3842 default:
3843 return SDValue();
3844 case 8:
3845 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3846 break;
3847 case 16:
3848 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3849 break;
3850 case 32:
3851 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3852 break;
3853 case 64:
3854 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3855 break;
3856 }
3857
3858 // SelectionDAG::getConstant will promote SplatValue appropriately.
3859 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3860
3861 // Bitcast to the type we originally wanted.
3862 if (ViaVecTy != ResTy)
3863 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3864
3865 return Result;
3866 }
3867
3868 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3869 return Op;
3870
3871 for (unsigned i = 0; i < NumElts; ++i) {
3872 SDValue Opi = Node->getOperand(i);
3873 if (isIntOrFPConstant(Opi)) {
3874 IsConstant = true;
3875 if (!ConstantValue.getNode())
3876 ConstantValue = Opi;
3877 else if (ConstantValue != Opi)
3878 UseSameConstant = false;
3879 }
3880 }
3881
3882 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3883 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3884 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3885 for (unsigned i = 0; i < NumElts; ++i) {
3886 SDValue Opi = Node->getOperand(i);
3887 if (!isIntOrFPConstant(Opi))
3888 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3889 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3890 }
3891 return Result;
3892 }
3893
3894 if (!IsConstant) {
3895 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3896 // the sub-sequence of the vector and then broadcast the sub-sequence.
3897 //
3898 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3899 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3900 // generates worse code in some cases. This could be further optimized
3901 // with more consideration.
3903 BitVector UndefElements;
3904 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3905 UndefElements.count() == 0) {
3906 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3907 // because the high part can be simply treated as undef.
3908 SDValue Vector = DAG.getUNDEF(ResTy);
3909 EVT FillTy = Is256Vec
3911 : ResTy;
3912 SDValue FillVec =
3913 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3914
3915 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3916
3917 unsigned SeqLen = Sequence.size();
3918 unsigned SplatLen = NumElts / SeqLen;
3919 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3920 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3921
3922 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3923 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3924 if (SplatEltTy == MVT::i128)
3925 SplatTy = MVT::v4i64;
3926
3927 SDValue SplatVec;
3928 SDValue SrcVec = DAG.getBitcast(
3929 SplatTy,
3930 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3931 if (Is256Vec) {
3932 SplatVec =
3933 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3934 : LoongArchISD::XVREPLVE0,
3935 DL, SplatTy, SrcVec);
3936 } else {
3937 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3938 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3939 }
3940
3941 return DAG.getBitcast(ResTy, SplatVec);
3942 }
3943
3944 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3945 // using memory operations is much lower.
3946 //
3947 // For 256-bit vectors, normally split into two halves and concatenate.
3948 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
3949 // one non-undef element, skip spliting to avoid a worse result.
3950 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
3951 ResTy == MVT::v4f64) {
3952 unsigned NonUndefCount = 0;
3953 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
3954 if (!Node->getOperand(i).isUndef()) {
3955 ++NonUndefCount;
3956 if (NonUndefCount > 1)
3957 break;
3958 }
3959 }
3960 if (NonUndefCount == 1)
3961 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
3962 }
3963
3964 EVT VecTy =
3965 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
3966 SDValue Vector =
3967 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
3968
3969 if (Is128Vec)
3970 return Vector;
3971
3972 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
3973 VecTy, NumElts / 2);
3974
3975 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
3976 }
3977
3978 return SDValue();
3979}
3980
3981SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
3982 SelectionDAG &DAG) const {
3983 SDLoc DL(Op);
3984 MVT ResVT = Op.getSimpleValueType();
3985 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
3986
3987 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
3988 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
3989 return Op;
3990
3991 unsigned NumOperands = Op.getNumOperands();
3992 unsigned NumFreezeUndef = 0;
3993 unsigned NumZero = 0;
3994 unsigned NumNonZero = 0;
3995 unsigned NonZeros = 0;
3996 SmallSet<SDValue, 4> Undefs;
3997 for (unsigned i = 0; i != NumOperands; ++i) {
3998 SDValue SubVec = Op.getOperand(i);
3999 if (SubVec.isUndef())
4000 continue;
4001 if (ISD::isFreezeUndef(SubVec.getNode())) {
4002 // If the freeze(undef) has multiple uses then we must fold to zero.
4003 if (SubVec.hasOneUse()) {
4004 ++NumFreezeUndef;
4005 } else {
4006 ++NumZero;
4007 Undefs.insert(SubVec);
4008 }
4009 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
4010 ++NumZero;
4011 else {
4012 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
4013 NonZeros |= 1 << i;
4014 ++NumNonZero;
4015 }
4016 }
4017
4018 // If we have more than 2 non-zeros, build each half separately.
4019 if (NumNonZero > 2) {
4020 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
4021 ArrayRef<SDUse> Ops = Op->ops();
4022 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
4023 Ops.slice(0, NumOperands / 2));
4024 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
4025 Ops.slice(NumOperands / 2));
4026 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
4027 }
4028
4029 // Otherwise, build it up through insert_subvectors.
4030 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
4031 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
4032 : DAG.getUNDEF(ResVT));
4033
4034 // Replace Undef operands with ZeroVector.
4035 for (SDValue U : Undefs)
4036 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
4037
4038 MVT SubVT = Op.getOperand(0).getSimpleValueType();
4039 unsigned NumSubElems = SubVT.getVectorNumElements();
4040 for (unsigned i = 0; i != NumOperands; ++i) {
4041 if ((NonZeros & (1 << i)) == 0)
4042 continue;
4043
4044 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
4045 DAG.getVectorIdxConstant(i * NumSubElems, DL));
4046 }
4047
4048 return Vec;
4049}
4050
4051SDValue
4052LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
4053 SelectionDAG &DAG) const {
4054 MVT EltVT = Op.getSimpleValueType();
4055 SDValue Vec = Op->getOperand(0);
4056 EVT VecTy = Vec->getValueType(0);
4057 SDValue Idx = Op->getOperand(1);
4058 SDLoc DL(Op);
4059 MVT GRLenVT = Subtarget.getGRLenVT();
4060
4061 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
4062
4063 if (isa<ConstantSDNode>(Idx))
4064 return Op;
4065
4066 switch (VecTy.getSimpleVT().SimpleTy) {
4067 default:
4068 llvm_unreachable("Unexpected type");
4069 case MVT::v32i8:
4070 case MVT::v16i16:
4071 case MVT::v4i64:
4072 case MVT::v4f64: {
4073 // Extract the high half subvector and place it to the low half of a new
4074 // vector. It doesn't matter what the high half of the new vector is.
4075 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
4076 SDValue VecHi =
4077 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
4078 SDValue TmpVec =
4079 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
4080 VecHi, DAG.getConstant(0, DL, GRLenVT));
4081
4082 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
4083 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
4084 // desired element.
4085 SDValue IdxCp =
4086 Subtarget.is64Bit()
4087 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
4088 : DAG.getBitcast(MVT::f32, Idx);
4089 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
4090 SDValue MaskVec =
4091 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
4092 SDValue ResVec =
4093 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
4094
4095 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
4096 DAG.getConstant(0, DL, GRLenVT));
4097 }
4098 case MVT::v8i32:
4099 case MVT::v8f32: {
4100 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
4101 SDValue SplatValue =
4102 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
4103
4104 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
4105 DAG.getConstant(0, DL, GRLenVT));
4106 }
4107 }
4108}
4109
4110SDValue
4111LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
4112 SelectionDAG &DAG) const {
4113 MVT VT = Op.getSimpleValueType();
4114 MVT EltVT = VT.getVectorElementType();
4115 unsigned NumElts = VT.getVectorNumElements();
4116 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
4117 SDLoc DL(Op);
4118 SDValue Op0 = Op.getOperand(0);
4119 SDValue Op1 = Op.getOperand(1);
4120 SDValue Op2 = Op.getOperand(2);
4121
4122 // Lower inserting a loaded integer into lane 0 of an undefined vector as a
4123 // vector load that writes the whole register: FLD.{S/D} for 32/64-bit
4124 // elements and [X]VLDREPL.{B/H} for 8/16-bit ones. Unlike a scalar load +
4125 // [X]VINSGR2VR, it has no false dependency on the previous value of the
4126 // destination and doesn't need to move the value from a GPR.
4127 // For example:
4128 // %a = load i64, ptr %ptr
4129 // %b = insert_vector_elt undef, %a, 0
4130 // is lowered to:
4131 // (FLD_D $a0, 0)
4132 if (Op0.isUndef() && isNullConstant(Op2) && EltVT.isInteger() &&
4133 Op1.getOpcode() == ISD::LOAD && Op1.hasOneUse()) {
4134 auto *LN = cast<LoadSDNode>(Op1);
4135 auto ExtType = LN->getExtensionType();
4136 if (LN->isSimple() &&
4137 (ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
4138 LN->getMemoryVT().getSizeInBits() == EltSizeInBits) {
4139 // Indexed loads and stores are not supported on LoongArch.
4140 assert(LN->isUnindexed() && "Unexpected indexed load.");
4141 SDValue Res;
4142 if (EltSizeInBits >= 32) {
4143 MVT FltVT = MVT::getFloatingPointVT(EltSizeInBits);
4144 // Don't reuse the memory operand, its range metadata (if any) only
4145 // applies to integer loads.
4146 SDValue Ld = DAG.getLoad(
4147 FltVT, DL, LN->getChain(), LN->getBasePtr(), LN->getPointerInfo(),
4148 LN->getAlign(), LN->getMemOperand()->getFlags(), LN->getAAInfo());
4149 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL,
4150 MVT::getVectorVT(FltVT, NumElts), Ld);
4151 Res = DAG.getBitcast(VT, Res);
4152 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), Ld.getValue(1));
4153 } else {
4154 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
4155 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
4156 Res = DAG.getMemIntrinsicNode(LoongArchISD::VLDREPL, DL, Tys, Ops,
4157 LN->getMemoryVT(), LN->getMemOperand());
4158 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), Res.getValue(1));
4159 }
4160 return Res;
4161 }
4162 }
4163
4164 if (isa<ConstantSDNode>(Op2))
4165 return Op;
4166
4167 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4168 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4169
4170 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4171 return SDValue();
4172
4173 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4174 SmallVector<SDValue, 32> RawIndices;
4175 SDValue SplatIdx;
4176 SDValue Indices;
4177
4178 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4179 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4180 for (unsigned i = 0; i < NumElts; ++i) {
4181 RawIndices.push_back(Op2);
4182 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4183 }
4184 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4185 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4186
4187 RawIndices.clear();
4188 for (unsigned i = 0; i < NumElts; ++i) {
4189 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4190 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4191 }
4192 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4193 Indices = DAG.getBitcast(IdxVTy, Indices);
4194 } else {
4195 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4196
4197 for (unsigned i = 0; i < NumElts; ++i)
4198 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4199 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4200 }
4201
4202 // insert vec, elt, idx
4203 // =>
4204 // select (splatidx == {0,1,2...}) ? splatelt : vec
4205 SDValue SelectCC =
4206 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4207 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4208}
4209
4210SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4211 SelectionDAG &DAG) const {
4212 SDLoc DL(Op);
4213 SyncScope::ID FenceSSID =
4214 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4215
4216 // singlethread fences only synchronize with signal handlers on the same
4217 // thread and thus only need to preserve instruction order, not actually
4218 // enforce memory ordering.
4219 if (FenceSSID == SyncScope::SingleThread)
4220 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4221 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4222
4223 return Op;
4224}
4225
4227 MVT GRLenVT, SDValue RMValue) {
4228 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4229 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4230 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4231 //
4232 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4233 // Since the transformation is self-inverse, it applies in both directions:
4234 // LLVM RM <-> LoongArch FCSR RM
4235 //
4236 // Transformation: RM ^ (~(RM >> 1) & 1)
4237 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4238 DAG.getConstant(1, DL, GRLenVT));
4239
4240 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4241 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4242 DAG.getConstant(1, DL, GRLenVT)),
4243 DAG.getConstant(1, DL, GRLenVT));
4244
4245 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4246}
4247
4248SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4249 SelectionDAG &DAG) const {
4250 MVT GRLenVT = Subtarget.getGRLenVT();
4251 SDLoc DL(Op);
4252 SDValue Chain = Op.getOperand(0);
4253 SDValue RMValue = Op.getOperand(1);
4254
4255 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4256 uint64_t RM = CVal->getZExtValue();
4257 if (RM > 3) {
4259 LLVMContext &C = MF.getFunction().getContext();
4260 C.diagnose(DiagnosticInfoUnsupported(
4261 MF.getFunction(),
4262 "rounding mode is not supported by LoongArch hardware",
4263 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4264 return Chain;
4265 }
4266 }
4267
4268 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4269 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4270
4271 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4272 // into position before writing via WRFCSR.
4273 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4274 DAG.getConstant(8, DL, GRLenVT));
4275
4276 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4277 // unrelated fields in FCSR0.
4278 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4279 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4280 FCSRNo, RMValue, Chain);
4281 return SDValue(RN, 0);
4282}
4283
4284SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4285 SelectionDAG &DAG) const {
4286 MVT GRLenVT = Subtarget.getGRLenVT();
4287 SDLoc DL(Op);
4288 SDValue Chain = Op->getOperand(0);
4289
4290 // FCSR3 is an alias of the RM field.
4291 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4292 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4293 MVT::Other, FCSRNo, Chain);
4294 SDValue RMValue = SDValue(FCSR, 0);
4295 Chain = SDValue(FCSR, 1);
4296
4297 // The RM field in FCSR is at bits [9:8].
4298 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4299 DAG.getConstant(8, DL, GRLenVT));
4300 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4301
4302 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4303 return DAG.getMergeValues({RetVal, Chain}, DL);
4304}
4305
4306SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4307 SelectionDAG &DAG) const {
4308
4309 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4310 DAG.getContext()->emitError(
4311 "On LA64, only 64-bit registers can be written.");
4312 return Op.getOperand(0);
4313 }
4314
4315 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4316 DAG.getContext()->emitError(
4317 "On LA32, only 32-bit registers can be written.");
4318 return Op.getOperand(0);
4319 }
4320
4321 return Op;
4322}
4323
4324SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4325 SelectionDAG &DAG) const {
4326 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4327 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4328 "be a constant integer");
4329 return SDValue();
4330 }
4331
4334 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4335 EVT VT = Op.getValueType();
4336 SDLoc DL(Op);
4337 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4338 unsigned Depth = Op.getConstantOperandVal(0);
4339 int GRLenInBytes = Subtarget.getGRLen() / 8;
4340
4341 while (Depth--) {
4342 int Offset = -(GRLenInBytes * 2);
4343 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4344 DAG.getSignedConstant(Offset, DL, VT));
4345 FrameAddr =
4346 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4347 }
4348 return FrameAddr;
4349}
4350
4351SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4352 SelectionDAG &DAG) const {
4353 // Currently only support lowering return address for current frame.
4354 if (Op.getConstantOperandVal(0) != 0) {
4355 DAG.getContext()->emitError(
4356 "return address can only be determined for the current frame");
4357 return SDValue();
4358 }
4359
4362 MVT GRLenVT = Subtarget.getGRLenVT();
4363
4364 // Return the value of the return address register, marking it an implicit
4365 // live-in.
4366 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4367 getRegClassFor(GRLenVT));
4368 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4369}
4370
4371SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4372 SelectionDAG &DAG) const {
4374 auto Size = Subtarget.getGRLen() / 8;
4375 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4376 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4377}
4378
4379SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4380 SelectionDAG &DAG) const {
4382 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4383
4384 SDLoc DL(Op);
4385 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4387
4388 // vastart just stores the address of the VarArgsFrameIndex slot into the
4389 // memory location argument.
4390 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4391 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4392 MachinePointerInfo(SV));
4393}
4394
4395SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4396 SelectionDAG &DAG) const {
4397 SDLoc DL(Op);
4398 SDValue Op0 = Op.getOperand(0);
4399 EVT VT = Op.getValueType();
4400 EVT Op0VT = Op0.getValueType();
4401
4402 if (VT.isVector()) {
4403 if (VT.getScalarSizeInBits() != Op0VT.getScalarSizeInBits())
4404 return SDValue();
4405 return Op;
4406 }
4407
4408 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4411 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4412
4413 // We can't do uint64 -> double -> float because of double-rounding issue.
4414 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4415 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4416 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4417 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4418 DAG.getIntPtrConstant(0, DL));
4419 return Conv;
4420 }
4421
4422 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4423 return SDValue();
4424
4425 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4426 !Subtarget.hasBasicD() && "unexpected target features");
4427
4428 if (Op0->getOpcode() == ISD::AND) {
4429 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4430 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4431 return Op;
4432 }
4433
4434 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4435 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4436 Op0.getConstantOperandVal(2) == UINT64_C(0))
4437 return Op;
4438
4439 if (Op0.getOpcode() == ISD::AssertZext &&
4440 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4441 return Op;
4442
4443 EVT OpVT = Op0.getValueType();
4444 EVT RetVT = Op.getValueType();
4445 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4446 MakeLibCallOptions CallOptions;
4447 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4448 SDValue Chain = SDValue();
4450 std::tie(Result, Chain) =
4451 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4452 return Result;
4453}
4454
4455SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4456 SelectionDAG &DAG) const {
4457 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4458 !Subtarget.hasBasicD() && "unexpected target features");
4459
4460 SDLoc DL(Op);
4461 SDValue Op0 = Op.getOperand(0);
4462
4463 if ((Op0.getOpcode() == ISD::AssertSext ||
4465 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4466 return Op;
4467
4468 EVT OpVT = Op0.getValueType();
4469 EVT RetVT = Op.getValueType();
4470 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4471 MakeLibCallOptions CallOptions;
4472 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4473 SDValue Chain = SDValue();
4475 std::tie(Result, Chain) =
4476 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4477 return Result;
4478}
4479
4480SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4481 SelectionDAG &DAG) const {
4482
4483 SDLoc DL(Op);
4484 EVT VT = Op.getValueType();
4485 SDValue Op0 = Op.getOperand(0);
4486 EVT Op0VT = Op0.getValueType();
4487
4488 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4489 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4490 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4491 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4492 }
4493 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4494 SDValue Lo, Hi;
4495 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4496 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4497 }
4498 return Op;
4499}
4500
4501SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4502 SelectionDAG &DAG) const {
4503
4504 SDLoc DL(Op);
4505 SDValue Op0 = Op.getOperand(0);
4506
4507 if (Op0.getValueType() == MVT::f16)
4508 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4509
4510 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4511 !Subtarget.hasBasicD()) {
4512 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4513 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4514 }
4515
4516 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4517 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4518 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4519}
4520
4521// [X]VFTINTRZ and FTINTRZ saturate out-of-range values and convert NaN to 0,
4522// which is exactly the semantics of FP_TO_SINT_SAT with a native saturation
4523// width.
4524SDValue LoongArchTargetLowering::lowerFP_TO_SINT_SAT(SDValue Op,
4525 SelectionDAG &DAG) const {
4526 SDLoc DL(Op);
4527 SDValue Src = Op.getOperand(0);
4528 EVT VT = Op.getValueType();
4529 EVT SrcVT = Src.getValueType();
4530 unsigned SatWidth = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
4531
4532 // Vectors are selected by patterns.
4533 if (VT.isVector()) {
4534 if (SatWidth == VT.getScalarSizeInBits() &&
4535 SatWidth == SrcVT.getScalarSizeInBits())
4536 return Op;
4537 return SDValue();
4538 }
4539
4540 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4541 return SDValue();
4542
4543 if (SatWidth == 32) {
4544 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Src);
4545 if (Subtarget.is64Bit())
4546 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, VT, Ftint);
4547 return DAG.getBitcast(VT, Ftint);
4548 }
4549
4550 if (SatWidth == 64 && Subtarget.is64Bit() && Subtarget.hasBasicD()) {
4551 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f64, Src);
4552 return DAG.getBitcast(VT, Ftint);
4553 }
4554
4555 return SDValue();
4556}
4557
4558SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4559 SelectionDAG &DAG) const {
4560 if (!Subtarget.hasExtLSX())
4561 return SDValue();
4562
4563 SDLoc DL(Op);
4564 SDValue Src = Op.getOperand(0);
4565 EVT VT = Op.getValueType();
4566 EVT SrcVT = Src.getValueType();
4567
4568 if (VT != MVT::i64)
4569 return SDValue();
4570
4571 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4572 return SDValue();
4573
4574 if (SrcVT == MVT::f32)
4575 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4576 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4577 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4578 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4579 DAG.getIntPtrConstant(0, DL));
4580}
4581
4583 SelectionDAG &DAG, unsigned Flags) {
4584 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4585}
4586
4588 SelectionDAG &DAG, unsigned Flags) {
4589 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4590 Flags);
4591}
4592
4594 SelectionDAG &DAG, unsigned Flags) {
4595 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4596 N->getOffset(), Flags);
4597}
4598
4600 SelectionDAG &DAG, unsigned Flags) {
4601 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4602}
4603
4604template <class NodeTy>
4605SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4607 bool IsLocal) const {
4608 SDLoc DL(N);
4609 EVT Ty = getPointerTy(DAG.getDataLayout());
4610 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4611 SDValue Load;
4612
4613 switch (M) {
4614 default:
4615 report_fatal_error("Unsupported code model");
4616
4617 case CodeModel::Large: {
4618 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4619
4620 // This is not actually used, but is necessary for successfully matching
4621 // the PseudoLA_*_LARGE nodes.
4622 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4623 if (IsLocal) {
4624 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4625 // eventually becomes the desired 5-insn code sequence.
4626 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4627 Tmp, Addr),
4628 0);
4629 } else {
4630 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4631 // eventually becomes the desired 5-insn code sequence.
4632 Load = SDValue(
4633 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4634 0);
4635 }
4636 break;
4637 }
4638
4639 case CodeModel::Small:
4640 case CodeModel::Medium:
4641 if (IsLocal) {
4642 // This generates the pattern (PseudoLA_PCREL sym), which
4643 //
4644 // for la32r expands to:
4645 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4646 //
4647 // for la32s and la64 expands to:
4648 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4649 Load = SDValue(
4650 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4651 } else {
4652 // This generates the pattern (PseudoLA_GOT sym), which
4653 //
4654 // for la32r expands to:
4655 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4656 //
4657 // for la32s and la64 expands to:
4658 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4659 Load =
4660 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4661 }
4662 }
4663
4664 if (!IsLocal) {
4665 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4667 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4671 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4672 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4673 }
4674
4675 return Load;
4676}
4677
4678SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4679 SelectionDAG &DAG) const {
4680 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4681 DAG.getTarget().getCodeModel());
4682}
4683
4684SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4685 SelectionDAG &DAG) const {
4686 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4687 DAG.getTarget().getCodeModel());
4688}
4689
4690SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4691 SelectionDAG &DAG) const {
4692 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4693 DAG.getTarget().getCodeModel());
4694}
4695
4696SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4697 SelectionDAG &DAG) const {
4698 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4699 assert(N->getOffset() == 0 && "unexpected offset in global node");
4700 auto CM = DAG.getTarget().getCodeModel();
4701 const GlobalValue *GV = N->getGlobal();
4702
4703 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4704 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4705 CM = *GCM;
4706 }
4707
4708 return getAddr(N, DAG, CM, GV->isDSOLocal());
4709}
4710
4711SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4712 SelectionDAG &DAG,
4713 unsigned Opc, bool UseGOT,
4714 bool Large) const {
4715 SDLoc DL(N);
4716 EVT Ty = getPointerTy(DAG.getDataLayout());
4717 MVT GRLenVT = Subtarget.getGRLenVT();
4718
4719 // This is not actually used, but is necessary for successfully matching the
4720 // PseudoLA_*_LARGE nodes.
4721 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4722 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4723
4724 // Only IE needs an extra argument for large code model.
4725 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4726 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4727 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4728
4729 // If it is LE for normal/medium code model, the add tp operation will occur
4730 // during the pseudo-instruction expansion.
4731 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4732 return Offset;
4733
4734 if (UseGOT) {
4735 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4737 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4741 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4742 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4743 }
4744
4745 // Add the thread pointer.
4746 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4747 DAG.getRegister(LoongArch::R2, GRLenVT));
4748}
4749
4750SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4751 SelectionDAG &DAG,
4752 unsigned Opc,
4753 bool Large) const {
4754 SDLoc DL(N);
4755 EVT Ty = getPointerTy(DAG.getDataLayout());
4756 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4757
4758 // This is not actually used, but is necessary for successfully matching the
4759 // PseudoLA_*_LARGE nodes.
4760 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4761
4762 // Use a PC-relative addressing mode to access the dynamic GOT address.
4763 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4764 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4765 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4766
4767 // Prepare argument list to generate call.
4769 Args.emplace_back(Load, CallTy);
4770
4771 // Setup call to __tls_get_addr.
4772 TargetLowering::CallLoweringInfo CLI(DAG);
4773 CLI.setDebugLoc(DL)
4774 .setChain(DAG.getEntryNode())
4775 .setLibCallee(CallingConv::C, CallTy,
4776 DAG.getExternalSymbol("__tls_get_addr", Ty),
4777 std::move(Args));
4778
4779 return LowerCallTo(CLI).first;
4780}
4781
4782SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4783 SelectionDAG &DAG, unsigned Opc,
4784 bool Large) const {
4785 SDLoc DL(N);
4786 EVT Ty = getPointerTy(DAG.getDataLayout());
4787 const GlobalValue *GV = N->getGlobal();
4788
4789 // This is not actually used, but is necessary for successfully matching the
4790 // PseudoLA_*_LARGE nodes.
4791 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4792
4793 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4794 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4795 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4796 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4797 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4798}
4799
4800SDValue
4801LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4802 SelectionDAG &DAG) const {
4805 report_fatal_error("In GHC calling convention TLS is not supported");
4806
4807 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4808 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4809
4810 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4811 assert(N->getOffset() == 0 && "unexpected offset in global node");
4812
4813 if (DAG.getTarget().useEmulatedTLS())
4814 reportFatalUsageError("the emulated TLS is prohibited");
4815
4816 bool IsDesc = DAG.getTarget().useTLSDESC();
4817
4818 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4820 // In this model, application code calls the dynamic linker function
4821 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4822 // runtime.
4823 if (!IsDesc)
4824 return getDynamicTLSAddr(N, DAG,
4825 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4826 : LoongArch::PseudoLA_TLS_GD,
4827 Large);
4828 break;
4830 // Same as GeneralDynamic, except for assembly modifiers and relocation
4831 // records.
4832 if (!IsDesc)
4833 return getDynamicTLSAddr(N, DAG,
4834 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4835 : LoongArch::PseudoLA_TLS_LD,
4836 Large);
4837 break;
4839 // This model uses the GOT to resolve TLS offsets.
4840 return getStaticTLSAddr(N, DAG,
4841 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4842 : LoongArch::PseudoLA_TLS_IE,
4843 /*UseGOT=*/true, Large);
4845 // This model is used when static linking as the TLS offsets are resolved
4846 // during program linking.
4847 //
4848 // This node doesn't need an extra argument for the large code model.
4849 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4850 /*UseGOT=*/false, Large);
4851 }
4852
4853 return getTLSDescAddr(N, DAG,
4854 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4855 : LoongArch::PseudoLA_TLS_DESC,
4856 Large);
4857}
4858
4859template <unsigned N>
4861 SelectionDAG &DAG, bool IsSigned = false) {
4862 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4863 // Check the ImmArg.
4864 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4865 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4866 DAG.getContext()->emitError(Op->getOperationName(0) +
4867 ": argument out of range.");
4868 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4869 }
4870 return SDValue();
4871}
4872
4873SDValue
4874LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4875 SelectionDAG &DAG) const {
4876 switch (Op.getConstantOperandVal(0)) {
4877 default:
4878 return SDValue(); // Don't custom lower most intrinsics.
4879 case Intrinsic::thread_pointer: {
4880 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4881 return DAG.getRegister(LoongArch::R2, PtrVT);
4882 }
4883 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4884 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4885 case Intrinsic::loongarch_lsx_vreplvei_d:
4886 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4887 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4888 case Intrinsic::loongarch_lsx_vreplvei_w:
4889 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4890 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4891 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
4892 case Intrinsic::loongarch_lasx_xvpickve_d:
4893 case Intrinsic::loongarch_lasx_xvpickve_d_f:
4894 return checkIntrinsicImmArg<2>(Op, 2, DAG);
4895 case Intrinsic::loongarch_lasx_xvinsve0_d:
4896 return checkIntrinsicImmArg<2>(Op, 3, DAG);
4897 case Intrinsic::loongarch_lsx_vsat_b:
4898 case Intrinsic::loongarch_lsx_vsat_bu:
4899 case Intrinsic::loongarch_lsx_vrotri_b:
4900 case Intrinsic::loongarch_lsx_vsllwil_h_b:
4901 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
4902 case Intrinsic::loongarch_lsx_vsrlri_b:
4903 case Intrinsic::loongarch_lsx_vsrari_b:
4904 case Intrinsic::loongarch_lsx_vreplvei_h:
4905 case Intrinsic::loongarch_lasx_xvsat_b:
4906 case Intrinsic::loongarch_lasx_xvsat_bu:
4907 case Intrinsic::loongarch_lasx_xvrotri_b:
4908 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
4909 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
4910 case Intrinsic::loongarch_lasx_xvsrlri_b:
4911 case Intrinsic::loongarch_lasx_xvsrari_b:
4912 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
4913 case Intrinsic::loongarch_lasx_xvpickve_w:
4914 case Intrinsic::loongarch_lasx_xvpickve_w_f:
4915 return checkIntrinsicImmArg<3>(Op, 2, DAG);
4916 case Intrinsic::loongarch_lasx_xvinsve0_w:
4917 return checkIntrinsicImmArg<3>(Op, 3, DAG);
4918 case Intrinsic::loongarch_lsx_vsat_h:
4919 case Intrinsic::loongarch_lsx_vsat_hu:
4920 case Intrinsic::loongarch_lsx_vrotri_h:
4921 case Intrinsic::loongarch_lsx_vsllwil_w_h:
4922 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
4923 case Intrinsic::loongarch_lsx_vsrlri_h:
4924 case Intrinsic::loongarch_lsx_vsrari_h:
4925 case Intrinsic::loongarch_lsx_vreplvei_b:
4926 case Intrinsic::loongarch_lasx_xvsat_h:
4927 case Intrinsic::loongarch_lasx_xvsat_hu:
4928 case Intrinsic::loongarch_lasx_xvrotri_h:
4929 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
4930 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
4931 case Intrinsic::loongarch_lasx_xvsrlri_h:
4932 case Intrinsic::loongarch_lasx_xvsrari_h:
4933 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
4934 return checkIntrinsicImmArg<4>(Op, 2, DAG);
4935 case Intrinsic::loongarch_lsx_vsrlni_b_h:
4936 case Intrinsic::loongarch_lsx_vsrani_b_h:
4937 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
4938 case Intrinsic::loongarch_lsx_vsrarni_b_h:
4939 case Intrinsic::loongarch_lsx_vssrlni_b_h:
4940 case Intrinsic::loongarch_lsx_vssrani_b_h:
4941 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
4942 case Intrinsic::loongarch_lsx_vssrani_bu_h:
4943 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
4944 case Intrinsic::loongarch_lsx_vssrarni_b_h:
4945 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
4946 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
4947 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
4948 case Intrinsic::loongarch_lasx_xvsrani_b_h:
4949 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
4950 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
4951 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
4952 case Intrinsic::loongarch_lasx_xvssrani_b_h:
4953 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
4954 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
4955 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
4956 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
4957 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
4958 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
4959 return checkIntrinsicImmArg<4>(Op, 3, DAG);
4960 case Intrinsic::loongarch_lsx_vsat_w:
4961 case Intrinsic::loongarch_lsx_vsat_wu:
4962 case Intrinsic::loongarch_lsx_vrotri_w:
4963 case Intrinsic::loongarch_lsx_vsllwil_d_w:
4964 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
4965 case Intrinsic::loongarch_lsx_vsrlri_w:
4966 case Intrinsic::loongarch_lsx_vsrari_w:
4967 case Intrinsic::loongarch_lsx_vslei_bu:
4968 case Intrinsic::loongarch_lsx_vslei_hu:
4969 case Intrinsic::loongarch_lsx_vslei_wu:
4970 case Intrinsic::loongarch_lsx_vslei_du:
4971 case Intrinsic::loongarch_lsx_vslti_bu:
4972 case Intrinsic::loongarch_lsx_vslti_hu:
4973 case Intrinsic::loongarch_lsx_vslti_wu:
4974 case Intrinsic::loongarch_lsx_vslti_du:
4975 case Intrinsic::loongarch_lsx_vbsll_v:
4976 case Intrinsic::loongarch_lsx_vbsrl_v:
4977 case Intrinsic::loongarch_lasx_xvsat_w:
4978 case Intrinsic::loongarch_lasx_xvsat_wu:
4979 case Intrinsic::loongarch_lasx_xvrotri_w:
4980 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
4981 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
4982 case Intrinsic::loongarch_lasx_xvsrlri_w:
4983 case Intrinsic::loongarch_lasx_xvsrari_w:
4984 case Intrinsic::loongarch_lasx_xvslei_bu:
4985 case Intrinsic::loongarch_lasx_xvslei_hu:
4986 case Intrinsic::loongarch_lasx_xvslei_wu:
4987 case Intrinsic::loongarch_lasx_xvslei_du:
4988 case Intrinsic::loongarch_lasx_xvslti_bu:
4989 case Intrinsic::loongarch_lasx_xvslti_hu:
4990 case Intrinsic::loongarch_lasx_xvslti_wu:
4991 case Intrinsic::loongarch_lasx_xvslti_du:
4992 case Intrinsic::loongarch_lasx_xvbsll_v:
4993 case Intrinsic::loongarch_lasx_xvbsrl_v:
4994 return checkIntrinsicImmArg<5>(Op, 2, DAG);
4995 case Intrinsic::loongarch_lsx_vseqi_b:
4996 case Intrinsic::loongarch_lsx_vseqi_h:
4997 case Intrinsic::loongarch_lsx_vseqi_w:
4998 case Intrinsic::loongarch_lsx_vseqi_d:
4999 case Intrinsic::loongarch_lsx_vslei_b:
5000 case Intrinsic::loongarch_lsx_vslei_h:
5001 case Intrinsic::loongarch_lsx_vslei_w:
5002 case Intrinsic::loongarch_lsx_vslei_d:
5003 case Intrinsic::loongarch_lsx_vslti_b:
5004 case Intrinsic::loongarch_lsx_vslti_h:
5005 case Intrinsic::loongarch_lsx_vslti_w:
5006 case Intrinsic::loongarch_lsx_vslti_d:
5007 case Intrinsic::loongarch_lasx_xvseqi_b:
5008 case Intrinsic::loongarch_lasx_xvseqi_h:
5009 case Intrinsic::loongarch_lasx_xvseqi_w:
5010 case Intrinsic::loongarch_lasx_xvseqi_d:
5011 case Intrinsic::loongarch_lasx_xvslei_b:
5012 case Intrinsic::loongarch_lasx_xvslei_h:
5013 case Intrinsic::loongarch_lasx_xvslei_w:
5014 case Intrinsic::loongarch_lasx_xvslei_d:
5015 case Intrinsic::loongarch_lasx_xvslti_b:
5016 case Intrinsic::loongarch_lasx_xvslti_h:
5017 case Intrinsic::loongarch_lasx_xvslti_w:
5018 case Intrinsic::loongarch_lasx_xvslti_d:
5019 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
5020 case Intrinsic::loongarch_lsx_vsrlni_h_w:
5021 case Intrinsic::loongarch_lsx_vsrani_h_w:
5022 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
5023 case Intrinsic::loongarch_lsx_vsrarni_h_w:
5024 case Intrinsic::loongarch_lsx_vssrlni_h_w:
5025 case Intrinsic::loongarch_lsx_vssrani_h_w:
5026 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
5027 case Intrinsic::loongarch_lsx_vssrani_hu_w:
5028 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
5029 case Intrinsic::loongarch_lsx_vssrarni_h_w:
5030 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
5031 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
5032 case Intrinsic::loongarch_lsx_vfrstpi_b:
5033 case Intrinsic::loongarch_lsx_vfrstpi_h:
5034 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
5035 case Intrinsic::loongarch_lasx_xvsrani_h_w:
5036 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
5037 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
5038 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
5039 case Intrinsic::loongarch_lasx_xvssrani_h_w:
5040 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
5041 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
5042 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
5043 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
5044 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
5045 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
5046 case Intrinsic::loongarch_lasx_xvfrstpi_b:
5047 case Intrinsic::loongarch_lasx_xvfrstpi_h:
5048 return checkIntrinsicImmArg<5>(Op, 3, DAG);
5049 case Intrinsic::loongarch_lsx_vsat_d:
5050 case Intrinsic::loongarch_lsx_vsat_du:
5051 case Intrinsic::loongarch_lsx_vrotri_d:
5052 case Intrinsic::loongarch_lsx_vsrlri_d:
5053 case Intrinsic::loongarch_lsx_vsrari_d:
5054 case Intrinsic::loongarch_lasx_xvsat_d:
5055 case Intrinsic::loongarch_lasx_xvsat_du:
5056 case Intrinsic::loongarch_lasx_xvrotri_d:
5057 case Intrinsic::loongarch_lasx_xvsrlri_d:
5058 case Intrinsic::loongarch_lasx_xvsrari_d:
5059 return checkIntrinsicImmArg<6>(Op, 2, DAG);
5060 case Intrinsic::loongarch_lsx_vsrlni_w_d:
5061 case Intrinsic::loongarch_lsx_vsrani_w_d:
5062 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
5063 case Intrinsic::loongarch_lsx_vsrarni_w_d:
5064 case Intrinsic::loongarch_lsx_vssrlni_w_d:
5065 case Intrinsic::loongarch_lsx_vssrani_w_d:
5066 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
5067 case Intrinsic::loongarch_lsx_vssrani_wu_d:
5068 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
5069 case Intrinsic::loongarch_lsx_vssrarni_w_d:
5070 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
5071 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
5072 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
5073 case Intrinsic::loongarch_lasx_xvsrani_w_d:
5074 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
5075 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
5076 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
5077 case Intrinsic::loongarch_lasx_xvssrani_w_d:
5078 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
5079 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
5080 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
5081 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
5082 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
5083 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
5084 return checkIntrinsicImmArg<6>(Op, 3, DAG);
5085 case Intrinsic::loongarch_lsx_vsrlni_d_q:
5086 case Intrinsic::loongarch_lsx_vsrani_d_q:
5087 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
5088 case Intrinsic::loongarch_lsx_vsrarni_d_q:
5089 case Intrinsic::loongarch_lsx_vssrlni_d_q:
5090 case Intrinsic::loongarch_lsx_vssrani_d_q:
5091 case Intrinsic::loongarch_lsx_vssrlni_du_q:
5092 case Intrinsic::loongarch_lsx_vssrani_du_q:
5093 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
5094 case Intrinsic::loongarch_lsx_vssrarni_d_q:
5095 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
5096 case Intrinsic::loongarch_lsx_vssrarni_du_q:
5097 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
5098 case Intrinsic::loongarch_lasx_xvsrani_d_q:
5099 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
5100 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
5101 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
5102 case Intrinsic::loongarch_lasx_xvssrani_d_q:
5103 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
5104 case Intrinsic::loongarch_lasx_xvssrani_du_q:
5105 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
5106 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
5107 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
5108 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
5109 return checkIntrinsicImmArg<7>(Op, 3, DAG);
5110 case Intrinsic::loongarch_lsx_vnori_b:
5111 case Intrinsic::loongarch_lsx_vshuf4i_b:
5112 case Intrinsic::loongarch_lsx_vshuf4i_h:
5113 case Intrinsic::loongarch_lsx_vshuf4i_w:
5114 case Intrinsic::loongarch_lasx_xvnori_b:
5115 case Intrinsic::loongarch_lasx_xvshuf4i_b:
5116 case Intrinsic::loongarch_lasx_xvshuf4i_h:
5117 case Intrinsic::loongarch_lasx_xvshuf4i_w:
5118 case Intrinsic::loongarch_lasx_xvpermi_d:
5119 return checkIntrinsicImmArg<8>(Op, 2, DAG);
5120 case Intrinsic::loongarch_lsx_vshuf4i_d:
5121 case Intrinsic::loongarch_lsx_vpermi_w:
5122 case Intrinsic::loongarch_lsx_vbitseli_b:
5123 case Intrinsic::loongarch_lsx_vextrins_b:
5124 case Intrinsic::loongarch_lsx_vextrins_h:
5125 case Intrinsic::loongarch_lsx_vextrins_w:
5126 case Intrinsic::loongarch_lsx_vextrins_d:
5127 case Intrinsic::loongarch_lasx_xvshuf4i_d:
5128 case Intrinsic::loongarch_lasx_xvpermi_w:
5129 case Intrinsic::loongarch_lasx_xvpermi_q:
5130 case Intrinsic::loongarch_lasx_xvbitseli_b:
5131 case Intrinsic::loongarch_lasx_xvextrins_b:
5132 case Intrinsic::loongarch_lasx_xvextrins_h:
5133 case Intrinsic::loongarch_lasx_xvextrins_w:
5134 case Intrinsic::loongarch_lasx_xvextrins_d:
5135 return checkIntrinsicImmArg<8>(Op, 3, DAG);
5136 case Intrinsic::loongarch_lsx_vrepli_b:
5137 case Intrinsic::loongarch_lsx_vrepli_h:
5138 case Intrinsic::loongarch_lsx_vrepli_w:
5139 case Intrinsic::loongarch_lsx_vrepli_d:
5140 case Intrinsic::loongarch_lasx_xvrepli_b:
5141 case Intrinsic::loongarch_lasx_xvrepli_h:
5142 case Intrinsic::loongarch_lasx_xvrepli_w:
5143 case Intrinsic::loongarch_lasx_xvrepli_d:
5144 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
5145 case Intrinsic::loongarch_lsx_vldi:
5146 case Intrinsic::loongarch_lasx_xvldi:
5147 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
5148 }
5149}
5150
5151// Helper function that emits error message for intrinsics with chain and return
5152// merge values of a UNDEF and the chain.
5154 StringRef ErrorMsg,
5155 SelectionDAG &DAG) {
5156 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5157 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
5158 SDLoc(Op));
5159}
5160
5161SDValue
5162LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
5163 SelectionDAG &DAG) const {
5164 SDLoc DL(Op);
5165 MVT GRLenVT = Subtarget.getGRLenVT();
5166 EVT VT = Op.getValueType();
5167 SDValue Chain = Op.getOperand(0);
5168 const StringRef ErrorMsgOOR = "argument out of range";
5169 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5170 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5171
5172 switch (Op.getConstantOperandVal(1)) {
5173 default:
5174 return Op;
5175 case Intrinsic::loongarch_crc_w_b_w:
5176 case Intrinsic::loongarch_crc_w_h_w:
5177 case Intrinsic::loongarch_crc_w_w_w:
5178 case Intrinsic::loongarch_crc_w_d_w:
5179 case Intrinsic::loongarch_crcc_w_b_w:
5180 case Intrinsic::loongarch_crcc_w_h_w:
5181 case Intrinsic::loongarch_crcc_w_w_w:
5182 case Intrinsic::loongarch_crcc_w_d_w:
5183 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
5184 case Intrinsic::loongarch_csrrd_w:
5185 case Intrinsic::loongarch_csrrd_d: {
5186 unsigned Imm = Op.getConstantOperandVal(2);
5187 return !isUInt<14>(Imm)
5188 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5189 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5190 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5191 }
5192 case Intrinsic::loongarch_csrwr_w:
5193 case Intrinsic::loongarch_csrwr_d: {
5194 unsigned Imm = Op.getConstantOperandVal(3);
5195 return !isUInt<14>(Imm)
5196 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5197 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5198 {Chain, Op.getOperand(2),
5199 DAG.getConstant(Imm, DL, GRLenVT)});
5200 }
5201 case Intrinsic::loongarch_csrxchg_w:
5202 case Intrinsic::loongarch_csrxchg_d: {
5203 unsigned Imm = Op.getConstantOperandVal(4);
5204 return !isUInt<14>(Imm)
5205 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5206 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5207 {Chain, Op.getOperand(2), Op.getOperand(3),
5208 DAG.getConstant(Imm, DL, GRLenVT)});
5209 }
5210 case Intrinsic::loongarch_iocsrrd_d: {
5211 return DAG.getNode(
5212 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5213 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5214 }
5215#define IOCSRRD_CASE(NAME, NODE) \
5216 case Intrinsic::loongarch_##NAME: { \
5217 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5218 {Chain, Op.getOperand(2)}); \
5219 }
5220 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5221 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5222 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5223#undef IOCSRRD_CASE
5224 case Intrinsic::loongarch_cpucfg: {
5225 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5226 {Chain, Op.getOperand(2)});
5227 }
5228 case Intrinsic::loongarch_lddir_d: {
5229 unsigned Imm = Op.getConstantOperandVal(3);
5230 return !isUInt<8>(Imm)
5231 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5232 : Op;
5233 }
5234 case Intrinsic::loongarch_movfcsr2gr: {
5235 if (!Subtarget.hasBasicF())
5236 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5237 unsigned Imm = Op.getConstantOperandVal(2);
5238 return !isUInt<2>(Imm)
5239 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5240 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5241 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5242 }
5243 case Intrinsic::loongarch_lsx_vld:
5244 case Intrinsic::loongarch_lsx_vldrepl_b:
5245 case Intrinsic::loongarch_lasx_xvld:
5246 case Intrinsic::loongarch_lasx_xvldrepl_b:
5247 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5248 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5249 : SDValue();
5250 case Intrinsic::loongarch_lsx_vldrepl_h:
5251 case Intrinsic::loongarch_lasx_xvldrepl_h:
5252 return !isShiftedInt<11, 1>(
5253 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5255 Op, "argument out of range or not a multiple of 2", DAG)
5256 : SDValue();
5257 case Intrinsic::loongarch_lsx_vldrepl_w:
5258 case Intrinsic::loongarch_lasx_xvldrepl_w:
5259 return !isShiftedInt<10, 2>(
5260 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5262 Op, "argument out of range or not a multiple of 4", DAG)
5263 : SDValue();
5264 case Intrinsic::loongarch_lsx_vldrepl_d:
5265 case Intrinsic::loongarch_lasx_xvldrepl_d:
5266 return !isShiftedInt<9, 3>(
5267 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5269 Op, "argument out of range or not a multiple of 8", DAG)
5270 : SDValue();
5271 }
5272}
5273
5274// Helper function that emits error message for intrinsics with void return
5275// value and return the chain.
5277 SelectionDAG &DAG) {
5278
5279 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5280 return Op.getOperand(0);
5281}
5282
5283SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5284 SelectionDAG &DAG) const {
5285 SDLoc DL(Op);
5286 MVT GRLenVT = Subtarget.getGRLenVT();
5287 SDValue Chain = Op.getOperand(0);
5288 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5289 SDValue Op2 = Op.getOperand(2);
5290 const StringRef ErrorMsgOOR = "argument out of range";
5291 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5292 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5293 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5294
5295 switch (IntrinsicEnum) {
5296 default:
5297 // TODO: Add more Intrinsics.
5298 return SDValue();
5299 case Intrinsic::loongarch_cacop_d:
5300 case Intrinsic::loongarch_cacop_w: {
5301 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5302 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5303 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5304 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5305 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5306 unsigned Imm1 = Op2->getAsZExtVal();
5307 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5308 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5309 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5310 return Op;
5311 }
5312 case Intrinsic::loongarch_dbar: {
5313 unsigned Imm = Op2->getAsZExtVal();
5314 return !isUInt<15>(Imm)
5315 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5316 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5317 DAG.getConstant(Imm, DL, GRLenVT));
5318 }
5319 case Intrinsic::loongarch_ibar: {
5320 unsigned Imm = Op2->getAsZExtVal();
5321 return !isUInt<15>(Imm)
5322 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5323 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5324 DAG.getConstant(Imm, DL, GRLenVT));
5325 }
5326 case Intrinsic::loongarch_break: {
5327 unsigned Imm = Op2->getAsZExtVal();
5328 return !isUInt<15>(Imm)
5329 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5330 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5331 DAG.getConstant(Imm, DL, GRLenVT));
5332 }
5333 case Intrinsic::loongarch_movgr2fcsr: {
5334 if (!Subtarget.hasBasicF())
5335 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5336 unsigned Imm = Op2->getAsZExtVal();
5337 return !isUInt<2>(Imm)
5338 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5339 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5340 DAG.getConstant(Imm, DL, GRLenVT),
5341 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5342 Op.getOperand(3)));
5343 }
5344 case Intrinsic::loongarch_syscall: {
5345 unsigned Imm = Op2->getAsZExtVal();
5346 return !isUInt<15>(Imm)
5347 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5348 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5349 DAG.getConstant(Imm, DL, GRLenVT));
5350 }
5351#define IOCSRWR_CASE(NAME, NODE) \
5352 case Intrinsic::loongarch_##NAME: { \
5353 SDValue Op3 = Op.getOperand(3); \
5354 return Subtarget.is64Bit() \
5355 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5356 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5357 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5358 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5359 Op3); \
5360 }
5361 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5362 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5363 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5364#undef IOCSRWR_CASE
5365 case Intrinsic::loongarch_iocsrwr_d: {
5366 return !Subtarget.is64Bit()
5367 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5368 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5369 Op2,
5370 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5371 Op.getOperand(3)));
5372 }
5373#define ASRT_LE_GT_CASE(NAME) \
5374 case Intrinsic::loongarch_##NAME: { \
5375 return !Subtarget.is64Bit() \
5376 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5377 : Op; \
5378 }
5379 ASRT_LE_GT_CASE(asrtle_d)
5380 ASRT_LE_GT_CASE(asrtgt_d)
5381#undef ASRT_LE_GT_CASE
5382 case Intrinsic::loongarch_ldpte_d: {
5383 unsigned Imm = Op.getConstantOperandVal(3);
5384 return !Subtarget.is64Bit()
5385 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5386 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5387 : Op;
5388 }
5389 case Intrinsic::loongarch_lsx_vst:
5390 case Intrinsic::loongarch_lasx_xvst:
5391 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5392 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5393 : SDValue();
5394 case Intrinsic::loongarch_lasx_xvstelm_b:
5395 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5396 !isUInt<5>(Op.getConstantOperandVal(5)))
5397 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5398 : SDValue();
5399 case Intrinsic::loongarch_lsx_vstelm_b:
5400 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5401 !isUInt<4>(Op.getConstantOperandVal(5)))
5402 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5403 : SDValue();
5404 case Intrinsic::loongarch_lasx_xvstelm_h:
5405 return (!isShiftedInt<8, 1>(
5406 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5407 !isUInt<4>(Op.getConstantOperandVal(5)))
5409 Op, "argument out of range or not a multiple of 2", DAG)
5410 : SDValue();
5411 case Intrinsic::loongarch_lsx_vstelm_h:
5412 return (!isShiftedInt<8, 1>(
5413 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5414 !isUInt<3>(Op.getConstantOperandVal(5)))
5416 Op, "argument out of range or not a multiple of 2", DAG)
5417 : SDValue();
5418 case Intrinsic::loongarch_lasx_xvstelm_w:
5419 return (!isShiftedInt<8, 2>(
5420 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5421 !isUInt<3>(Op.getConstantOperandVal(5)))
5423 Op, "argument out of range or not a multiple of 4", DAG)
5424 : SDValue();
5425 case Intrinsic::loongarch_lsx_vstelm_w:
5426 return (!isShiftedInt<8, 2>(
5427 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5428 !isUInt<2>(Op.getConstantOperandVal(5)))
5430 Op, "argument out of range or not a multiple of 4", DAG)
5431 : SDValue();
5432 case Intrinsic::loongarch_lasx_xvstelm_d:
5433 return (!isShiftedInt<8, 3>(
5434 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5435 !isUInt<2>(Op.getConstantOperandVal(5)))
5437 Op, "argument out of range or not a multiple of 8", DAG)
5438 : SDValue();
5439 case Intrinsic::loongarch_lsx_vstelm_d:
5440 return (!isShiftedInt<8, 3>(
5441 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5442 !isUInt<1>(Op.getConstantOperandVal(5)))
5444 Op, "argument out of range or not a multiple of 8", DAG)
5445 : SDValue();
5446 }
5447}
5448
5449SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5450 SelectionDAG &DAG) const {
5451 SDLoc DL(Op);
5452 SDValue Lo = Op.getOperand(0);
5453 SDValue Hi = Op.getOperand(1);
5454 SDValue Shamt = Op.getOperand(2);
5455 EVT VT = Lo.getValueType();
5456
5457 // if Shamt-GRLen < 0: // Shamt < GRLen
5458 // Lo = Lo << Shamt
5459 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5460 // else:
5461 // Lo = 0
5462 // Hi = Lo << (Shamt-GRLen)
5463
5464 SDValue Zero = DAG.getConstant(0, DL, VT);
5465 SDValue One = DAG.getConstant(1, DL, VT);
5466 SDValue MinusGRLen =
5467 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5468 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5469 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5470 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5471
5472 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5473 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5474 SDValue ShiftRightLo =
5475 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5476 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5477 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5478 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5479
5480 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5481
5482 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5483 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5484
5485 SDValue Parts[2] = {Lo, Hi};
5486 return DAG.getMergeValues(Parts, DL);
5487}
5488
5489SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5490 SelectionDAG &DAG,
5491 bool IsSRA) const {
5492 SDLoc DL(Op);
5493 SDValue Lo = Op.getOperand(0);
5494 SDValue Hi = Op.getOperand(1);
5495 SDValue Shamt = Op.getOperand(2);
5496 EVT VT = Lo.getValueType();
5497
5498 // SRA expansion:
5499 // if Shamt-GRLen < 0: // Shamt < GRLen
5500 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5501 // Hi = Hi >>s Shamt
5502 // else:
5503 // Lo = Hi >>s (Shamt-GRLen);
5504 // Hi = Hi >>s (GRLen-1)
5505 //
5506 // SRL expansion:
5507 // if Shamt-GRLen < 0: // Shamt < GRLen
5508 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5509 // Hi = Hi >>u Shamt
5510 // else:
5511 // Lo = Hi >>u (Shamt-GRLen);
5512 // Hi = 0;
5513
5514 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5515
5516 SDValue Zero = DAG.getConstant(0, DL, VT);
5517 SDValue One = DAG.getConstant(1, DL, VT);
5518 SDValue MinusGRLen =
5519 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5520 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5521 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5522 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5523
5524 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5525 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5526 SDValue ShiftLeftHi =
5527 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5528 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5529 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5530 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5531 SDValue HiFalse =
5532 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5533
5534 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5535
5536 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5537 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5538
5539 SDValue Parts[2] = {Lo, Hi};
5540 return DAG.getMergeValues(Parts, DL);
5541}
5542
5543// Returns the opcode of the target-specific SDNode that implements the 32-bit
5544// form of the given Opcode.
5545static unsigned getLoongArchWOpcode(unsigned Opcode) {
5546 switch (Opcode) {
5547 default:
5548 llvm_unreachable("Unexpected opcode");
5549 case ISD::SDIV:
5550 return LoongArchISD::DIV_W;
5551 case ISD::UDIV:
5552 return LoongArchISD::DIV_WU;
5553 case ISD::SREM:
5554 return LoongArchISD::MOD_W;
5555 case ISD::UREM:
5556 return LoongArchISD::MOD_WU;
5557 case ISD::SHL:
5558 return LoongArchISD::SLL_W;
5559 case ISD::SRA:
5560 return LoongArchISD::SRA_W;
5561 case ISD::SRL:
5562 return LoongArchISD::SRL_W;
5563 case ISD::ROTL:
5564 case ISD::ROTR:
5565 return LoongArchISD::ROTR_W;
5566 case ISD::CTTZ:
5567 return LoongArchISD::CTZ_W;
5568 case ISD::CTLZ:
5569 return LoongArchISD::CLZ_W;
5570 }
5571}
5572
5573// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5574// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5575// otherwise be promoted to i64, making it difficult to select the
5576// SLL_W/.../*W later one because the fact the operation was originally of
5577// type i8/i16/i32 is lost.
5579 unsigned ExtOpc = ISD::ANY_EXTEND) {
5580 SDLoc DL(N);
5581 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5582 SDValue NewOp0, NewRes;
5583
5584 switch (NumOp) {
5585 default:
5586 llvm_unreachable("Unexpected NumOp");
5587 case 1: {
5588 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5589 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5590 break;
5591 }
5592 case 2: {
5593 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5594 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5595 if (N->getOpcode() == ISD::ROTL) {
5596 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5597 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5598 }
5599 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5600 break;
5601 }
5602 // TODO:Handle more NumOp.
5603 }
5604
5605 // ReplaceNodeResults requires we maintain the same type for the return
5606 // value.
5607 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5608}
5609
5610// Converts the given 32-bit operation to a i64 operation with signed extension
5611// semantic to reduce the signed extension instructions.
5613 SDLoc DL(N);
5614 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5615 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5616 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5617 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5618 DAG.getValueType(MVT::i32));
5619 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5620}
5621
5622// Helper function that emits error message for intrinsics with/without chain
5623// and return a UNDEF or and the chain as the results.
5626 StringRef ErrorMsg, bool WithChain = true) {
5627 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5628 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5629 if (!WithChain)
5630 return;
5631 Results.push_back(N->getOperand(0));
5632}
5633
5634template <unsigned N>
5635static void
5638 unsigned ResOp) {
5639 const StringRef ErrorMsgOOR = "argument out of range";
5640 unsigned Imm = Node->getConstantOperandVal(2);
5641 if (!isUInt<N>(Imm)) {
5643 /*WithChain=*/false);
5644 return;
5645 }
5646 SDLoc DL(Node);
5647 SDValue Vec = Node->getOperand(1);
5648
5649 SDValue PickElt =
5650 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5651 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5653 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5654 PickElt.getValue(0)));
5655}
5656
5659 SelectionDAG &DAG,
5661 unsigned ResOp) {
5662 SDLoc DL(N);
5663 SDValue Vec = N->getOperand(1);
5664
5665 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5666 Results.push_back(
5667 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5668}
5669
5670static void
5672 SelectionDAG &DAG,
5674 switch (N->getConstantOperandVal(0)) {
5675 default:
5676 llvm_unreachable("Unexpected Intrinsic.");
5677 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5679 LoongArchISD::VPICK_SEXT_ELT);
5680 break;
5681 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5682 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5684 LoongArchISD::VPICK_SEXT_ELT);
5685 break;
5686 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5688 LoongArchISD::VPICK_SEXT_ELT);
5689 break;
5690 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5692 LoongArchISD::VPICK_ZEXT_ELT);
5693 break;
5694 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5695 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5697 LoongArchISD::VPICK_ZEXT_ELT);
5698 break;
5699 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5701 LoongArchISD::VPICK_ZEXT_ELT);
5702 break;
5703 case Intrinsic::loongarch_lsx_bz_b:
5704 case Intrinsic::loongarch_lsx_bz_h:
5705 case Intrinsic::loongarch_lsx_bz_w:
5706 case Intrinsic::loongarch_lsx_bz_d:
5707 case Intrinsic::loongarch_lasx_xbz_b:
5708 case Intrinsic::loongarch_lasx_xbz_h:
5709 case Intrinsic::loongarch_lasx_xbz_w:
5710 case Intrinsic::loongarch_lasx_xbz_d:
5712 LoongArchISD::VALL_ZERO);
5713 break;
5714 case Intrinsic::loongarch_lsx_bz_v:
5715 case Intrinsic::loongarch_lasx_xbz_v:
5717 LoongArchISD::VANY_ZERO);
5718 break;
5719 case Intrinsic::loongarch_lsx_bnz_b:
5720 case Intrinsic::loongarch_lsx_bnz_h:
5721 case Intrinsic::loongarch_lsx_bnz_w:
5722 case Intrinsic::loongarch_lsx_bnz_d:
5723 case Intrinsic::loongarch_lasx_xbnz_b:
5724 case Intrinsic::loongarch_lasx_xbnz_h:
5725 case Intrinsic::loongarch_lasx_xbnz_w:
5726 case Intrinsic::loongarch_lasx_xbnz_d:
5728 LoongArchISD::VALL_NONZERO);
5729 break;
5730 case Intrinsic::loongarch_lsx_bnz_v:
5731 case Intrinsic::loongarch_lasx_xbnz_v:
5733 LoongArchISD::VANY_NONZERO);
5734 break;
5735 }
5736}
5737
5740 SelectionDAG &DAG) {
5741 assert(N->getValueType(0) == MVT::i128 &&
5742 "AtomicCmpSwap on types less than 128 should be legal");
5743 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5744
5745 unsigned Opcode;
5746 switch (MemOp->getMergedOrdering()) {
5750 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5751 break;
5754 Opcode = LoongArch::PseudoCmpXchg128;
5755 break;
5756 default:
5757 llvm_unreachable("Unexpected ordering!");
5758 }
5759
5760 SDLoc DL(N);
5761 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5762 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5763 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5764 NewVal.first, NewVal.second, N->getOperand(0)};
5765
5766 SDNode *CmpSwap = DAG.getMachineNode(
5767 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5768 Ops);
5769 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5770 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5771 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5772 Results.push_back(SDValue(CmpSwap, 3));
5773}
5774
5777 SDLoc DL(N);
5778 EVT VT = N->getValueType(0);
5779 switch (N->getOpcode()) {
5780 default:
5781 llvm_unreachable("Don't know how to legalize this operation");
5782 case ISD::ADD:
5783 case ISD::SUB:
5784 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5785 "Unexpected custom legalisation");
5786 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5787 break;
5788 case ISD::SDIV:
5789 case ISD::UDIV:
5790 case ISD::SREM:
5791 case ISD::UREM:
5792 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5793 "Unexpected custom legalisation");
5794 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5795 Subtarget.hasDiv32() && VT == MVT::i32
5797 : ISD::SIGN_EXTEND));
5798 break;
5799 case ISD::SHL:
5800 case ISD::SRA:
5801 case ISD::SRL:
5802 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5803 "Unexpected custom legalisation");
5804 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5805 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5806 break;
5807 }
5808 break;
5809 case ISD::ROTL:
5810 case ISD::ROTR:
5811 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5812 "Unexpected custom legalisation");
5813 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5814 break;
5815 case ISD::LOAD: {
5816 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5817 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5818 // cast since type legalization will try to use an i64 load.
5819 MVT VT = N->getSimpleValueType(0);
5820 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5821 "Unexpected custom legalisation");
5823 "Unexpected type action!");
5824 if (!ISD::isNON_EXTLoad(N))
5825 return;
5826 auto *Ld = cast<LoadSDNode>(N);
5827 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5828 Ld->getPointerInfo(), Ld->getBaseAlign(),
5829 Ld->getMemOperand()->getFlags());
5830 SDValue Chain = Res.getValue(1);
5831 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5832 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5833 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5834 Res = DAG.getBitcast(WideVT, Res);
5835 Results.push_back(Res);
5836 Results.push_back(Chain);
5837 break;
5838 }
5839 case ISD::FP_TO_SINT: {
5840 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5841 "Unexpected custom legalisation");
5842 SDValue Src = N->getOperand(0);
5843 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5844 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5846 if (!isTypeLegal(Src.getValueType()))
5847 return;
5848 if (Src.getValueType() == MVT::f16)
5849 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5850 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5851 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5852 return;
5853 }
5854 // If the FP type needs to be softened, emit a library call using the 'si'
5855 // version. If we left it to default legalization we'd end up with 'di'.
5856 RTLIB::Libcall LC;
5857 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5858 MakeLibCallOptions CallOptions;
5859 EVT OpVT = Src.getValueType();
5860 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5861 SDValue Chain = SDValue();
5862 SDValue Result;
5863 std::tie(Result, Chain) =
5864 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5865 Results.push_back(Result);
5866 break;
5867 }
5868 case ISD::BITCAST: {
5869 SDValue Src = N->getOperand(0);
5870 EVT SrcVT = Src.getValueType();
5871 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5872 Subtarget.hasBasicF()) {
5873 SDValue Dst =
5874 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5875 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5876 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5877 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5878 DAG.getVTList(MVT::i32, MVT::i32), Src);
5879 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5880 NewReg.getValue(0), NewReg.getValue(1));
5881 Results.push_back(RetReg);
5882 }
5883 break;
5884 }
5885 case ISD::FP_TO_UINT: {
5886 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5887 "Unexpected custom legalisation");
5888 auto &TLI = DAG.getTargetLoweringInfo();
5889 SDValue Tmp1, Tmp2;
5890 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5891 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
5892 break;
5893 }
5894 case ISD::FP_ROUND: {
5895 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5896 "Unexpected custom legalisation");
5897 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
5898 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
5899 // a target-specific LoongArchISD::VFCVT to optimize it.
5900 SDValue Op0 = N->getOperand(0);
5901 EVT OpVT = Op0.getValueType();
5902 if (OpVT == MVT::v2f64) {
5903 SDValue Undef = DAG.getUNDEF(OpVT);
5904 SDValue Dst =
5905 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
5906 Results.push_back(Dst);
5907 }
5908 break;
5909 }
5910 case ISD::BSWAP: {
5911 SDValue Src = N->getOperand(0);
5912 assert((VT == MVT::i16 || VT == MVT::i32) &&
5913 "Unexpected custom legalization");
5914 MVT GRLenVT = Subtarget.getGRLenVT();
5915 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5916 SDValue Tmp;
5917 switch (VT.getSizeInBits()) {
5918 default:
5919 llvm_unreachable("Unexpected operand width");
5920 case 16:
5921 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
5922 break;
5923 case 32:
5924 // Only LA64 will get to here due to the size mismatch between VT and
5925 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
5926 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
5927 break;
5928 }
5929 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5930 break;
5931 }
5932 case ISD::BITREVERSE: {
5933 SDValue Src = N->getOperand(0);
5934 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
5935 "Unexpected custom legalization");
5936 MVT GRLenVT = Subtarget.getGRLenVT();
5937 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5938 SDValue Tmp;
5939 switch (VT.getSizeInBits()) {
5940 default:
5941 llvm_unreachable("Unexpected operand width");
5942 case 8:
5943 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
5944 break;
5945 case 32:
5946 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
5947 break;
5948 }
5949 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5950 break;
5951 }
5952 case ISD::CTLZ:
5953 case ISD::CTTZ: {
5954 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5955 "Unexpected custom legalisation");
5956 Results.push_back(customLegalizeToWOp(N, DAG, 1));
5957 break;
5958 }
5960 SDValue Chain = N->getOperand(0);
5961 SDValue Op2 = N->getOperand(2);
5962 MVT GRLenVT = Subtarget.getGRLenVT();
5963 const StringRef ErrorMsgOOR = "argument out of range";
5964 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5965 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5966
5967 switch (N->getConstantOperandVal(1)) {
5968 default:
5969 llvm_unreachable("Unexpected Intrinsic.");
5970 case Intrinsic::loongarch_movfcsr2gr: {
5971 if (!Subtarget.hasBasicF()) {
5972 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
5973 return;
5974 }
5975 unsigned Imm = Op2->getAsZExtVal();
5976 if (!isUInt<2>(Imm)) {
5977 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5978 return;
5979 }
5980 SDValue MOVFCSR2GRResults = DAG.getNode(
5981 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
5982 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5983 Results.push_back(
5984 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
5985 Results.push_back(MOVFCSR2GRResults.getValue(1));
5986 break;
5987 }
5988#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
5989 case Intrinsic::loongarch_##NAME: { \
5990 SDValue NODE = DAG.getNode( \
5991 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5992 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5993 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5994 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5995 Results.push_back(NODE.getValue(1)); \
5996 break; \
5997 }
5998 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
5999 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
6000 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
6001 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
6002 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
6003 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
6004#undef CRC_CASE_EXT_BINARYOP
6005
6006#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
6007 case Intrinsic::loongarch_##NAME: { \
6008 SDValue NODE = DAG.getNode( \
6009 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6010 {Chain, Op2, \
6011 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
6012 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
6013 Results.push_back(NODE.getValue(1)); \
6014 break; \
6015 }
6016 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
6017 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
6018#undef CRC_CASE_EXT_UNARYOP
6019#define CSR_CASE(ID) \
6020 case Intrinsic::loongarch_##ID: { \
6021 if (!Subtarget.is64Bit()) \
6022 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
6023 break; \
6024 }
6025 CSR_CASE(csrrd_d);
6026 CSR_CASE(csrwr_d);
6027 CSR_CASE(csrxchg_d);
6028 CSR_CASE(iocsrrd_d);
6029#undef CSR_CASE
6030 case Intrinsic::loongarch_csrrd_w: {
6031 unsigned Imm = Op2->getAsZExtVal();
6032 if (!isUInt<14>(Imm)) {
6033 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6034 return;
6035 }
6036 SDValue CSRRDResults =
6037 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
6038 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
6039 Results.push_back(
6040 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
6041 Results.push_back(CSRRDResults.getValue(1));
6042 break;
6043 }
6044 case Intrinsic::loongarch_csrwr_w: {
6045 unsigned Imm = N->getConstantOperandVal(3);
6046 if (!isUInt<14>(Imm)) {
6047 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6048 return;
6049 }
6050 SDValue CSRWRResults =
6051 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
6052 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
6053 DAG.getConstant(Imm, DL, GRLenVT)});
6054 Results.push_back(
6055 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
6056 Results.push_back(CSRWRResults.getValue(1));
6057 break;
6058 }
6059 case Intrinsic::loongarch_csrxchg_w: {
6060 unsigned Imm = N->getConstantOperandVal(4);
6061 if (!isUInt<14>(Imm)) {
6062 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6063 return;
6064 }
6065 SDValue CSRXCHGResults = DAG.getNode(
6066 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
6067 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
6068 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
6069 DAG.getConstant(Imm, DL, GRLenVT)});
6070 Results.push_back(
6071 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
6072 Results.push_back(CSRXCHGResults.getValue(1));
6073 break;
6074 }
6075#define IOCSRRD_CASE(NAME, NODE) \
6076 case Intrinsic::loongarch_##NAME: { \
6077 SDValue IOCSRRDResults = \
6078 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6079 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
6080 Results.push_back( \
6081 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
6082 Results.push_back(IOCSRRDResults.getValue(1)); \
6083 break; \
6084 }
6085 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
6086 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
6087 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
6088#undef IOCSRRD_CASE
6089 case Intrinsic::loongarch_cpucfg: {
6090 SDValue CPUCFGResults =
6091 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
6092 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
6093 Results.push_back(
6094 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
6095 Results.push_back(CPUCFGResults.getValue(1));
6096 break;
6097 }
6098 case Intrinsic::loongarch_lddir_d: {
6099 if (!Subtarget.is64Bit()) {
6100 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
6101 return;
6102 }
6103 break;
6104 }
6105 }
6106 break;
6107 }
6108 case ISD::READ_REGISTER: {
6109 if (Subtarget.is64Bit())
6110 DAG.getContext()->emitError(
6111 "On LA64, only 64-bit registers can be read.");
6112 else
6113 DAG.getContext()->emitError(
6114 "On LA32, only 32-bit registers can be read.");
6115 Results.push_back(DAG.getUNDEF(VT));
6116 Results.push_back(N->getOperand(0));
6117 break;
6118 }
6120 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
6121 break;
6122 }
6123 case ISD::LROUND: {
6124 SDValue Op0 = N->getOperand(0);
6125 EVT OpVT = Op0.getValueType();
6126 RTLIB::Libcall LC =
6127 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
6128 MakeLibCallOptions CallOptions;
6129 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
6130 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
6131 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
6132 Results.push_back(Result);
6133 break;
6134 }
6135 case ISD::ATOMIC_CMP_SWAP: {
6137 break;
6138 }
6139 case ISD::TRUNCATE: {
6140 MVT VT = N->getSimpleValueType(0);
6141 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
6142 return;
6143
6144 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
6145 SDValue In = N->getOperand(0);
6146 EVT InVT = In.getValueType();
6147 EVT InEltVT = InVT.getVectorElementType();
6148 EVT EltVT = VT.getVectorElementType();
6149 unsigned MinElts = VT.getVectorNumElements();
6150 unsigned WidenNumElts = WidenVT.getVectorNumElements();
6151 unsigned InBits = InVT.getSizeInBits();
6152
6153 // v8i64 -> (v8i32) -> v8i8
6154 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
6155 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
6156 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6157 InBits = 256;
6158 }
6159
6160 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
6161 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
6162 WidenVT.is128BitVector()) {
6163 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
6164 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6165 InBits = 128;
6166 InEltVT = InVT.getVectorElementType();
6167 }
6168
6169 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
6170 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
6171 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
6172 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
6173 for (unsigned I = 0; I < MinElts; ++I)
6174 TruncMask[I] = Scale * I;
6175
6176 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
6177 MVT SVT = In.getSimpleValueType().getScalarType();
6178 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
6179 SDValue WidenIn =
6180 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
6181 DAG.getVectorIdxConstant(0, DL));
6182 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
6183 "Illegal vector type in truncation");
6184 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
6185 Results.push_back(
6186 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
6187 return;
6188 }
6189 }
6190
6191 break;
6192 }
6193 case ISD::SIGN_EXTEND: {
6194 // LASX has native VEXT2XV_* for sign extension.
6195 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
6196 return;
6197
6198 EVT DstVT = N->getValueType(0);
6199 SDValue Src = N->getOperand(0);
6200 MVT SrcVT = Src.getSimpleValueType();
6201
6202 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
6203 unsigned DstEltBits = DstVT.getScalarSizeInBits();
6204 unsigned NumElts = DstVT.getVectorNumElements();
6205
6206 if (SrcVT.getSizeInBits() > 128)
6207 return;
6208
6209 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6210 return;
6211
6212 // If every source element is all-ones or all-zeros, so is every extended
6213 // element, and interleaving a block with itself extends its low half.
6214 bool IsSignSplat = DAG.ComputeNumSignBits(Src) == SrcEltBits;
6215
6216 // Legalize and extend the src to 128-bit first.
6217 if (SrcVT.getSizeInBits() < 128) {
6218 unsigned WidenSrcElts = 128 / SrcEltBits;
6219 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6220 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6221 DAG.getUNDEF(WidenSrcVT), Src,
6222 DAG.getVectorIdxConstant(0, DL));
6223 SrcVT = WidenSrcVT;
6224
6225 unsigned FirstStageEltBits = 128 / NumElts;
6226 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6227 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6228 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6229 SrcVT = FirstStageVT;
6230 SrcEltBits = FirstStageEltBits;
6231 }
6232
6234 Blocks.push_back(Src);
6235
6236 // Sign-extend the src by using VSLLWIL (or VILVL for a sign splat) + VEXTH
6237 // recursively.
6238 while (SrcEltBits < DstEltBits) {
6239 unsigned NextEltBits = SrcEltBits * 2;
6240 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6241 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6242 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6243 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6244
6245 SmallVector<SDValue, 8> NextBlocks;
6246 NextBlocks.reserve(Blocks.size() * 2);
6247 for (SDValue Block : Blocks) {
6248 SDValue Lo;
6249 if (IsSignSplat) {
6250 Lo = DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Block, Block);
6251 Lo = DAG.getBitcast(NextBlockVT, Lo);
6252 } else {
6253 Lo = DAG.getNode(LoongArchISD::VSLLWIL, DL, NextBlockVT, Block,
6254 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
6255 }
6256 NextBlocks.push_back(Lo);
6257 NextBlocks.push_back(
6258 DAG.getNode(LoongArchISD::VEXTH, DL, NextBlockVT, Block));
6259 }
6260
6261 Blocks = std::move(NextBlocks);
6262 SrcVT = NextBlockVT;
6263 SrcEltBits = NextEltBits;
6264 }
6265
6266 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6267 break;
6268 }
6269 case ISD::FP_EXTEND:
6270 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6271 // no target-specific lowering is required. Leave it unchanged and rely on
6272 // the default type legalization.
6273 break;
6274 }
6275}
6276
6277/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6279 SelectionDAG &DAG) {
6280 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6281
6282 MVT VT = N->getSimpleValueType(0);
6283 if (!VT.is128BitVector() && !VT.is256BitVector())
6284 return SDValue();
6285
6286 SDValue X, Y;
6287 SDValue N0 = N->getOperand(0);
6288 SDValue N1 = N->getOperand(1);
6289
6290 if (SDValue Not = isNOT(N0, DAG)) {
6291 X = Not;
6292 Y = N1;
6293 } else if (SDValue Not = isNOT(N1, DAG)) {
6294 X = Not;
6295 Y = N0;
6296 } else
6297 return SDValue();
6298
6299 X = DAG.getBitcast(VT, X);
6300 Y = DAG.getBitcast(VT, Y);
6301 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6302}
6303
6304static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6305 unsigned MinSizeInBits) {
6308
6309 if (!Node)
6310 return false;
6311
6312 APInt SplatUndef;
6313 unsigned SplatBitSize;
6314 bool HasAnyUndefs;
6315
6316 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6317 HasAnyUndefs, MinSizeInBits,
6318 /*IsBigEndian=*/false);
6319}
6320
6321static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6322 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6323 if (!BV)
6324 return SDValue();
6325
6326 SDValue Src;
6327 int Start = -1;
6328
6329 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6330 SDValue Op = BV->getOperand(i);
6331 if (Op.isUndef())
6332 continue;
6333 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6334 return SDValue();
6335
6336 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6337 if (!IdxC)
6338 return SDValue();
6339
6340 unsigned EltIdx = IdxC->getZExtValue();
6341 if (Start < 0)
6342 Start = (int)EltIdx - (int)(i * 2);
6343 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6344 return SDValue();
6345
6346 SDValue CurSrc = Op.getOperand(0);
6347 if (!Src)
6348 Src = CurSrc;
6349 else if (Src != CurSrc)
6350 return SDValue();
6351 }
6352
6353 if (!Src || Start < 0)
6354 return SDValue();
6355
6356 StartIndex = (unsigned)Start;
6357 return Src;
6358}
6359
6360static SDValue
6363 if (!Subtarget.hasExtLSX())
6364 return SDValue();
6365
6366 unsigned Opc = N->getOpcode();
6367 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6368
6369 EVT VT = N->getValueType(0);
6370 SDLoc DL(N);
6371
6372 SDValue LHS = N->getOperand(0);
6373 SDValue RHS = N->getOperand(1);
6374
6375 bool isSigned;
6376 unsigned ExtOpc = LHS.getOpcode();
6377 if (ExtOpc == ISD::SIGN_EXTEND)
6378 isSigned = true;
6379 else if (ExtOpc == ISD::ZERO_EXTEND)
6380 isSigned = false;
6381 else
6382 return SDValue();
6383
6384 if (ExtOpc != RHS.getOpcode())
6385 return SDValue();
6386
6387 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6388 return SDValue();
6389
6390 unsigned OddIdx, EvenIdx;
6391 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6392 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6393
6394 if (!LHSVec || !RHSVec)
6395 return SDValue();
6396 if (OddIdx != 1 || EvenIdx != 0)
6397 return SDValue();
6398 if (LHSVec.getValueType() != RHSVec.getValueType())
6399 return SDValue();
6400
6401 EVT SrcVT = LHSVec.getValueType();
6402 EVT SrcEltVT = SrcVT.getVectorElementType();
6403 EVT DstEltVT = VT.getVectorElementType();
6404 auto &TLI = DAG.getTargetLoweringInfo();
6405
6406 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6407 return SDValue();
6408 if (!SrcVT.isVector() || !VT.isVector())
6409 return SDValue();
6410 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6411 return SDValue();
6412 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6413 return SDValue();
6414 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6415 return SDValue();
6416
6417 unsigned TargetOpc;
6418 if (Opc == ISD::ADD)
6419 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6420 else
6421 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6422
6423 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6424}
6425
6430 return V;
6431
6432 if (DCI.isBeforeLegalizeOps())
6433 return SDValue();
6434
6435 EVT VT = N->getValueType(0);
6436 if (!VT.isVector())
6437 return SDValue();
6438
6439 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6440 return SDValue();
6441
6442 EVT EltVT = VT.getVectorElementType();
6443 if (!EltVT.isInteger())
6444 return SDValue();
6445
6446 // match:
6447 //
6448 // add
6449 // (and
6450 // (srl X, shift-1) / X
6451 // 1)
6452 // (srl/sra X, shift)
6453
6454 SDValue Add0 = N->getOperand(0);
6455 SDValue Add1 = N->getOperand(1);
6456 SDValue And;
6457 SDValue Shr;
6458
6459 if (Add0.getOpcode() == ISD::AND) {
6460 And = Add0;
6461 Shr = Add1;
6462 } else if (Add1.getOpcode() == ISD::AND) {
6463 And = Add1;
6464 Shr = Add0;
6465 } else {
6466 return SDValue();
6467 }
6468
6469 // match:
6470 //
6471 // srl/sra X, shift
6472
6473 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6474 return SDValue();
6475
6476 SDValue X = Shr.getOperand(0);
6477 SDValue Shift = Shr.getOperand(1);
6478 APInt ShiftVal;
6479
6480 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6481 return SDValue();
6482
6483 if (ShiftVal == 0)
6484 return SDValue();
6485
6486 // match:
6487 //
6488 // and
6489 // (srl X, shift-1) / X
6490 // 1
6491
6492 SDValue One = And.getOperand(1);
6493 APInt SplatVal;
6494
6495 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6496 return SDValue();
6497
6498 if (SplatVal != 1)
6499 return SDValue();
6500
6501 if (And.getOperand(0) == X) {
6502 // match:
6503 //
6504 // shift == 1
6505
6506 if (ShiftVal != 1)
6507 return SDValue();
6508 } else {
6509 // match:
6510 //
6511 // srl X, shift-1
6512
6513 SDValue Srl = And.getOperand(0);
6514
6515 if (Srl.getOpcode() != ISD::SRL)
6516 return SDValue();
6517
6518 if (Srl.getOperand(0) != X)
6519 return SDValue();
6520
6521 // match:
6522 //
6523 // shift-1
6524
6525 SDValue ShiftMinus1 = Srl.getOperand(1);
6526
6527 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6528 return SDValue();
6529
6530 if (ShiftVal != (SplatVal + 1))
6531 return SDValue();
6532 }
6533
6534 // We matched a rounded right shift pattern and can lower it
6535 // to a single vector rounded shift instruction.
6536
6537 SDLoc DL(N);
6538 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6539 : LoongArchISD::VSRAR,
6540 DL, VT, X, Shift);
6541}
6542
6546 if (DCI.isBeforeLegalizeOps())
6547 return SDValue();
6548
6549 SDValue FirstOperand = N->getOperand(0);
6550 SDValue SecondOperand = N->getOperand(1);
6551 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6552 EVT ValTy = N->getValueType(0);
6553 SDLoc DL(N);
6554 uint64_t lsb, msb;
6555 unsigned SMIdx, SMLen;
6556 ConstantSDNode *CN;
6557 SDValue NewOperand;
6558 MVT GRLenVT = Subtarget.getGRLenVT();
6559
6560 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6561 return R;
6562
6563 // BSTRPICK requires the 32S feature.
6564 if (!Subtarget.has32S())
6565 return SDValue();
6566
6567 // Op's second operand must be a shifted mask.
6568 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6569 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6570 return SDValue();
6571
6572 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6573 // Pattern match BSTRPICK.
6574 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6575 // => BSTRPICK $dst, $src, msb, lsb
6576 // where msb = lsb + len - 1
6577
6578 // The second operand of the shift must be an immediate.
6579 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6580 return SDValue();
6581
6582 lsb = CN->getZExtValue();
6583
6584 // Return if the shifted mask does not start at bit 0 or the sum of its
6585 // length and lsb exceeds the word's size.
6586 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6587 return SDValue();
6588
6589 NewOperand = FirstOperand.getOperand(0);
6590 } else {
6591 // Pattern match BSTRPICK.
6592 // $dst = and $src, (2**len- 1) , if len > 12
6593 // => BSTRPICK $dst, $src, msb, lsb
6594 // where lsb = 0 and msb = len - 1
6595
6596 // If the mask is <= 0xfff, andi can be used instead.
6597 if (CN->getZExtValue() <= 0xfff)
6598 return SDValue();
6599
6600 // Return if the MSB exceeds.
6601 if (SMIdx + SMLen > ValTy.getSizeInBits())
6602 return SDValue();
6603
6604 if (SMIdx > 0) {
6605 // Omit if the constant has more than 2 uses. This a conservative
6606 // decision. Whether it is a win depends on the HW microarchitecture.
6607 // However it should always be better for 1 and 2 uses.
6608 if (CN->use_size() > 2)
6609 return SDValue();
6610 // Return if the constant can be composed by a single LU12I.W.
6611 if ((CN->getZExtValue() & 0xfff) == 0)
6612 return SDValue();
6613 // Return if the constand can be composed by a single ADDI with
6614 // the zero register.
6615 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6616 return SDValue();
6617 }
6618
6619 lsb = SMIdx;
6620 NewOperand = FirstOperand;
6621 }
6622
6623 msb = lsb + SMLen - 1;
6624 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6625 DAG.getConstant(msb, DL, GRLenVT),
6626 DAG.getConstant(lsb, DL, GRLenVT));
6627 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6628 return NR0;
6629 // Try to optimize to
6630 // bstrpick $Rd, $Rs, msb, lsb
6631 // slli $Rd, $Rd, lsb
6632 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6633 DAG.getConstant(lsb, DL, GRLenVT));
6634}
6635
6636// Return the original source vector if N consists of the half
6637// of each 128-bit lane.
6640
6641 EVT DstVT = N.getValueType();
6642 if (!DstVT.isVector())
6643 return SDValue();
6644
6645 unsigned NumElts = DstVT.getVectorNumElements();
6646
6647 // LSX canonical form:
6648 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6649 SDValue Src = N.getOperand(0);
6650 EVT SrcVT = Src.getValueType();
6651
6652 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6653 return SDValue();
6654 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6655 return SDValue();
6656 if (SrcVT.getVectorNumElements() != NumElts * 2)
6657 return SDValue();
6658 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6659 return SDValue();
6660
6661 return Src;
6662 }
6663
6664 // LASX canonical form:
6665 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6666 if (!BV)
6667 return SDValue();
6668
6669 if (NumElts % 2 != 0)
6670 return SDValue();
6671
6672 SDValue Src;
6673 EVT SrcVT;
6674
6675 for (unsigned I = 0; I != NumElts; ++I) {
6676 SDValue Elt = BV->getOperand(I);
6677 if (Elt.isUndef())
6678 continue;
6680 return SDValue();
6681
6682 SDValue ThisSrc = Elt.getOperand(0);
6683 SDValue Idx = Elt.getOperand(1);
6684 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6685 if (!CI)
6686 return SDValue();
6687
6688 if (!Src) {
6689 Src = ThisSrc;
6690 SrcVT = Src.getValueType();
6691 if (!SrcVT.isVector())
6692 return SDValue();
6693
6694 if (!SrcVT.is256BitVector())
6695 return SDValue();
6696 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6697 return SDValue();
6698 if (SrcVT.getVectorNumElements() != NumElts * 2)
6699 return SDValue();
6700 } else if (ThisSrc != Src) {
6701 return SDValue();
6702 }
6703
6704 unsigned Half = NumElts / 2;
6705 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6706 ExpectedIdx += isLow ? 0 : Half;
6707
6708 if (CI->getZExtValue() != ExpectedIdx)
6709 return SDValue();
6710 }
6711
6712 return Src;
6713}
6714
6718 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6719
6720 EVT VT = N->getValueType(0);
6721 SDLoc DL(N);
6722
6723 SDValue LHS = N->getOperand(0);
6724 SDValue RHS = N->getOperand(1);
6725
6726 bool isSigned;
6727 unsigned ExtOpc = LHS.getOpcode();
6728 if (ExtOpc == ISD::SIGN_EXTEND)
6729 isSigned = true;
6730 else if (ExtOpc == ISD::ZERO_EXTEND)
6731 isSigned = false;
6732 else
6733 return SDValue();
6734
6735 if (!LHS.hasOneUse())
6736 return SDValue();
6737
6738 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
6739 N->getValueSizeInBits(0) != LHS->getOperand(0).getValueSizeInBits() * 2)
6740 return SDValue();
6741
6742 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6743 if (!Vec)
6744 return SDValue();
6745
6746 EVT SrcVT = Vec.getValueType();
6747 EVT SrcEltVT = SrcVT.getVectorElementType();
6748 EVT DstEltVT = VT.getVectorElementType();
6749 APInt Imm;
6750 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6751 return SDValue();
6752 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6753 return SDValue();
6754
6755 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6756 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6757 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6758}
6759
6763 // BSTRPICK requires the 32S feature.
6764 if (!Subtarget.has32S())
6765 return SDValue();
6766
6767 if (DCI.isBeforeLegalizeOps())
6768 return SDValue();
6769
6770 // $dst = srl (and $src, Mask), Shamt
6771 // =>
6772 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6773 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6774 //
6775
6776 SDValue FirstOperand = N->getOperand(0);
6777 ConstantSDNode *CN;
6778 EVT ValTy = N->getValueType(0);
6779 SDLoc DL(N);
6780 MVT GRLenVT = Subtarget.getGRLenVT();
6781 unsigned MaskIdx, MaskLen;
6782 uint64_t Shamt;
6783
6784 // The first operand must be an AND and the second operand of the AND must be
6785 // a shifted mask.
6786 if (FirstOperand.getOpcode() != ISD::AND ||
6787 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6788 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6789 return SDValue();
6790
6791 // The second operand (shift amount) must be an immediate.
6792 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6793 return SDValue();
6794
6795 Shamt = CN->getZExtValue();
6796 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6797 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6798 FirstOperand->getOperand(0),
6799 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6800 DAG.getConstant(Shamt, DL, GRLenVT));
6801
6802 return SDValue();
6803}
6804
6809 return V;
6810
6811 return SDValue();
6812}
6813
6814// Helper to peek through bitops/trunc/setcc to determine size of source vector.
6815// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
6816static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
6817 unsigned Depth) {
6818 // Limit recursion.
6820 return false;
6821 switch (Src.getOpcode()) {
6822 case ISD::SETCC:
6823 case ISD::TRUNCATE:
6824 return Src.getOperand(0).getValueSizeInBits() == Size;
6825 case ISD::FREEZE:
6826 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
6827 case ISD::AND:
6828 case ISD::XOR:
6829 case ISD::OR:
6830 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
6831 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
6832 case ISD::SELECT:
6833 case ISD::VSELECT:
6834 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
6835 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
6836 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
6837 case ISD::BUILD_VECTOR:
6838 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
6839 ISD::isBuildVectorAllOnes(Src.getNode());
6840 }
6841 return false;
6842}
6843
6844// Helper to push sign extension of vXi1 SETCC result through bitops.
6846 SDValue Src, const SDLoc &DL) {
6847 switch (Src.getOpcode()) {
6848 case ISD::SETCC:
6849 case ISD::FREEZE:
6850 case ISD::TRUNCATE:
6851 case ISD::BUILD_VECTOR:
6852 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6853 case ISD::AND:
6854 case ISD::XOR:
6855 case ISD::OR:
6856 return DAG.getNode(
6857 Src.getOpcode(), DL, SExtVT,
6858 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
6859 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
6860 case ISD::SELECT:
6861 case ISD::VSELECT:
6862 return DAG.getSelect(
6863 DL, SExtVT, Src.getOperand(0),
6864 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
6865 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
6866 }
6867 llvm_unreachable("Unexpected node type for vXi1 sign extension");
6868}
6869
6870static SDValue
6874 SDLoc DL(N);
6875 EVT VT = N->getValueType(0);
6876 SDValue Src = N->getOperand(0);
6877 EVT SrcVT = Src.getValueType();
6878
6879 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
6880 return SDValue();
6881
6882 bool UseLASX;
6883 unsigned Opc = ISD::DELETED_NODE;
6884 EVT CmpVT = Src.getOperand(0).getValueType();
6885 EVT EltVT = CmpVT.getVectorElementType();
6886
6887 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
6888 UseLASX = false;
6889 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
6890 CmpVT.getSizeInBits() == 256)
6891 UseLASX = true;
6892 else
6893 return SDValue();
6894
6895 SDValue SrcN1 = Src.getOperand(1);
6896 switch (Src.getOperandCondCode(2)) {
6897 default:
6898 break;
6899 case ISD::SETEQ:
6900 // x == 0 => not (vmsknez.b x)
6901 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6902 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
6903 break;
6904 case ISD::SETGT:
6905 // x > -1 => vmskgez.b x
6906 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
6907 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6908 break;
6909 case ISD::SETGE:
6910 // x >= 0 => vmskgez.b x
6911 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6912 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6913 break;
6914 case ISD::SETLT:
6915 // x < 0 => vmskltz.{b,h,w,d} x
6916 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
6917 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6918 EltVT == MVT::i64))
6919 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6920 break;
6921 case ISD::SETLE:
6922 // x <= -1 => vmskltz.{b,h,w,d} x
6923 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
6924 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6925 EltVT == MVT::i64))
6926 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6927 break;
6928 case ISD::SETNE:
6929 // x != 0 => vmsknez.b x
6930 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6931 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
6932 break;
6933 }
6934
6935 if (Opc == ISD::DELETED_NODE)
6936 return SDValue();
6937
6938 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
6940 V = DAG.getZExtOrTrunc(V, DL, T);
6941 return DAG.getBitcast(VT, V);
6942}
6943
6947 SDLoc DL(N);
6948 EVT VT = N->getValueType(0);
6949 SDValue Src = N->getOperand(0);
6950 EVT SrcVT = Src.getValueType();
6951 MVT GRLenVT = Subtarget.getGRLenVT();
6952
6953 if (!DCI.isBeforeLegalizeOps())
6954 return SDValue();
6955
6956 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
6957 return SDValue();
6958
6959 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
6961 if (Res)
6962 return Res;
6963
6964 // Generate vXi1 using [X]VMSKLTZ
6965 MVT SExtVT;
6966 unsigned Opc;
6967 bool UseLASX = false;
6968 bool PropagateSExt = false;
6969
6970 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
6971 EVT CmpVT = Src.getOperand(0).getValueType();
6972 if (CmpVT.getSizeInBits() > 256)
6973 return SDValue();
6974 }
6975
6976 switch (SrcVT.getSimpleVT().SimpleTy) {
6977 default:
6978 return SDValue();
6979 case MVT::v2i1:
6980 SExtVT = MVT::v2i64;
6981 break;
6982 case MVT::v4i1:
6983 SExtVT = MVT::v4i32;
6984 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6985 SExtVT = MVT::v4i64;
6986 UseLASX = true;
6987 PropagateSExt = true;
6988 }
6989 break;
6990 case MVT::v8i1:
6991 SExtVT = MVT::v8i16;
6992 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6993 SExtVT = MVT::v8i32;
6994 UseLASX = true;
6995 PropagateSExt = true;
6996 }
6997 break;
6998 case MVT::v16i1:
6999 SExtVT = MVT::v16i8;
7000 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
7001 SExtVT = MVT::v16i16;
7002 UseLASX = true;
7003 PropagateSExt = true;
7004 }
7005 break;
7006 case MVT::v32i1:
7007 SExtVT = MVT::v32i8;
7008 UseLASX = true;
7009 break;
7010 };
7011 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
7012 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
7013
7014 SDValue V;
7015 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
7016 if (Src.getSimpleValueType() == MVT::v32i8) {
7017 SDValue Lo, Hi;
7018 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
7019 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
7020 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
7021 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
7022 DAG.getShiftAmountConstant(16, GRLenVT, DL));
7023 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
7024 } else if (UseLASX) {
7025 return SDValue();
7026 }
7027 }
7028
7029 if (!V) {
7030 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
7031 V = DAG.getNode(Opc, DL, GRLenVT, Src);
7032 }
7033
7035 V = DAG.getZExtOrTrunc(V, DL, T);
7036 return DAG.getBitcast(VT, V);
7037}
7038
7042 MVT GRLenVT = Subtarget.getGRLenVT();
7043 EVT ValTy = N->getValueType(0);
7044 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
7045 ConstantSDNode *CN0, *CN1;
7046 SDLoc DL(N);
7047 unsigned ValBits = ValTy.getSizeInBits();
7048 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
7049 unsigned Shamt;
7050 bool SwapAndRetried = false;
7051
7052 // BSTRPICK requires the 32S feature.
7053 if (!Subtarget.has32S())
7054 return SDValue();
7055
7056 if (DCI.isBeforeLegalizeOps())
7057 return SDValue();
7058
7059 if (ValBits != 32 && ValBits != 64)
7060 return SDValue();
7061
7062Retry:
7063 // 1st pattern to match BSTRINS:
7064 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
7065 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
7066 // =>
7067 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
7068 if (N0.getOpcode() == ISD::AND &&
7069 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7070 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7071 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
7072 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7073 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
7074 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
7075 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7076 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
7077 (MaskIdx0 + MaskLen0 <= ValBits)) {
7078 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
7079 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7080 N1.getOperand(0).getOperand(0),
7081 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7082 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7083 }
7084
7085 // 2nd pattern to match BSTRINS:
7086 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
7087 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
7088 // =>
7089 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
7090 if (N0.getOpcode() == ISD::AND &&
7091 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7092 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7093 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7094 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7095 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
7096 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7097 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
7098 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
7099 (MaskIdx0 + MaskLen0 <= ValBits)) {
7100 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
7101 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7102 N1.getOperand(0).getOperand(0),
7103 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7104 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7105 }
7106
7107 // 3rd pattern to match BSTRINS:
7108 // R = or (and X, mask0), (and Y, mask1)
7109 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
7110 // =>
7111 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
7112 // where msb = lsb + size - 1
7113 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
7114 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7115 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7116 (MaskIdx0 + MaskLen0 <= 64) &&
7117 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
7118 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7119 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
7120 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7121 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
7122 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
7123 DAG.getConstant(ValBits == 32
7124 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7125 : (MaskIdx0 + MaskLen0 - 1),
7126 DL, GRLenVT),
7127 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7128 }
7129
7130 // 4th pattern to match BSTRINS:
7131 // R = or (and X, mask), (shl Y, shamt)
7132 // where mask = (2**shamt - 1)
7133 // =>
7134 // R = BSTRINS X, Y, ValBits - 1, shamt
7135 // where ValBits = 32 or 64
7136 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
7137 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7138 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
7139 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7140 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
7141 (MaskIdx0 + MaskLen0 <= ValBits)) {
7142 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
7143 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7144 N1.getOperand(0),
7145 DAG.getConstant((ValBits - 1), DL, GRLenVT),
7146 DAG.getConstant(Shamt, DL, GRLenVT));
7147 }
7148
7149 // 5th pattern to match BSTRINS:
7150 // R = or (and X, mask), const
7151 // where ~mask = (2**size - 1) << lsb, mask & const = 0
7152 // =>
7153 // R = BSTRINS X, (const >> lsb), msb, lsb
7154 // where msb = lsb + size - 1
7155 if (N0.getOpcode() == ISD::AND &&
7156 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7157 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7158 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
7159 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7160 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
7161 return DAG.getNode(
7162 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7163 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
7164 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7165 : (MaskIdx0 + MaskLen0 - 1),
7166 DL, GRLenVT),
7167 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7168 }
7169
7170 // 6th pattern.
7171 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
7172 // by the incoming bits are known to be zero.
7173 // =>
7174 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
7175 //
7176 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
7177 // pattern is more common than the 1st. So we put the 1st before the 6th in
7178 // order to match as many nodes as possible.
7179 ConstantSDNode *CNMask, *CNShamt;
7180 unsigned MaskIdx, MaskLen;
7181 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7182 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7183 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7184 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7185 CNShamt->getZExtValue() + MaskLen <= ValBits) {
7186 Shamt = CNShamt->getZExtValue();
7187 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
7188 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7189 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
7190 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7191 N1.getOperand(0).getOperand(0),
7192 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
7193 DAG.getConstant(Shamt, DL, GRLenVT));
7194 }
7195 }
7196
7197 // 7th pattern.
7198 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
7199 // overwritten by the incoming bits are known to be zero.
7200 // =>
7201 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7202 //
7203 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7204 // before the 7th in order to match as many nodes as possible.
7205 if (N1.getOpcode() == ISD::AND &&
7206 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7207 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7208 N1.getOperand(0).getOpcode() == ISD::SHL &&
7209 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7210 CNShamt->getZExtValue() == MaskIdx) {
7211 APInt ShMask(ValBits, CNMask->getZExtValue());
7212 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7213 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7214 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7215 N1.getOperand(0).getOperand(0),
7216 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7217 DAG.getConstant(MaskIdx, DL, GRLenVT));
7218 }
7219 }
7220
7221 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7222 if (!SwapAndRetried) {
7223 std::swap(N0, N1);
7224 SwapAndRetried = true;
7225 goto Retry;
7226 }
7227
7228 SwapAndRetried = false;
7229Retry2:
7230 // 8th pattern.
7231 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7232 // the incoming bits are known to be zero.
7233 // =>
7234 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7235 //
7236 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7237 // we put it here in order to match as many nodes as possible or generate less
7238 // instructions.
7239 if (N1.getOpcode() == ISD::AND &&
7240 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7241 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7242 APInt ShMask(ValBits, CNMask->getZExtValue());
7243 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7244 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7245 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7246 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7247 N1->getOperand(0),
7248 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7249 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7250 DAG.getConstant(MaskIdx, DL, GRLenVT));
7251 }
7252 }
7253 // Swap N0/N1 and retry.
7254 if (!SwapAndRetried) {
7255 std::swap(N0, N1);
7256 SwapAndRetried = true;
7257 goto Retry2;
7258 }
7259
7260 return SDValue();
7261}
7262
7264 ExtType = ISD::NON_EXTLOAD;
7265
7266 switch (V.getNode()->getOpcode()) {
7267 case ISD::LOAD: {
7268 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7269 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7270 (LoadNode->getMemoryVT() == MVT::i16)) {
7271 ExtType = LoadNode->getExtensionType();
7272 return true;
7273 }
7274 return false;
7275 }
7276 case ISD::AssertSext: {
7277 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7278 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7279 ExtType = ISD::SEXTLOAD;
7280 return true;
7281 }
7282 return false;
7283 }
7284 case ISD::AssertZext: {
7285 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7286 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7287 ExtType = ISD::ZEXTLOAD;
7288 return true;
7289 }
7290 return false;
7291 }
7292 default:
7293 return false;
7294 }
7295
7296 return false;
7297}
7298
7299// Fold a lane-mask extraction that is only compared against zero into one of
7300// all-lane check instructions, which write the results into fcc register, so
7301// BCEQZ could use it directly.
7302//
7303// (VMSKLTZ X) != 0 -> VSETNEZ.V X
7304// (VMSKLTZ X) == 0 -> VSETEQZ.V X
7305//
7306// This is valid when X is the result of a vector compare instruction,
7307// so each lane of X has to be all-ones or all-zeros.
7309 const SDLoc &DL, SelectionDAG &DAG,
7311 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7312 return SDValue();
7313 if (!isNullConstant(RHS))
7314 return SDValue();
7315
7316 unsigned MskOpc = LHS.getOpcode();
7317 if (MskOpc != LoongArchISD::VMSKLTZ && MskOpc != LoongArchISD::XVMSKLTZ)
7318 return SDValue();
7319 // Keeping the mask alive for another user would defeat the purpose.
7320 if (!LHS.hasOneUse())
7321 return SDValue();
7322
7323 SDValue Src = LHS.getOperand(0);
7324 EVT SrcVT = Src.getValueType();
7325 // Make sure every lane is all-ones or all-zeros.
7326 if (!SrcVT.isVector() ||
7327 DAG.ComputeNumSignBits(Src) != SrcVT.getScalarSizeInBits())
7328 return SDValue();
7329
7330 return DAG.getNode(CC == ISD::SETNE ? LoongArchISD::VANYNONZERO
7331 : LoongArchISD::VALLZERO,
7332 DL, Subtarget.getGRLenVT(), Src);
7333}
7334
7335// Eliminate redundant truncation and zero-extension nodes.
7336// * Case 1:
7337// +------------+ +------------+ +------------+
7338// | Input1 | | Input2 | | CC |
7339// +------------+ +------------+ +------------+
7340// | | |
7341// V V +----+
7342// +------------+ +------------+ |
7343// | TRUNCATE | | TRUNCATE | |
7344// +------------+ +------------+ |
7345// | | |
7346// V V |
7347// +------------+ +------------+ |
7348// | ZERO_EXT | | ZERO_EXT | |
7349// +------------+ +------------+ |
7350// | | |
7351// | +-------------+ |
7352// V V | |
7353// +----------------+ | |
7354// | AND | | |
7355// +----------------+ | |
7356// | | |
7357// +---------------+ | |
7358// | | |
7359// V V V
7360// +-------------+
7361// | CMP |
7362// +-------------+
7363// * Case 2:
7364// +------------+ +------------+ +-------------+ +------------+ +------------+
7365// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7366// +------------+ +------------+ +-------------+ +------------+ +------------+
7367// | | | | |
7368// V | | | |
7369// +------------+ | | | |
7370// | XOR |<---------------------+ | |
7371// +------------+ | | |
7372// | | | |
7373// V V +---------------+ |
7374// +------------+ +------------+ | |
7375// | TRUNCATE | | TRUNCATE | | +-------------------------+
7376// +------------+ +------------+ | |
7377// | | | |
7378// V V | |
7379// +------------+ +------------+ | |
7380// | ZERO_EXT | | ZERO_EXT | | |
7381// +------------+ +------------+ | |
7382// | | | |
7383// V V | |
7384// +----------------+ | |
7385// | AND | | |
7386// +----------------+ | |
7387// | | |
7388// +---------------+ | |
7389// | | |
7390// V V V
7391// +-------------+
7392// | CMP |
7393// +-------------+
7397 ISD::CondCode CC = N->getOperandCondCode(2);
7398
7399 if (N->getValueType(0) == Subtarget.getGRLenVT())
7400 if (SDValue V = foldVMskZeroTest(N->getOperand(0), N->getOperand(1), CC,
7401 SDLoc(N), DAG, Subtarget))
7402 return V;
7403
7404 SDNode *AndNode = N->getOperand(0).getNode();
7405 if (AndNode->getOpcode() != ISD::AND)
7406 return SDValue();
7407
7408 SDValue AndInputValue2 = AndNode->getOperand(1);
7409 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7410 return SDValue();
7411
7412 SDValue CmpInputValue = N->getOperand(1);
7413 SDValue AndInputValue1 = AndNode->getOperand(0);
7414 if (AndInputValue1.getOpcode() == ISD::XOR) {
7415 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7416 return SDValue();
7417 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7418 if (!CN || !CN->isAllOnes())
7419 return SDValue();
7420 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7421 if (!CN || !CN->isZero())
7422 return SDValue();
7423 AndInputValue1 = AndInputValue1.getOperand(0);
7424 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7425 return SDValue();
7426 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7427 if (AndInputValue2 != CmpInputValue)
7428 return SDValue();
7429 } else {
7430 return SDValue();
7431 }
7432
7433 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7434 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7435 return SDValue();
7436
7437 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7438 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7439 return SDValue();
7440
7441 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7442 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7443 ISD::LoadExtType ExtType1;
7444 ISD::LoadExtType ExtType2;
7445
7446 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7447 !checkValueWidth(TruncInputValue2, ExtType2))
7448 return SDValue();
7449
7450 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7451 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7452 return SDValue();
7453
7454 if ((ExtType2 != ISD::ZEXTLOAD) &&
7455 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7456 return SDValue();
7457
7458 // These truncation and zero-extension nodes are not necessary, remove them.
7459 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7460 TruncInputValue1, TruncInputValue2);
7461 SDValue NewSetCC =
7462 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7463 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7464 return SDValue(N, 0);
7465}
7466
7467// Strip a single outer ISD::SIGN_EXTEND_INREG from \p V, if present, and
7468// return the inner value together with the narrow VT it was extending
7469// from. If no such node is present, returns \p V unchanged and an invalid
7470// EVT.
7471//
7472// i32 (and other sub-GRLen) arithmetic is legalized to operate on the full
7473// GRLen-width register, with a `sign_extend_inreg` re-normalizing the
7474// result back into the narrow type's range afterwards (see e.g. the
7475// `add i32` -> `add` + `sign_extend_inreg ..., i32` legalization). Any
7476// combine that reassociates such a binop must track and reapply this
7477// extension, otherwise the transformed code can produce a value whose
7478// high bits no longer match the narrow-type semantics.
7479static std::pair<SDValue, EVT> stripSignExtendInReg(SDValue V) {
7480 if (V.getOpcode() == ISD::SIGN_EXTEND_INREG)
7481 return {V.getOperand(0), cast<VTSDNode>(V.getOperand(1))->getVT()};
7482 return {V, EVT()};
7483}
7484
7485// Try to match \p BinV (after optionally stripping an outer
7486// sign_extend_inreg) as a supported binary operation that has \p X as one
7487// of its operands, returning the matched opcode, the other operand (the
7488// "delta"), and the narrow VT of the sign_extend_inreg that was stripped
7489// (invalid EVT if none was present).
7490//
7491// For commutative ops (add/or/xor), \p X may be either operand, since
7492// `binop(X, Y) == binop(Y, X)` and the identity element (0) works on
7493// either side.
7494//
7495// For `sub`, the operation is NOT commutative: `sub(X, Y) != sub(Y, X)`.
7496// Only `sub(X, Y)` (i.e. \p X is the *minuend*, the first operand) can be
7497// rewritten using the identity `X - 0 == X`. If \p X were the *subtrahend*
7498// (second operand, i.e. the pattern is actually `sub(Y, X)`), there is no
7499// way to express `cond ? (Y - X) : X` (or the symmetric case) as
7500// `X op (select ...)` without introducing an extra negation, so that case
7501// must be rejected instead of "optimized" into worse code.
7502static std::tuple<unsigned, SDValue, EVT>
7504 auto [Inner, ExtVT] = stripSignExtendInReg(BinV);
7505
7506 unsigned Opc = Inner.getOpcode();
7507 switch (Opc) {
7508 case ISD::ADD:
7509 case ISD::OR:
7510 case ISD::XOR:
7511 if (Inner.getOperand(0) == X)
7512 return {Opc, Inner.getOperand(1), ExtVT};
7513 if (Inner.getOperand(1) == X)
7514 return {Opc, Inner.getOperand(0), ExtVT};
7515 return {0, SDValue(), EVT()};
7516 case ISD::SUB:
7517 // Only accept X as the minuend (first operand); see comment above.
7518 if (Inner.getOperand(0) == X)
7519 return {Opc, Inner.getOperand(1), ExtVT};
7520 return {0, SDValue(), EVT()};
7521 default:
7522 return {0, SDValue(), EVT()};
7523 }
7524}
7525
7526// Try to combine:
7527// select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
7528// select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
7529// for binop in {add, or, xor, sub}, where 0 is the identity element of the
7530// respective operation, additionally handling the common legalized form
7531// where the binop result is wrapped in a `sign_extend_inreg` (as happens
7532// for sub-GRLen types such as i32 on a 64-bit GRLen target). See
7533// matchBinOpWithSharedOperand() for the restrictions applied to
7534// non-commutative operations (currently only `sub`).
7538 if (DCI.isBeforeLegalizeOps())
7539 return SDValue();
7540
7541 EVT VT = N->getValueType(0);
7542 // Restrict to the scalar GRLen integer type that maskeqz/masknez operate
7543 // on; this also naturally excludes float and vector selects.
7544 if (VT != Subtarget.getGRLenVT())
7545 return SDValue();
7546
7547 SDValue Cond = N->getOperand(0);
7548 SDValue TrueV = N->getOperand(1);
7549 SDValue FalseV = N->getOperand(2);
7550 SDLoc DL(N);
7551
7552 auto TryFold = [&](SDValue BinV, SDValue SharedV,
7553 bool BinIsTrueArm) -> SDValue {
7554 auto [Opc, Delta, ExtVT] = matchBinOpWithSharedOperand(BinV, SharedV);
7555 if (!Opc)
7556 return SDValue();
7557
7558 // Avoid infinite combine loops: bail out if Delta is trivially the
7559 // same node we would otherwise be selecting on (shouldn't normally
7560 // happen, but guards against degenerate/self-referential IR).
7561 if (Delta.getNode() == N)
7562 return SDValue();
7563
7564 SDValue Zero = DAG.getConstant(0, DL, VT);
7565 SDValue NewSel = BinIsTrueArm ? DAG.getSelect(DL, VT, Cond, Delta, Zero)
7566 : DAG.getSelect(DL, VT, Cond, Zero, Delta);
7567 SDValue NewBin = DAG.getNode(Opc, DL, VT, SharedV, NewSel);
7568
7569 // If the original binop result was normalized back into a narrower
7570 // type via sign_extend_inreg (e.g. i32 arithmetic on a 64-bit GRLen
7571 // target), the new binop must be re-normalized the same way: SharedV
7572 // is already known-sign-extended for that narrow type, but NewSel
7573 // (Delta or 0, selected) combined with SharedV via Opc can still
7574 // produce a 64-bit result whose high bits don't match the narrow
7575 // type's sign-extended representation.
7576 if (ExtVT != EVT())
7577 NewBin = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, NewBin,
7578 DAG.getValueType(ExtVT));
7579
7580 return NewBin;
7581 };
7582
7583 if (SDValue R = TryFold(TrueV, FalseV, /*BinIsTrueArm=*/true))
7584 return R;
7585 if (SDValue R = TryFold(FalseV, TrueV, /*BinIsTrueArm=*/false))
7586 return R;
7587
7588 return SDValue();
7589}
7590
7591// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7595 if (DCI.isBeforeLegalizeOps())
7596 return SDValue();
7597
7598 SDValue Src = N->getOperand(0);
7599 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7600 return SDValue();
7601
7602 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7603 Src.getOperand(0));
7604}
7605
7606// Perform common combines for BR_CC and SELECT_CC conditions.
7607static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7609 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7610
7611 // As far as arithmetic right shift always saves the sign,
7612 // shift can be omitted.
7613 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7614 // setge (sra X, N), 0 -> setge X, 0
7615 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7616 LHS.getOpcode() == ISD::SRA) {
7617 LHS = LHS.getOperand(0);
7618 return true;
7619 }
7620
7621 if (!ISD::isIntEqualitySetCC(CCVal))
7622 return false;
7623
7624 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7625 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7626 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7627 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7628 // If we're looking for eq 0 instead of ne 0, we need to invert the
7629 // condition.
7630 bool Invert = CCVal == ISD::SETEQ;
7631 CCVal = LHS.getOperandCondCode(2);
7632 if (Invert)
7633 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7634
7635 RHS = LHS.getOperand(1);
7636 LHS = LHS.getOperand(0);
7637 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7638
7639 CC = DAG.getCondCode(CCVal);
7640 return true;
7641 }
7642
7643 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7644 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7645 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7646 SDValue LHS0 = LHS.getOperand(0);
7647 if (LHS0.getOpcode() == ISD::AND &&
7648 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7649 uint64_t Mask = LHS0.getConstantOperandVal(1);
7650 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7651 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7652 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7653 CC = DAG.getCondCode(CCVal);
7654
7655 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7656 LHS = LHS0.getOperand(0);
7657 if (ShAmt != 0)
7658 LHS =
7659 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7660 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7661 return true;
7662 }
7663 }
7664 }
7665
7666 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7667 // This can occur when legalizing some floating point comparisons.
7668 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7669 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7670 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7671 CC = DAG.getCondCode(CCVal);
7672 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7673 return true;
7674 }
7675
7676 // Fold ((shl (extract_vector_elt X, I), GRLen - EleBits)), 0, eq/ne) ->
7677 // ((extract_vector_elt X, I), 0, eq/ne)
7678 if (isNullConstant(RHS) && (CCVal == ISD::SETEQ || CCVal == ISD::SETNE) &&
7679 LHS.getOpcode() == ISD::SHL && LHS.hasOneUse() &&
7680 isa<ConstantSDNode>(LHS.getOperand(1))) {
7681 SDValue Ext = LHS.getOperand(0);
7682 unsigned Sht = LHS.getConstantOperandVal(1);
7683 if (Ext.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
7684 SDValue Vec = Ext.getOperand(0);
7685 unsigned EleBits = Vec.getScalarValueSizeInBits();
7686 if ((EleBits + Sht) == Subtarget.getGRLen()) {
7687 LHS = Ext;
7688 return true;
7689 }
7690 }
7691 }
7692
7693 // Fold (C1, C2, cond) -> (0, 0, seteq/setne)
7695 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
7696 EVT VT = LHS.getValueType();
7697 EVT SetCCResVT =
7698 TLI->getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
7699 if (SDValue Folded = DAG.FoldSetCC(SetCCResVT, LHS, RHS, CCVal, DL)) {
7700 LHS = DAG.getConstant(0, DL, VT);
7701 RHS = DAG.getConstant(0, DL, VT);
7703 return true;
7704 }
7705 }
7706
7707 return false;
7708}
7709
7713 SDValue LHS = N->getOperand(1);
7714 SDValue RHS = N->getOperand(2);
7715 SDValue CC = N->getOperand(3);
7716 SDLoc DL(N);
7717
7718 // CC was folded into V, so always return ISD::SETNE is fine.
7720 DL, DAG, Subtarget))
7721 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7722 N->getOperand(0), V,
7723 DAG.getConstant(0, DL, Subtarget.getGRLenVT()),
7724 DAG.getCondCode(ISD::SETNE), N->getOperand(4));
7725
7726 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7727 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7728 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7729
7730 return SDValue();
7731}
7732
7736 // Transform
7737 SDValue LHS = N->getOperand(0);
7738 SDValue RHS = N->getOperand(1);
7739 SDValue CC = N->getOperand(2);
7740 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7741 SDValue TrueV = N->getOperand(3);
7742 SDValue FalseV = N->getOperand(4);
7743 SDLoc DL(N);
7744 EVT VT = N->getValueType(0);
7745
7746 // If the True and False values are the same, we don't need a select_cc.
7747 if (TrueV == FalseV)
7748 return TrueV;
7749
7750 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7751 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7752 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7754 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7755 if (CCVal == ISD::CondCode::SETGE)
7756 std::swap(TrueV, FalseV);
7757
7758 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7759 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7760 // Only handle simm12, if it is not in this range, it can be considered as
7761 // register.
7762 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7763 isInt<12>(TrueSImm - FalseSImm)) {
7764 SDValue SRA =
7765 DAG.getNode(ISD::SRA, DL, VT, LHS,
7766 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7767 SDValue AND =
7768 DAG.getNode(ISD::AND, DL, VT, SRA,
7769 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7770 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7771 }
7772
7773 if (CCVal == ISD::CondCode::SETGE)
7774 std::swap(TrueV, FalseV);
7775 }
7776
7777 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7778 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
7779 {LHS, RHS, CC, TrueV, FalseV});
7780
7781 return SDValue();
7782}
7783
7784template <unsigned N>
7786 SelectionDAG &DAG,
7788 bool IsSigned = false) {
7789 SDLoc DL(Node);
7790 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7791 // Check the ImmArg.
7792 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7793 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7794 DAG.getContext()->emitError(Node->getOperationName(0) +
7795 ": argument out of range.");
7796 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
7797 }
7798 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
7799}
7800
7801template <unsigned N>
7802static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
7803 SelectionDAG &DAG, bool IsSigned = false) {
7804 SDLoc DL(Node);
7805 EVT ResTy = Node->getValueType(0);
7806 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7807
7808 // Check the ImmArg.
7809 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7810 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7811 DAG.getContext()->emitError(Node->getOperationName(0) +
7812 ": argument out of range.");
7813 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7814 }
7815 return DAG.getConstant(
7817 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
7818 DL, ResTy);
7819}
7820
7822 SDLoc DL(Node);
7823 EVT ResTy = Node->getValueType(0);
7824 SDValue Vec = Node->getOperand(2);
7825 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
7826 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
7827}
7828
7830 SDLoc DL(Node);
7831 EVT ResTy = Node->getValueType(0);
7832 SDValue One = DAG.getConstant(1, DL, ResTy);
7833 SDValue Bit =
7834 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
7835
7836 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
7837 DAG.getNOT(DL, Bit, ResTy));
7838}
7839
7840template <unsigned N>
7842 SDLoc DL(Node);
7843 EVT ResTy = Node->getValueType(0);
7844 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7845 // Check the unsigned ImmArg.
7846 if (!isUInt<N>(CImm->getZExtValue())) {
7847 DAG.getContext()->emitError(Node->getOperationName(0) +
7848 ": argument out of range.");
7849 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7850 }
7851
7852 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7853 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
7854
7855 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
7856}
7857
7858template <unsigned N>
7860 SDLoc DL(Node);
7861 EVT ResTy = Node->getValueType(0);
7862 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7863 // Check the unsigned ImmArg.
7864 if (!isUInt<N>(CImm->getZExtValue())) {
7865 DAG.getContext()->emitError(Node->getOperationName(0) +
7866 ": argument out of range.");
7867 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7868 }
7869
7870 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7871 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7872 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
7873}
7874
7875template <unsigned N>
7877 SDLoc DL(Node);
7878 EVT ResTy = Node->getValueType(0);
7879 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7880 // Check the unsigned ImmArg.
7881 if (!isUInt<N>(CImm->getZExtValue())) {
7882 DAG.getContext()->emitError(Node->getOperationName(0) +
7883 ": argument out of range.");
7884 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7885 }
7886
7887 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7888 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7889 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
7890}
7891
7892template <unsigned W>
7894 unsigned ResOp) {
7895 unsigned Imm = N->getConstantOperandVal(2);
7896 if (!isUInt<W>(Imm)) {
7897 const StringRef ErrorMsg = "argument out of range";
7898 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
7899 return DAG.getUNDEF(N->getValueType(0));
7900 }
7901 SDLoc DL(N);
7902 SDValue Vec = N->getOperand(1);
7903 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
7905 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
7906}
7907
7908static SDValue
7912 SDLoc DL(N);
7913 switch (N->getConstantOperandVal(0)) {
7914 default:
7915 break;
7916 case Intrinsic::loongarch_lsx_vadd_b:
7917 case Intrinsic::loongarch_lsx_vadd_h:
7918 case Intrinsic::loongarch_lsx_vadd_w:
7919 case Intrinsic::loongarch_lsx_vadd_d:
7920 case Intrinsic::loongarch_lasx_xvadd_b:
7921 case Intrinsic::loongarch_lasx_xvadd_h:
7922 case Intrinsic::loongarch_lasx_xvadd_w:
7923 case Intrinsic::loongarch_lasx_xvadd_d:
7924 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7925 N->getOperand(2));
7926 case Intrinsic::loongarch_lsx_vaddi_bu:
7927 case Intrinsic::loongarch_lsx_vaddi_hu:
7928 case Intrinsic::loongarch_lsx_vaddi_wu:
7929 case Intrinsic::loongarch_lsx_vaddi_du:
7930 case Intrinsic::loongarch_lasx_xvaddi_bu:
7931 case Intrinsic::loongarch_lasx_xvaddi_hu:
7932 case Intrinsic::loongarch_lasx_xvaddi_wu:
7933 case Intrinsic::loongarch_lasx_xvaddi_du:
7934 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7935 lowerVectorSplatImm<5>(N, 2, DAG));
7936 case Intrinsic::loongarch_lsx_vsub_b:
7937 case Intrinsic::loongarch_lsx_vsub_h:
7938 case Intrinsic::loongarch_lsx_vsub_w:
7939 case Intrinsic::loongarch_lsx_vsub_d:
7940 case Intrinsic::loongarch_lasx_xvsub_b:
7941 case Intrinsic::loongarch_lasx_xvsub_h:
7942 case Intrinsic::loongarch_lasx_xvsub_w:
7943 case Intrinsic::loongarch_lasx_xvsub_d:
7944 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7945 N->getOperand(2));
7946 case Intrinsic::loongarch_lsx_vsubi_bu:
7947 case Intrinsic::loongarch_lsx_vsubi_hu:
7948 case Intrinsic::loongarch_lsx_vsubi_wu:
7949 case Intrinsic::loongarch_lsx_vsubi_du:
7950 case Intrinsic::loongarch_lasx_xvsubi_bu:
7951 case Intrinsic::loongarch_lasx_xvsubi_hu:
7952 case Intrinsic::loongarch_lasx_xvsubi_wu:
7953 case Intrinsic::loongarch_lasx_xvsubi_du:
7954 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7955 lowerVectorSplatImm<5>(N, 2, DAG));
7956 case Intrinsic::loongarch_lsx_vneg_b:
7957 case Intrinsic::loongarch_lsx_vneg_h:
7958 case Intrinsic::loongarch_lsx_vneg_w:
7959 case Intrinsic::loongarch_lsx_vneg_d:
7960 case Intrinsic::loongarch_lasx_xvneg_b:
7961 case Intrinsic::loongarch_lasx_xvneg_h:
7962 case Intrinsic::loongarch_lasx_xvneg_w:
7963 case Intrinsic::loongarch_lasx_xvneg_d:
7964 return DAG.getNode(
7965 ISD::SUB, DL, N->getValueType(0),
7966 DAG.getConstant(
7967 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
7968 /*isSigned=*/true),
7969 SDLoc(N), N->getValueType(0)),
7970 N->getOperand(1));
7971 case Intrinsic::loongarch_lsx_vmax_b:
7972 case Intrinsic::loongarch_lsx_vmax_h:
7973 case Intrinsic::loongarch_lsx_vmax_w:
7974 case Intrinsic::loongarch_lsx_vmax_d:
7975 case Intrinsic::loongarch_lasx_xvmax_b:
7976 case Intrinsic::loongarch_lasx_xvmax_h:
7977 case Intrinsic::loongarch_lasx_xvmax_w:
7978 case Intrinsic::loongarch_lasx_xvmax_d:
7979 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7980 N->getOperand(2));
7981 case Intrinsic::loongarch_lsx_vmax_bu:
7982 case Intrinsic::loongarch_lsx_vmax_hu:
7983 case Intrinsic::loongarch_lsx_vmax_wu:
7984 case Intrinsic::loongarch_lsx_vmax_du:
7985 case Intrinsic::loongarch_lasx_xvmax_bu:
7986 case Intrinsic::loongarch_lasx_xvmax_hu:
7987 case Intrinsic::loongarch_lasx_xvmax_wu:
7988 case Intrinsic::loongarch_lasx_xvmax_du:
7989 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7990 N->getOperand(2));
7991 case Intrinsic::loongarch_lsx_vmaxi_b:
7992 case Intrinsic::loongarch_lsx_vmaxi_h:
7993 case Intrinsic::loongarch_lsx_vmaxi_w:
7994 case Intrinsic::loongarch_lsx_vmaxi_d:
7995 case Intrinsic::loongarch_lasx_xvmaxi_b:
7996 case Intrinsic::loongarch_lasx_xvmaxi_h:
7997 case Intrinsic::loongarch_lasx_xvmaxi_w:
7998 case Intrinsic::loongarch_lasx_xvmaxi_d:
7999 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
8000 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
8001 case Intrinsic::loongarch_lsx_vmaxi_bu:
8002 case Intrinsic::loongarch_lsx_vmaxi_hu:
8003 case Intrinsic::loongarch_lsx_vmaxi_wu:
8004 case Intrinsic::loongarch_lsx_vmaxi_du:
8005 case Intrinsic::loongarch_lasx_xvmaxi_bu:
8006 case Intrinsic::loongarch_lasx_xvmaxi_hu:
8007 case Intrinsic::loongarch_lasx_xvmaxi_wu:
8008 case Intrinsic::loongarch_lasx_xvmaxi_du:
8009 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
8010 lowerVectorSplatImm<5>(N, 2, DAG));
8011 case Intrinsic::loongarch_lsx_vmin_b:
8012 case Intrinsic::loongarch_lsx_vmin_h:
8013 case Intrinsic::loongarch_lsx_vmin_w:
8014 case Intrinsic::loongarch_lsx_vmin_d:
8015 case Intrinsic::loongarch_lasx_xvmin_b:
8016 case Intrinsic::loongarch_lasx_xvmin_h:
8017 case Intrinsic::loongarch_lasx_xvmin_w:
8018 case Intrinsic::loongarch_lasx_xvmin_d:
8019 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
8020 N->getOperand(2));
8021 case Intrinsic::loongarch_lsx_vmin_bu:
8022 case Intrinsic::loongarch_lsx_vmin_hu:
8023 case Intrinsic::loongarch_lsx_vmin_wu:
8024 case Intrinsic::loongarch_lsx_vmin_du:
8025 case Intrinsic::loongarch_lasx_xvmin_bu:
8026 case Intrinsic::loongarch_lasx_xvmin_hu:
8027 case Intrinsic::loongarch_lasx_xvmin_wu:
8028 case Intrinsic::loongarch_lasx_xvmin_du:
8029 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
8030 N->getOperand(2));
8031 case Intrinsic::loongarch_lsx_vmini_b:
8032 case Intrinsic::loongarch_lsx_vmini_h:
8033 case Intrinsic::loongarch_lsx_vmini_w:
8034 case Intrinsic::loongarch_lsx_vmini_d:
8035 case Intrinsic::loongarch_lasx_xvmini_b:
8036 case Intrinsic::loongarch_lasx_xvmini_h:
8037 case Intrinsic::loongarch_lasx_xvmini_w:
8038 case Intrinsic::loongarch_lasx_xvmini_d:
8039 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
8040 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
8041 case Intrinsic::loongarch_lsx_vmini_bu:
8042 case Intrinsic::loongarch_lsx_vmini_hu:
8043 case Intrinsic::loongarch_lsx_vmini_wu:
8044 case Intrinsic::loongarch_lsx_vmini_du:
8045 case Intrinsic::loongarch_lasx_xvmini_bu:
8046 case Intrinsic::loongarch_lasx_xvmini_hu:
8047 case Intrinsic::loongarch_lasx_xvmini_wu:
8048 case Intrinsic::loongarch_lasx_xvmini_du:
8049 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
8050 lowerVectorSplatImm<5>(N, 2, DAG));
8051 case Intrinsic::loongarch_lsx_vmul_b:
8052 case Intrinsic::loongarch_lsx_vmul_h:
8053 case Intrinsic::loongarch_lsx_vmul_w:
8054 case Intrinsic::loongarch_lsx_vmul_d:
8055 case Intrinsic::loongarch_lasx_xvmul_b:
8056 case Intrinsic::loongarch_lasx_xvmul_h:
8057 case Intrinsic::loongarch_lasx_xvmul_w:
8058 case Intrinsic::loongarch_lasx_xvmul_d:
8059 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
8060 N->getOperand(2));
8061 case Intrinsic::loongarch_lsx_vmadd_b:
8062 case Intrinsic::loongarch_lsx_vmadd_h:
8063 case Intrinsic::loongarch_lsx_vmadd_w:
8064 case Intrinsic::loongarch_lsx_vmadd_d:
8065 case Intrinsic::loongarch_lasx_xvmadd_b:
8066 case Intrinsic::loongarch_lasx_xvmadd_h:
8067 case Intrinsic::loongarch_lasx_xvmadd_w:
8068 case Intrinsic::loongarch_lasx_xvmadd_d: {
8069 EVT ResTy = N->getValueType(0);
8070 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
8071 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
8072 N->getOperand(3)));
8073 }
8074 case Intrinsic::loongarch_lsx_vmsub_b:
8075 case Intrinsic::loongarch_lsx_vmsub_h:
8076 case Intrinsic::loongarch_lsx_vmsub_w:
8077 case Intrinsic::loongarch_lsx_vmsub_d:
8078 case Intrinsic::loongarch_lasx_xvmsub_b:
8079 case Intrinsic::loongarch_lasx_xvmsub_h:
8080 case Intrinsic::loongarch_lasx_xvmsub_w:
8081 case Intrinsic::loongarch_lasx_xvmsub_d: {
8082 EVT ResTy = N->getValueType(0);
8083 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
8084 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
8085 N->getOperand(3)));
8086 }
8087 case Intrinsic::loongarch_lsx_vdiv_b:
8088 case Intrinsic::loongarch_lsx_vdiv_h:
8089 case Intrinsic::loongarch_lsx_vdiv_w:
8090 case Intrinsic::loongarch_lsx_vdiv_d:
8091 case Intrinsic::loongarch_lasx_xvdiv_b:
8092 case Intrinsic::loongarch_lasx_xvdiv_h:
8093 case Intrinsic::loongarch_lasx_xvdiv_w:
8094 case Intrinsic::loongarch_lasx_xvdiv_d:
8095 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
8096 N->getOperand(2));
8097 case Intrinsic::loongarch_lsx_vdiv_bu:
8098 case Intrinsic::loongarch_lsx_vdiv_hu:
8099 case Intrinsic::loongarch_lsx_vdiv_wu:
8100 case Intrinsic::loongarch_lsx_vdiv_du:
8101 case Intrinsic::loongarch_lasx_xvdiv_bu:
8102 case Intrinsic::loongarch_lasx_xvdiv_hu:
8103 case Intrinsic::loongarch_lasx_xvdiv_wu:
8104 case Intrinsic::loongarch_lasx_xvdiv_du:
8105 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
8106 N->getOperand(2));
8107 case Intrinsic::loongarch_lsx_vmod_b:
8108 case Intrinsic::loongarch_lsx_vmod_h:
8109 case Intrinsic::loongarch_lsx_vmod_w:
8110 case Intrinsic::loongarch_lsx_vmod_d:
8111 case Intrinsic::loongarch_lasx_xvmod_b:
8112 case Intrinsic::loongarch_lasx_xvmod_h:
8113 case Intrinsic::loongarch_lasx_xvmod_w:
8114 case Intrinsic::loongarch_lasx_xvmod_d:
8115 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
8116 N->getOperand(2));
8117 case Intrinsic::loongarch_lsx_vmod_bu:
8118 case Intrinsic::loongarch_lsx_vmod_hu:
8119 case Intrinsic::loongarch_lsx_vmod_wu:
8120 case Intrinsic::loongarch_lsx_vmod_du:
8121 case Intrinsic::loongarch_lasx_xvmod_bu:
8122 case Intrinsic::loongarch_lasx_xvmod_hu:
8123 case Intrinsic::loongarch_lasx_xvmod_wu:
8124 case Intrinsic::loongarch_lasx_xvmod_du:
8125 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
8126 N->getOperand(2));
8127 case Intrinsic::loongarch_lsx_vand_v:
8128 case Intrinsic::loongarch_lasx_xvand_v:
8129 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8130 N->getOperand(2));
8131 case Intrinsic::loongarch_lsx_vor_v:
8132 case Intrinsic::loongarch_lasx_xvor_v:
8133 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8134 N->getOperand(2));
8135 case Intrinsic::loongarch_lsx_vxor_v:
8136 case Intrinsic::loongarch_lasx_xvxor_v:
8137 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8138 N->getOperand(2));
8139 case Intrinsic::loongarch_lsx_vnor_v:
8140 case Intrinsic::loongarch_lasx_xvnor_v: {
8141 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8142 N->getOperand(2));
8143 return DAG.getNOT(DL, Res, Res->getValueType(0));
8144 }
8145 case Intrinsic::loongarch_lsx_vandi_b:
8146 case Intrinsic::loongarch_lasx_xvandi_b:
8147 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8148 lowerVectorSplatImm<8>(N, 2, DAG));
8149 case Intrinsic::loongarch_lsx_vori_b:
8150 case Intrinsic::loongarch_lasx_xvori_b:
8151 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8152 lowerVectorSplatImm<8>(N, 2, DAG));
8153 case Intrinsic::loongarch_lsx_vxori_b:
8154 case Intrinsic::loongarch_lasx_xvxori_b:
8155 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8156 lowerVectorSplatImm<8>(N, 2, DAG));
8157 case Intrinsic::loongarch_lsx_vsll_b:
8158 case Intrinsic::loongarch_lsx_vsll_h:
8159 case Intrinsic::loongarch_lsx_vsll_w:
8160 case Intrinsic::loongarch_lsx_vsll_d:
8161 case Intrinsic::loongarch_lasx_xvsll_b:
8162 case Intrinsic::loongarch_lasx_xvsll_h:
8163 case Intrinsic::loongarch_lasx_xvsll_w:
8164 case Intrinsic::loongarch_lasx_xvsll_d:
8165 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8166 truncateVecElts(N, DAG));
8167 case Intrinsic::loongarch_lsx_vslli_b:
8168 case Intrinsic::loongarch_lasx_xvslli_b:
8169 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8170 lowerVectorSplatImm<3>(N, 2, DAG));
8171 case Intrinsic::loongarch_lsx_vslli_h:
8172 case Intrinsic::loongarch_lasx_xvslli_h:
8173 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8174 lowerVectorSplatImm<4>(N, 2, DAG));
8175 case Intrinsic::loongarch_lsx_vslli_w:
8176 case Intrinsic::loongarch_lasx_xvslli_w:
8177 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8178 lowerVectorSplatImm<5>(N, 2, DAG));
8179 case Intrinsic::loongarch_lsx_vslli_d:
8180 case Intrinsic::loongarch_lasx_xvslli_d:
8181 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8182 lowerVectorSplatImm<6>(N, 2, DAG));
8183 case Intrinsic::loongarch_lsx_vsrl_b:
8184 case Intrinsic::loongarch_lsx_vsrl_h:
8185 case Intrinsic::loongarch_lsx_vsrl_w:
8186 case Intrinsic::loongarch_lsx_vsrl_d:
8187 case Intrinsic::loongarch_lasx_xvsrl_b:
8188 case Intrinsic::loongarch_lasx_xvsrl_h:
8189 case Intrinsic::loongarch_lasx_xvsrl_w:
8190 case Intrinsic::loongarch_lasx_xvsrl_d:
8191 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8192 truncateVecElts(N, DAG));
8193 case Intrinsic::loongarch_lsx_vsrli_b:
8194 case Intrinsic::loongarch_lasx_xvsrli_b:
8195 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8196 lowerVectorSplatImm<3>(N, 2, DAG));
8197 case Intrinsic::loongarch_lsx_vsrli_h:
8198 case Intrinsic::loongarch_lasx_xvsrli_h:
8199 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8200 lowerVectorSplatImm<4>(N, 2, DAG));
8201 case Intrinsic::loongarch_lsx_vsrli_w:
8202 case Intrinsic::loongarch_lasx_xvsrli_w:
8203 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8204 lowerVectorSplatImm<5>(N, 2, DAG));
8205 case Intrinsic::loongarch_lsx_vsrli_d:
8206 case Intrinsic::loongarch_lasx_xvsrli_d:
8207 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8208 lowerVectorSplatImm<6>(N, 2, DAG));
8209 case Intrinsic::loongarch_lsx_vsra_b:
8210 case Intrinsic::loongarch_lsx_vsra_h:
8211 case Intrinsic::loongarch_lsx_vsra_w:
8212 case Intrinsic::loongarch_lsx_vsra_d:
8213 case Intrinsic::loongarch_lasx_xvsra_b:
8214 case Intrinsic::loongarch_lasx_xvsra_h:
8215 case Intrinsic::loongarch_lasx_xvsra_w:
8216 case Intrinsic::loongarch_lasx_xvsra_d:
8217 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8218 truncateVecElts(N, DAG));
8219 case Intrinsic::loongarch_lsx_vsrai_b:
8220 case Intrinsic::loongarch_lasx_xvsrai_b:
8221 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8222 lowerVectorSplatImm<3>(N, 2, DAG));
8223 case Intrinsic::loongarch_lsx_vsrai_h:
8224 case Intrinsic::loongarch_lasx_xvsrai_h:
8225 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8226 lowerVectorSplatImm<4>(N, 2, DAG));
8227 case Intrinsic::loongarch_lsx_vsrai_w:
8228 case Intrinsic::loongarch_lasx_xvsrai_w:
8229 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8230 lowerVectorSplatImm<5>(N, 2, DAG));
8231 case Intrinsic::loongarch_lsx_vsrai_d:
8232 case Intrinsic::loongarch_lasx_xvsrai_d:
8233 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8234 lowerVectorSplatImm<6>(N, 2, DAG));
8235 case Intrinsic::loongarch_lsx_vclz_b:
8236 case Intrinsic::loongarch_lsx_vclz_h:
8237 case Intrinsic::loongarch_lsx_vclz_w:
8238 case Intrinsic::loongarch_lsx_vclz_d:
8239 case Intrinsic::loongarch_lasx_xvclz_b:
8240 case Intrinsic::loongarch_lasx_xvclz_h:
8241 case Intrinsic::loongarch_lasx_xvclz_w:
8242 case Intrinsic::loongarch_lasx_xvclz_d:
8243 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
8244 case Intrinsic::loongarch_lsx_vpcnt_b:
8245 case Intrinsic::loongarch_lsx_vpcnt_h:
8246 case Intrinsic::loongarch_lsx_vpcnt_w:
8247 case Intrinsic::loongarch_lsx_vpcnt_d:
8248 case Intrinsic::loongarch_lasx_xvpcnt_b:
8249 case Intrinsic::loongarch_lasx_xvpcnt_h:
8250 case Intrinsic::loongarch_lasx_xvpcnt_w:
8251 case Intrinsic::loongarch_lasx_xvpcnt_d:
8252 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
8253 case Intrinsic::loongarch_lsx_vbitclr_b:
8254 case Intrinsic::loongarch_lsx_vbitclr_h:
8255 case Intrinsic::loongarch_lsx_vbitclr_w:
8256 case Intrinsic::loongarch_lsx_vbitclr_d:
8257 case Intrinsic::loongarch_lasx_xvbitclr_b:
8258 case Intrinsic::loongarch_lasx_xvbitclr_h:
8259 case Intrinsic::loongarch_lasx_xvbitclr_w:
8260 case Intrinsic::loongarch_lasx_xvbitclr_d:
8261 return lowerVectorBitClear(N, DAG);
8262 case Intrinsic::loongarch_lsx_vbitclri_b:
8263 case Intrinsic::loongarch_lasx_xvbitclri_b:
8264 return lowerVectorBitClearImm<3>(N, DAG);
8265 case Intrinsic::loongarch_lsx_vbitclri_h:
8266 case Intrinsic::loongarch_lasx_xvbitclri_h:
8267 return lowerVectorBitClearImm<4>(N, DAG);
8268 case Intrinsic::loongarch_lsx_vbitclri_w:
8269 case Intrinsic::loongarch_lasx_xvbitclri_w:
8270 return lowerVectorBitClearImm<5>(N, DAG);
8271 case Intrinsic::loongarch_lsx_vbitclri_d:
8272 case Intrinsic::loongarch_lasx_xvbitclri_d:
8273 return lowerVectorBitClearImm<6>(N, DAG);
8274 case Intrinsic::loongarch_lsx_vbitset_b:
8275 case Intrinsic::loongarch_lsx_vbitset_h:
8276 case Intrinsic::loongarch_lsx_vbitset_w:
8277 case Intrinsic::loongarch_lsx_vbitset_d:
8278 case Intrinsic::loongarch_lasx_xvbitset_b:
8279 case Intrinsic::loongarch_lasx_xvbitset_h:
8280 case Intrinsic::loongarch_lasx_xvbitset_w:
8281 case Intrinsic::loongarch_lasx_xvbitset_d: {
8282 EVT VecTy = N->getValueType(0);
8283 SDValue One = DAG.getConstant(1, DL, VecTy);
8284 return DAG.getNode(
8285 ISD::OR, DL, VecTy, N->getOperand(1),
8286 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8287 }
8288 case Intrinsic::loongarch_lsx_vbitseti_b:
8289 case Intrinsic::loongarch_lasx_xvbitseti_b:
8290 return lowerVectorBitSetImm<3>(N, DAG);
8291 case Intrinsic::loongarch_lsx_vbitseti_h:
8292 case Intrinsic::loongarch_lasx_xvbitseti_h:
8293 return lowerVectorBitSetImm<4>(N, DAG);
8294 case Intrinsic::loongarch_lsx_vbitseti_w:
8295 case Intrinsic::loongarch_lasx_xvbitseti_w:
8296 return lowerVectorBitSetImm<5>(N, DAG);
8297 case Intrinsic::loongarch_lsx_vbitseti_d:
8298 case Intrinsic::loongarch_lasx_xvbitseti_d:
8299 return lowerVectorBitSetImm<6>(N, DAG);
8300 case Intrinsic::loongarch_lsx_vbitrev_b:
8301 case Intrinsic::loongarch_lsx_vbitrev_h:
8302 case Intrinsic::loongarch_lsx_vbitrev_w:
8303 case Intrinsic::loongarch_lsx_vbitrev_d:
8304 case Intrinsic::loongarch_lasx_xvbitrev_b:
8305 case Intrinsic::loongarch_lasx_xvbitrev_h:
8306 case Intrinsic::loongarch_lasx_xvbitrev_w:
8307 case Intrinsic::loongarch_lasx_xvbitrev_d: {
8308 EVT VecTy = N->getValueType(0);
8309 SDValue One = DAG.getConstant(1, DL, VecTy);
8310 return DAG.getNode(
8311 ISD::XOR, DL, VecTy, N->getOperand(1),
8312 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8313 }
8314 case Intrinsic::loongarch_lsx_vbitrevi_b:
8315 case Intrinsic::loongarch_lasx_xvbitrevi_b:
8316 return lowerVectorBitRevImm<3>(N, DAG);
8317 case Intrinsic::loongarch_lsx_vbitrevi_h:
8318 case Intrinsic::loongarch_lasx_xvbitrevi_h:
8319 return lowerVectorBitRevImm<4>(N, DAG);
8320 case Intrinsic::loongarch_lsx_vbitrevi_w:
8321 case Intrinsic::loongarch_lasx_xvbitrevi_w:
8322 return lowerVectorBitRevImm<5>(N, DAG);
8323 case Intrinsic::loongarch_lsx_vbitrevi_d:
8324 case Intrinsic::loongarch_lasx_xvbitrevi_d:
8325 return lowerVectorBitRevImm<6>(N, DAG);
8326 case Intrinsic::loongarch_lsx_vfadd_s:
8327 case Intrinsic::loongarch_lsx_vfadd_d:
8328 case Intrinsic::loongarch_lasx_xvfadd_s:
8329 case Intrinsic::loongarch_lasx_xvfadd_d:
8330 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
8331 N->getOperand(2));
8332 case Intrinsic::loongarch_lsx_vfsub_s:
8333 case Intrinsic::loongarch_lsx_vfsub_d:
8334 case Intrinsic::loongarch_lasx_xvfsub_s:
8335 case Intrinsic::loongarch_lasx_xvfsub_d:
8336 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
8337 N->getOperand(2));
8338 case Intrinsic::loongarch_lsx_vfmul_s:
8339 case Intrinsic::loongarch_lsx_vfmul_d:
8340 case Intrinsic::loongarch_lasx_xvfmul_s:
8341 case Intrinsic::loongarch_lasx_xvfmul_d:
8342 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
8343 N->getOperand(2));
8344 case Intrinsic::loongarch_lsx_vfdiv_s:
8345 case Intrinsic::loongarch_lsx_vfdiv_d:
8346 case Intrinsic::loongarch_lasx_xvfdiv_s:
8347 case Intrinsic::loongarch_lasx_xvfdiv_d:
8348 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
8349 N->getOperand(2));
8350 case Intrinsic::loongarch_lsx_vfmadd_s:
8351 case Intrinsic::loongarch_lsx_vfmadd_d:
8352 case Intrinsic::loongarch_lasx_xvfmadd_s:
8353 case Intrinsic::loongarch_lasx_xvfmadd_d:
8354 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
8355 N->getOperand(2), N->getOperand(3));
8356 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
8357 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8358 N->getOperand(1), N->getOperand(2),
8360 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
8361 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
8362 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8363 N->getOperand(1), N->getOperand(2),
8365 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
8366 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
8367 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8368 N->getOperand(1), N->getOperand(2),
8370 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
8371 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8372 N->getOperand(1), N->getOperand(2),
8374 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
8375 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
8376 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
8377 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
8378 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
8379 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
8380 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
8381 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
8382 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
8383 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8384 N->getOperand(1)));
8385 case Intrinsic::loongarch_lsx_vreplve_b:
8386 case Intrinsic::loongarch_lsx_vreplve_h:
8387 case Intrinsic::loongarch_lsx_vreplve_w:
8388 case Intrinsic::loongarch_lsx_vreplve_d:
8389 case Intrinsic::loongarch_lasx_xvreplve_b:
8390 case Intrinsic::loongarch_lasx_xvreplve_h:
8391 case Intrinsic::loongarch_lasx_xvreplve_w:
8392 case Intrinsic::loongarch_lasx_xvreplve_d:
8393 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
8394 N->getOperand(1),
8395 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8396 N->getOperand(2)));
8397 case Intrinsic::loongarch_lsx_vpickve2gr_b:
8398 if (!Subtarget.is64Bit())
8399 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8400 break;
8401 case Intrinsic::loongarch_lsx_vpickve2gr_h:
8402 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
8403 if (!Subtarget.is64Bit())
8404 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8405 break;
8406 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8407 if (!Subtarget.is64Bit())
8408 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8409 break;
8410 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8411 if (!Subtarget.is64Bit())
8412 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8413 break;
8414 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8415 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8416 if (!Subtarget.is64Bit())
8417 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8418 break;
8419 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8420 if (!Subtarget.is64Bit())
8421 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8422 break;
8423 case Intrinsic::loongarch_lsx_bz_b:
8424 case Intrinsic::loongarch_lsx_bz_h:
8425 case Intrinsic::loongarch_lsx_bz_w:
8426 case Intrinsic::loongarch_lsx_bz_d:
8427 case Intrinsic::loongarch_lasx_xbz_b:
8428 case Intrinsic::loongarch_lasx_xbz_h:
8429 case Intrinsic::loongarch_lasx_xbz_w:
8430 case Intrinsic::loongarch_lasx_xbz_d:
8431 if (!Subtarget.is64Bit())
8432 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8433 N->getOperand(1));
8434 break;
8435 case Intrinsic::loongarch_lsx_bz_v:
8436 case Intrinsic::loongarch_lasx_xbz_v:
8437 if (!Subtarget.is64Bit())
8438 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8439 N->getOperand(1));
8440 break;
8441 case Intrinsic::loongarch_lsx_bnz_b:
8442 case Intrinsic::loongarch_lsx_bnz_h:
8443 case Intrinsic::loongarch_lsx_bnz_w:
8444 case Intrinsic::loongarch_lsx_bnz_d:
8445 case Intrinsic::loongarch_lasx_xbnz_b:
8446 case Intrinsic::loongarch_lasx_xbnz_h:
8447 case Intrinsic::loongarch_lasx_xbnz_w:
8448 case Intrinsic::loongarch_lasx_xbnz_d:
8449 if (!Subtarget.is64Bit())
8450 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8451 N->getOperand(1));
8452 break;
8453 case Intrinsic::loongarch_lsx_bnz_v:
8454 case Intrinsic::loongarch_lasx_xbnz_v:
8455 if (!Subtarget.is64Bit())
8456 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8457 N->getOperand(1));
8458 break;
8459 case Intrinsic::loongarch_lasx_concat_128_s:
8460 case Intrinsic::loongarch_lasx_concat_128_d:
8461 case Intrinsic::loongarch_lasx_concat_128:
8462 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8463 N->getOperand(1), N->getOperand(2));
8464 }
8465 return SDValue();
8466}
8467
8471 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8472 // conversion is unnecessary and can be replaced with the
8473 // MOVFR2GR_S_LA64 operand.
8474 SDValue Op0 = N->getOperand(0);
8475 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8476 return Op0.getOperand(0);
8477 return SDValue();
8478}
8479
8483 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8484 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8485 // operand.
8486 SDValue Op0 = N->getOperand(0);
8487 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8488 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8489 "Unexpected value type!");
8490 return Op0.getOperand(0);
8491 }
8492 return SDValue();
8493}
8494
8495static SDValue
8498 MVT VT = N->getSimpleValueType(0);
8499 unsigned NumBits = VT.getScalarSizeInBits();
8500
8501 // Simplify the inputs.
8503 APInt DemandedMask(APInt::getAllOnes(NumBits));
8504 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8505 return SDValue(N, 0);
8506
8507 return SDValue();
8508}
8509
8510static SDValue
8514 SDValue Op0 = N->getOperand(0);
8515 SDLoc DL(N);
8516
8517 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8518 // redundant. Instead, use BuildPairF64's operands directly.
8519 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8520 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8521
8522 if (Op0->isUndef()) {
8523 SDValue Lo = DAG.getUNDEF(MVT::i32);
8524 SDValue Hi = DAG.getUNDEF(MVT::i32);
8525 return DCI.CombineTo(N, Lo, Hi);
8526 }
8527
8528 // It's cheaper to materialise two 32-bit integers than to load a double
8529 // from the constant pool and transfer it to integer registers through the
8530 // stack.
8532 APInt V = C->getValueAPF().bitcastToAPInt();
8533 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8534 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8535 return DCI.CombineTo(N, Lo, Hi);
8536 }
8537
8538 return SDValue();
8539}
8540
8541/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8545 SDValue N0 = N->getOperand(0);
8546 SDValue N1 = N->getOperand(1);
8547 MVT VT = N->getSimpleValueType(0);
8548 SDLoc DL(N);
8549
8550 // VANDN(undef, x) -> 0
8551 // VANDN(x, undef) -> 0
8552 if (N0.isUndef() || N1.isUndef())
8553 return DAG.getConstant(0, DL, VT);
8554
8555 // VANDN(0, x) -> x
8557 return N1;
8558
8559 // VANDN(x, 0) -> 0
8561 return DAG.getConstant(0, DL, VT);
8562
8563 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8565 return DAG.getNOT(DL, N0, VT);
8566
8567 // Turn VANDN back to AND if input is inverted.
8568 if (SDValue Not = isNOT(N0, DAG))
8569 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8570
8571 // Folds for better commutativity:
8572 if (N1->hasOneUse()) {
8573 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8574 if (SDValue Not = isNOT(N1, DAG))
8575 return DAG.getNOT(
8576 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8577
8578 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8579 // -> NOT(OR(x, SplatVector(-Imm))
8580 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8581 // gain benefits.
8582 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8583 N1.getOpcode() == ISD::BUILD_VECTOR) {
8584 if (SDValue SplatValue =
8585 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8586 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8587 return SDValue();
8588
8589 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8590 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8591 SDValue Not =
8592 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8593 return DAG.getNOT(
8594 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8595 VT);
8596 }
8597 }
8598 }
8599 }
8600
8601 return SDValue();
8602}
8603
8604static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8605 SDLoc DL(N);
8606 EVT VT = N->getValueType(0);
8607 SDValue Src = N->getOperand(0);
8608 EVT SrcVT = Src.getValueType();
8609
8610 unsigned DstElts = VT.getVectorNumElements();
8611 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8612 unsigned DstEltBits = VT.getScalarSizeInBits();
8613
8614 if (SrcEltBits >= DstEltBits)
8615 return SDValue();
8616
8617 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8618 EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
8619
8620 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8621 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8622}
8623
8624// Merge two 64 to 32 convert instructions into one,
8625// e.g.
8626// vffint.s.l $vr0, $vr1, $vr2
8627// will convert 4 si64 into 4 float at once.
8628// or
8629// vftintrz.w.d $vr0, $vr1, $vr2
8630// which will convert 4 double into 4 si32 at once.
8631// also deal with their 256-bits LASX version.
8632static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8633 unsigned BlockBits) {
8634 SDLoc DL(N);
8635 MVT DstVT = N->getSimpleValueType(0);
8636 SDValue Src = N->getOperand(0);
8637 MVT SrcVT = Src.getSimpleValueType();
8638 unsigned SrcBits = SrcVT.getSizeInBits();
8639
8641 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8642 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8643 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8644 Src.getOperand(0).getValueType() == BlockVT) {
8645 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8646 Blocks.push_back(Src.getOperand(i));
8647 } else if (SrcBits > BlockBits) {
8648 // Wider than one register: extract each BlockBits-wide sub-vector.
8649 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8650 Blocks.push_back(
8651 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8652 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8653 } else {
8654 BlockBits = SrcBits;
8655 Blocks.push_back(Src);
8656 }
8657
8658 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8659 BlockBits / DstVT.getScalarSizeInBits());
8661 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8662 SDValue Lo = Blocks[i];
8663 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8664 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8665
8666 if (BlockBits == 256) {
8667 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8668 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8669 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8670 Res = DAG.getBitcast(NativeVecVT, Res);
8671 }
8672
8673 Parts.push_back(Res);
8674 }
8675
8676 if (Blocks.size() == 1)
8677 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8678 DAG.getVectorIdxConstant(0, DL));
8679 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8680}
8681
8685 SDLoc DL(N);
8686 EVT VT = N->getValueType(0);
8687 SDValue Src = N->getOperand(0);
8688 EVT SrcVT = Src.getValueType();
8689
8690 if (VT.isVector()) {
8691 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8692 unsigned DstEltBits = VT.getScalarSizeInBits();
8693 unsigned NumElts = VT.getVectorNumElements();
8694 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8695
8696 // Sign-extend src to avoid scalarization.
8697 if (SrcEltBits <= DstEltBits)
8698 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8699
8700 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8701 return SDValue();
8702
8703 if (!SrcVT.isSimple() || !VT.isSimple())
8704 return SDValue();
8705
8706 // [x]vffint.s.l needs LSX and at least one full 128-bit source register.
8707 if (!Subtarget.hasExtLSX() || SrcVT.getSizeInBits() < 128)
8708 return SDValue();
8709
8710 // Combine [x]vffint.s.l for vector si64 to float conversion.
8711 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8712 }
8713
8714 if (VT != MVT::f32 && VT != MVT::f64)
8715 return SDValue();
8716 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8717 return SDValue();
8718 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8719 return SDValue();
8720
8721 // Only optimize when the source and destination types have the same width.
8722 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8723 return SDValue();
8724
8725 // If the result of an integer load is only used by an integer-to-float
8726 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8727 // (movgr2fr) instruction.
8728 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8729 // Do not change the width of a volatile load. This condition check is
8730 // inspired by AArch64.
8731 !cast<LoadSDNode>(Src)->isVolatile()) {
8732 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8733 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8734 LN0->getPointerInfo(), LN0->getAlign(),
8735 LN0->getMemOperand()->getFlags());
8736
8737 // Make sure successors of the original load stay after it by updating them
8738 // to use the new Chain.
8739 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8740 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8741 }
8742
8743 return SDValue();
8744}
8745
8749 SDLoc DL(N);
8750 EVT VT = N->getValueType(0);
8751
8752 // Zero-extend src to avoid scalarization.
8753 if (VT.isVector())
8754 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8755
8756 return SDValue();
8757}
8758
8759// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
8760// For example:
8761// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
8762// Can be combined into:
8763// v4i32 = VFTINTRZ_W_D v2f64. v2f64
8767 if (!Subtarget.hasExtLSX())
8768 return SDValue();
8769
8770 SDLoc DL(N);
8771 EVT DstVT = N->getValueType(0);
8772 SDValue Src = N->getOperand(0);
8773 EVT SrcVT = Src.getValueType();
8774 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
8775
8776 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
8777 return SDValue();
8778
8779 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8780 unsigned SrcBits = SrcVT.getSizeInBits();
8781 unsigned DstEltBits = DstVT.getScalarSizeInBits();
8782 unsigned NumElts = DstVT.getVectorNumElements();
8783 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8784
8785 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
8786 return SDValue();
8787
8788 if (SrcBits % BlockBits != 0 && SrcBits != 128)
8789 return SDValue();
8790
8791 if (DstEltBits < 32) {
8792 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
8793 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
8794 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
8795 }
8796
8797 if (SrcEltBits != 64 || DstEltBits != 32)
8798 return SDValue();
8799
8800 if (!IsSigned) {
8801 // LASX already has pattern for double convert to uint32.
8802 if (Subtarget.hasExtLASX())
8803 return SDValue();
8804 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
8805 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
8806 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
8807 }
8808
8809 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
8810}
8811
8812// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
8813// logical operations, like in the example below.
8814// or (and (truncate x, truncate y)),
8815// (xor (truncate z, build_vector (constants)))
8816// Given a target type \p VT, we generate
8817// or (and x, y), (xor z, zext(build_vector (constants)))
8818// given x, y and z are of type \p VT. We can do so, if operands are either
8819// truncates from VT types, the second operand is a vector of constants, can
8820// be recursively promoted or is an existing extension we can extend further.
8822 SelectionDAG &DAG,
8824 unsigned Depth) {
8825 // Limit recursion to avoid excessive compile times.
8827 return SDValue();
8828
8829 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
8830 return SDValue();
8831
8832 SDValue N0 = N.getOperand(0);
8833 SDValue N1 = N.getOperand(1);
8834
8836 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
8837 return SDValue();
8838
8839 if (SDValue NN0 =
8840 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
8841 N0 = NN0;
8842 else {
8843 // The left side has to be a 'trunc'.
8844 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
8845 N0.getOperand(0).getValueType() == VT;
8846 if (LHSTrunc)
8847 N0 = N0.getOperand(0);
8848 else
8849 return SDValue();
8850 }
8851
8852 if (SDValue NN1 =
8853 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
8854 N1 = NN1;
8855 else {
8856 // The right side has to be a 'trunc', a (foldable) constant or an
8857 // existing extension we can extend further.
8858 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
8859 N1.getOperand(0).getValueType() == VT;
8860 if (RHSTrunc)
8861 N1 = N1.getOperand(0);
8862 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
8863 Subtarget.hasExtLASX() && N1.hasOneUse())
8864 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
8865 // On 32-bit platform, i64 is an illegal integer scalar type, and
8866 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
8867 // future.
8868 else if (SDValue Cst =
8870 N1 = Cst;
8871 else
8872 return SDValue();
8873 }
8874
8875 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
8876}
8877
8878// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
8879// is LSX-sized register. In most cases we actually compare or select LASX-sized
8880// registers and mixing the two types creates horrible code. This method
8881// optimizes some of the transition sequences.
8883 SelectionDAG &DAG,
8885 EVT VT = N.getValueType();
8886 assert(VT.isVector() && "Expected vector type");
8887 assert((N.getOpcode() == ISD::ANY_EXTEND ||
8888 N.getOpcode() == ISD::ZERO_EXTEND ||
8889 N.getOpcode() == ISD::SIGN_EXTEND) &&
8890 "Invalid Node");
8891
8892 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
8893 return SDValue();
8894
8895 SDValue Narrow = N.getOperand(0);
8896 EVT NarrowVT = Narrow.getValueType();
8897
8898 // Generate the wide operation.
8899 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
8900 if (!Op)
8901 return SDValue();
8902 switch (N.getOpcode()) {
8903 default:
8904 llvm_unreachable("Unexpected opcode");
8905 case ISD::ANY_EXTEND:
8906 return Op;
8907 case ISD::ZERO_EXTEND:
8908 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
8909 case ISD::SIGN_EXTEND:
8910 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
8911 DAG.getValueType(NarrowVT));
8912 }
8913}
8914
8918 EVT VT = N->getValueType(0);
8919 SDLoc DL(N);
8920
8921 if (VT.isVector()) {
8922 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
8923 return R;
8924
8925 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
8926 N->getValueSizeInBits(0) != N->getOperand(0).getValueSizeInBits() * 2)
8927 return SDValue();
8928
8929 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
8930 if (N->getOpcode() == ISD::SIGN_EXTEND)
8931 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
8932 if (N->getOpcode() == ISD::ZERO_EXTEND)
8933 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
8934 }
8935 }
8936
8937 return SDValue();
8938}
8939
8940static SDValue
8944 SDLoc DL(N);
8945 EVT VT = N->getValueType(0);
8946
8947 if (VT.isVector() && N->getNumOperands() == 2)
8948 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
8949 return R;
8950
8951 return SDValue();
8952}
8953
8957 if (DCI.isBeforeLegalizeOps())
8958 return SDValue();
8959
8960 EVT VT = N->getValueType(0);
8961 if (!VT.isVector())
8962 return SDValue();
8963
8964 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
8965 return SDValue();
8966
8967 EVT EltVT = VT.getVectorElementType();
8968 if (!EltVT.isInteger())
8969 return SDValue();
8970
8971 SDValue Cond = N->getOperand(0);
8972 SDValue TrueVal = N->getOperand(1);
8973 SDValue FalseVal = N->getOperand(2);
8974
8975 // match:
8976 //
8977 // vselect (setcc shift, 0, seteq),
8978 // x,
8979 // rounded_shift
8980
8981 if (Cond.getOpcode() != ISD::SETCC)
8982 return SDValue();
8983
8984 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
8985 return SDValue();
8986
8987 if (Cond.getOperandCondCode(2) != ISD::SETEQ)
8988 return SDValue();
8989
8990 SDValue Shift = Cond.getOperand(0);
8991
8992 // True branch must be original value:
8993 //
8994 // vselect cond, x, ...
8995
8996 SDValue X = TrueVal;
8997
8998 // Now match rounded shift pattern:
8999 //
9000 // add
9001 // (and
9002 // (srl X, shift-1)
9003 // 1)
9004 // (srl/sra X, shift)
9005
9006 if (FalseVal.getOpcode() != ISD::ADD)
9007 return SDValue();
9008
9009 SDValue Add0 = FalseVal.getOperand(0);
9010 SDValue Add1 = FalseVal.getOperand(1);
9011 SDValue And;
9012 SDValue Shr;
9013
9014 if (Add0.getOpcode() == ISD::AND) {
9015 And = Add0;
9016 Shr = Add1;
9017 } else if (Add1.getOpcode() == ISD::AND) {
9018 And = Add1;
9019 Shr = Add0;
9020 } else {
9021 return SDValue();
9022 }
9023
9024 // match:
9025 //
9026 // srl/sra X, shift
9027
9028 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
9029 return SDValue();
9030
9031 if (Shr.getOperand(0) != X)
9032 return SDValue();
9033
9034 if (Shr.getOperand(1) != Shift)
9035 return SDValue();
9036
9037 // match:
9038 //
9039 // and
9040 // (srl X, shift-1)
9041 // 1
9042
9043 SDValue Srl = And.getOperand(0);
9044 SDValue One = And.getOperand(1);
9045 APInt SplatVal;
9046
9047 if (Srl.getOpcode() != ISD::SRL)
9048 return SDValue();
9049
9050 One = peekThroughBitcasts(One);
9051 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
9052 return SDValue();
9053
9054 if (SplatVal != 1)
9055 return SDValue();
9056
9057 if (Srl.getOperand(0) != X)
9058 return SDValue();
9059
9060 // match:
9061 //
9062 // shift-1
9063
9064 SDValue ShiftMinus1 = Srl.getOperand(1);
9065
9066 if (ShiftMinus1.getOpcode() != ISD::ADD)
9067 return SDValue();
9068
9069 if (ShiftMinus1.getOperand(0) != Shift)
9070 return SDValue();
9071
9073 return SDValue();
9074
9075 // We matched a rounded right shift pattern and can lower it
9076 // to a single vector rounded shift instruction.
9077
9078 SDLoc DL(N);
9079 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
9080 : LoongArchISD::VSRAR,
9081 DL, VT, X, Shift);
9082}
9083
9085 DAGCombinerInfo &DCI) const {
9086 SelectionDAG &DAG = DCI.DAG;
9087 switch (N->getOpcode()) {
9088 default:
9089 break;
9090 case ISD::ADD:
9091 return performADDCombine(N, DAG, DCI, Subtarget);
9092 case ISD::AND:
9093 return performANDCombine(N, DAG, DCI, Subtarget);
9094 case ISD::OR:
9095 return performORCombine(N, DAG, DCI, Subtarget);
9096 case ISD::SETCC:
9097 return performSETCCCombine(N, DAG, DCI, Subtarget);
9098 case ISD::SELECT:
9099 return performSELECTCombine(N, DAG, DCI, Subtarget);
9100 case ISD::SHL:
9101 return performSHLCombine(N, DAG, DCI, Subtarget);
9102 case ISD::SRL:
9103 return performSRLCombine(N, DAG, DCI, Subtarget);
9104 case ISD::SUB:
9105 return performSUBCombine(N, DAG, DCI, Subtarget);
9106 case ISD::BITCAST:
9107 return performBITCASTCombine(N, DAG, DCI, Subtarget);
9108 case ISD::ANY_EXTEND:
9109 case ISD::ZERO_EXTEND:
9110 case ISD::SIGN_EXTEND:
9111 return performEXTENDCombine(N, DAG, DCI, Subtarget);
9112 case ISD::SINT_TO_FP:
9113 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9114 case ISD::UINT_TO_FP:
9115 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9116 case ISD::FP_TO_SINT:
9117 case ISD::FP_TO_UINT:
9118 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
9119 case LoongArchISD::BITREV_W:
9120 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
9121 case LoongArchISD::BR_CC:
9122 return performBR_CCCombine(N, DAG, DCI, Subtarget);
9123 case LoongArchISD::SELECT_CC:
9124 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
9126 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
9127 case LoongArchISD::MOVGR2FR_W_LA64:
9128 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
9129 case LoongArchISD::MOVFR2GR_S_LA64:
9130 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
9131 case LoongArchISD::CRC_W_B_W:
9132 case LoongArchISD::CRC_W_H_W:
9133 case LoongArchISD::CRCC_W_B_W:
9134 case LoongArchISD::CRCC_W_H_W:
9135 case LoongArchISD::VMSKLTZ:
9136 case LoongArchISD::XVMSKLTZ:
9137 return performDemandedBitsCombine(N, DAG, DCI);
9138 case LoongArchISD::SPLIT_PAIR_F64:
9139 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
9140 case LoongArchISD::VANDN:
9141 return performVANDNCombine(N, DAG, DCI, Subtarget);
9143 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
9144 case ISD::VSELECT:
9145 return performVSELECTCombine(N, DAG, DCI, Subtarget);
9146 case LoongArchISD::VPACKEV:
9147 case LoongArchISD::VPERMI:
9148 if (SDValue Result =
9149 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
9150 return Result;
9151 }
9152 return SDValue();
9153}
9154
9157 if (!ZeroDivCheck)
9158 return MBB;
9159
9160 // Build instructions:
9161 // MBB:
9162 // div(or mod) $dst, $dividend, $divisor
9163 // bne $divisor, $zero, SinkMBB
9164 // BreakMBB:
9165 // break 7 // BRK_DIVZERO
9166 // SinkMBB:
9167 // fallthrough
9168 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
9169 MachineFunction::iterator It = ++MBB->getIterator();
9170 MachineFunction *MF = MBB->getParent();
9171 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9172 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9173 MF->insert(It, BreakMBB);
9174 MF->insert(It, SinkMBB);
9175
9176 // Transfer the remainder of MBB and its successor edges to SinkMBB.
9177 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
9178 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
9179
9180 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
9181 DebugLoc DL = MI.getDebugLoc();
9182 MachineOperand &Divisor = MI.getOperand(2);
9183 Register DivisorReg = Divisor.getReg();
9184
9185 // MBB:
9186 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
9187 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
9188 .addReg(LoongArch::R0)
9189 .addMBB(SinkMBB);
9190 MBB->addSuccessor(BreakMBB);
9191 MBB->addSuccessor(SinkMBB);
9192
9193 // BreakMBB:
9194 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
9195 // definition of BRK_DIVZERO.
9196 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
9197 BreakMBB->addSuccessor(SinkMBB);
9198
9199 // Clear Divisor's kill flag.
9200 Divisor.setIsKill(false);
9201
9202 return SinkMBB;
9203}
9204
9205static MachineBasicBlock *
9208 unsigned InsOp;
9209 unsigned BroadcastOp;
9210 unsigned HalfSize;
9211 switch (MI.getOpcode()) {
9212 default:
9213 llvm_unreachable("Unexpected opcode");
9214 case LoongArch::PseudoXVINSGR2VR_B:
9215 HalfSize = 16;
9216 BroadcastOp = LoongArch::XVREPLGR2VR_B;
9217 InsOp = LoongArch::XVEXTRINS_B;
9218 break;
9219 case LoongArch::PseudoXVINSGR2VR_H:
9220 HalfSize = 8;
9221 BroadcastOp = LoongArch::XVREPLGR2VR_H;
9222 InsOp = LoongArch::XVEXTRINS_H;
9223 break;
9224 }
9225 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9226 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
9227 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
9228 DebugLoc DL = MI.getDebugLoc();
9230 // XDst = vector_insert XSrc, Elt, Idx
9231 Register XDst = MI.getOperand(0).getReg();
9232 Register XSrc = MI.getOperand(1).getReg();
9233 Register Elt = MI.getOperand(2).getReg();
9234 unsigned Idx = MI.getOperand(3).getImm();
9235
9236 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
9237 Idx < HalfSize) {
9238 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
9239 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
9240
9241 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
9242 .addReg(XSrc, {}, LoongArch::sub_128);
9243 BuildMI(*BB, MI, DL,
9244 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
9245 : LoongArch::VINSGR2VR_B),
9246 ScratchSubReg2)
9247 .addReg(ScratchSubReg1)
9248 .addReg(Elt)
9249 .addImm(Idx);
9250
9251 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
9252 .addReg(ScratchSubReg2)
9253 .addImm(LoongArch::sub_128);
9254 } else {
9255 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9256 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9257
9258 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
9259
9260 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
9261 .addReg(ScratchReg1)
9262 .addReg(XSrc)
9263 .addImm(Idx >= HalfSize ? 48 : 18);
9264
9265 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
9266 .addReg(XSrc)
9267 .addReg(ScratchReg2)
9268 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
9269 }
9270
9271 MI.eraseFromParent();
9272 return BB;
9273}
9274
9278 assert(Subtarget.hasExtLSX());
9279 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9280 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9281 DebugLoc DL = MI.getDebugLoc();
9283 Register Dst = MI.getOperand(0).getReg();
9284 Register Src = MI.getOperand(1).getReg();
9285
9286 unsigned BroadcastOp, CTOp, PickOp;
9287 switch (MI.getOpcode()) {
9288 default:
9289 llvm_unreachable("Unexpected opcode");
9290 case LoongArch::PseudoCTPOP_B:
9291 BroadcastOp = LoongArch::VREPLGR2VR_B;
9292 CTOp = LoongArch::VPCNT_B;
9293 PickOp = LoongArch::VPICKVE2GR_B;
9294 break;
9295 case LoongArch::PseudoCTPOP_H:
9296 case LoongArch::PseudoCTPOP_H_LA32:
9297 BroadcastOp = LoongArch::VREPLGR2VR_H;
9298 CTOp = LoongArch::VPCNT_H;
9299 PickOp = LoongArch::VPICKVE2GR_H;
9300 break;
9301 case LoongArch::PseudoCTPOP_W:
9302 case LoongArch::PseudoCTPOP_W_LA32:
9303 BroadcastOp = LoongArch::VREPLGR2VR_W;
9304 CTOp = LoongArch::VPCNT_W;
9305 PickOp = LoongArch::VPICKVE2GR_W;
9306 break;
9307 case LoongArch::PseudoCTPOP_D:
9308 BroadcastOp = LoongArch::VREPLGR2VR_D;
9309 CTOp = LoongArch::VPCNT_D;
9310 PickOp = LoongArch::VPICKVE2GR_D;
9311 break;
9312 }
9313
9314 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9315 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9316 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9317 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9318 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9319
9320 MI.eraseFromParent();
9321 return BB;
9322}
9323
9324static MachineBasicBlock *
9327 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9328 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9329 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9331 Register Dst = MI.getOperand(0).getReg();
9332 Register Src = MI.getOperand(1).getReg();
9333 DebugLoc DL = MI.getDebugLoc();
9334 unsigned EleBits = 8;
9335 unsigned NotOpc = 0;
9336 unsigned MskOpc;
9337
9338 switch (MI.getOpcode()) {
9339 default:
9340 llvm_unreachable("Unexpected opcode");
9341 case LoongArch::PseudoVMSKLTZ_B:
9342 MskOpc = LoongArch::VMSKLTZ_B;
9343 break;
9344 case LoongArch::PseudoVMSKLTZ_H:
9345 MskOpc = LoongArch::VMSKLTZ_H;
9346 EleBits = 16;
9347 break;
9348 case LoongArch::PseudoVMSKLTZ_W:
9349 MskOpc = LoongArch::VMSKLTZ_W;
9350 EleBits = 32;
9351 break;
9352 case LoongArch::PseudoVMSKLTZ_D:
9353 MskOpc = LoongArch::VMSKLTZ_D;
9354 EleBits = 64;
9355 break;
9356 case LoongArch::PseudoVMSKGEZ_B:
9357 MskOpc = LoongArch::VMSKGEZ_B;
9358 break;
9359 case LoongArch::PseudoVMSKEQZ_B:
9360 MskOpc = LoongArch::VMSKNZ_B;
9361 NotOpc = LoongArch::VNOR_V;
9362 break;
9363 case LoongArch::PseudoVMSKNEZ_B:
9364 MskOpc = LoongArch::VMSKNZ_B;
9365 break;
9366 case LoongArch::PseudoXVMSKLTZ_B:
9367 MskOpc = LoongArch::XVMSKLTZ_B;
9368 RC = &LoongArch::LASX256RegClass;
9369 break;
9370 case LoongArch::PseudoXVMSKLTZ_H:
9371 MskOpc = LoongArch::XVMSKLTZ_H;
9372 RC = &LoongArch::LASX256RegClass;
9373 EleBits = 16;
9374 break;
9375 case LoongArch::PseudoXVMSKLTZ_W:
9376 MskOpc = LoongArch::XVMSKLTZ_W;
9377 RC = &LoongArch::LASX256RegClass;
9378 EleBits = 32;
9379 break;
9380 case LoongArch::PseudoXVMSKLTZ_D:
9381 MskOpc = LoongArch::XVMSKLTZ_D;
9382 RC = &LoongArch::LASX256RegClass;
9383 EleBits = 64;
9384 break;
9385 case LoongArch::PseudoXVMSKGEZ_B:
9386 MskOpc = LoongArch::XVMSKGEZ_B;
9387 RC = &LoongArch::LASX256RegClass;
9388 break;
9389 case LoongArch::PseudoXVMSKEQZ_B:
9390 MskOpc = LoongArch::XVMSKNZ_B;
9391 NotOpc = LoongArch::XVNOR_V;
9392 RC = &LoongArch::LASX256RegClass;
9393 break;
9394 case LoongArch::PseudoXVMSKNEZ_B:
9395 MskOpc = LoongArch::XVMSKNZ_B;
9396 RC = &LoongArch::LASX256RegClass;
9397 break;
9398 }
9399
9400 Register Msk = MRI.createVirtualRegister(RC);
9401 if (NotOpc) {
9402 Register Tmp = MRI.createVirtualRegister(RC);
9403 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9404 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk)
9405 .addReg(Tmp)
9406 .addReg(Tmp);
9407 } else {
9408 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9409 }
9410
9411 if (TRI->getRegSizeInBits(*RC) > 128) {
9412 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9413 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9414 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9415 .addReg(Msk)
9416 .addImm(0);
9417 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9418 .addReg(Msk)
9419 .addImm(4);
9420 BuildMI(*BB, MI, DL,
9421 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9422 : LoongArch::BSTRINS_W),
9423 Dst)
9424 .addReg(Lo)
9425 .addReg(Hi)
9426 .addImm(256 / EleBits - 1)
9427 .addImm(128 / EleBits);
9428 } else {
9429 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9430 .addReg(Msk)
9431 .addImm(0);
9432 }
9433
9434 MI.eraseFromParent();
9435 return BB;
9436}
9437
9438static MachineBasicBlock *
9441 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9442 "Unexpected instruction");
9443
9444 MachineFunction &MF = *BB->getParent();
9445 DebugLoc DL = MI.getDebugLoc();
9447 Register LoReg = MI.getOperand(0).getReg();
9448 Register HiReg = MI.getOperand(1).getReg();
9449 Register SrcReg = MI.getOperand(2).getReg();
9450
9451 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9452 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9453 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9454 MI.eraseFromParent(); // The pseudo instruction is gone now.
9455 return BB;
9456}
9457
9458static MachineBasicBlock *
9461 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9462 "Unexpected instruction");
9463
9464 MachineFunction &MF = *BB->getParent();
9465 DebugLoc DL = MI.getDebugLoc();
9468 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9469 Register DstReg = MI.getOperand(0).getReg();
9470 Register LoReg = MI.getOperand(1).getReg();
9471 Register HiReg = MI.getOperand(2).getReg();
9472
9473 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
9474 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
9475 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
9476 .addReg(TmpReg)
9477 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
9478 MI.eraseFromParent(); // The pseudo instruction is gone now.
9479 return BB;
9480}
9481
9483 switch (MI.getOpcode()) {
9484 default:
9485 return false;
9486 case LoongArch::Select_GPR_Using_CC_GPR:
9487 return true;
9488 }
9489}
9490
9491static MachineBasicBlock *
9494 // To "insert" Select_* instructions, we actually have to insert the triangle
9495 // control-flow pattern. The incoming instructions know the destination vreg
9496 // to set, the condition code register to branch on, the true/false values to
9497 // select between, and the condcode to use to select the appropriate branch.
9498 //
9499 // We produce the following control flow:
9500 // HeadMBB
9501 // | \
9502 // | IfFalseMBB
9503 // | /
9504 // TailMBB
9505 //
9506 // When we find a sequence of selects we attempt to optimize their emission
9507 // by sharing the control flow. Currently we only handle cases where we have
9508 // multiple selects with the exact same condition (same LHS, RHS and CC).
9509 // The selects may be interleaved with other instructions if the other
9510 // instructions meet some requirements we deem safe:
9511 // - They are not pseudo instructions.
9512 // - They are debug instructions. Otherwise,
9513 // - They do not have side-effects, do not access memory and their inputs do
9514 // not depend on the results of the select pseudo-instructions.
9515 // The TrueV/FalseV operands of the selects cannot depend on the result of
9516 // previous selects in the sequence.
9517 // These conditions could be further relaxed. See the X86 target for a
9518 // related approach and more information.
9519
9520 Register LHS = MI.getOperand(1).getReg();
9521 Register RHS;
9522 if (MI.getOperand(2).isReg())
9523 RHS = MI.getOperand(2).getReg();
9524 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
9525
9526 SmallVector<MachineInstr *, 4> SelectDebugValues;
9527 SmallSet<Register, 4> SelectDests;
9528 SelectDests.insert(MI.getOperand(0).getReg());
9529
9530 MachineInstr *LastSelectPseudo = &MI;
9531 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
9532 SequenceMBBI != E; ++SequenceMBBI) {
9533 if (SequenceMBBI->isDebugInstr())
9534 continue;
9535 if (isSelectPseudo(*SequenceMBBI)) {
9536 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
9537 !SequenceMBBI->getOperand(2).isReg() ||
9538 SequenceMBBI->getOperand(2).getReg() != RHS ||
9539 SequenceMBBI->getOperand(3).getImm() != CC ||
9540 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
9541 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
9542 break;
9543 LastSelectPseudo = &*SequenceMBBI;
9544 SequenceMBBI->collectDebugValues(SelectDebugValues);
9545 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
9546 continue;
9547 }
9548 if (SequenceMBBI->hasUnmodeledSideEffects() ||
9549 SequenceMBBI->mayLoadOrStore() ||
9550 SequenceMBBI->usesCustomInsertionHook())
9551 break;
9552 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
9553 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
9554 }))
9555 break;
9556 }
9557
9558 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
9559 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9560 DebugLoc DL = MI.getDebugLoc();
9562
9563 MachineBasicBlock *HeadMBB = BB;
9564 MachineFunction *F = BB->getParent();
9565 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
9566 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
9567
9568 F->insert(I, IfFalseMBB);
9569 F->insert(I, TailMBB);
9570
9571 // Set the call frame size on entry to the new basic blocks.
9572 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
9573 IfFalseMBB->setCallFrameSize(CallFrameSize);
9574 TailMBB->setCallFrameSize(CallFrameSize);
9575
9576 // Transfer debug instructions associated with the selects to TailMBB.
9577 for (MachineInstr *DebugInstr : SelectDebugValues) {
9578 TailMBB->push_back(DebugInstr->removeFromParent());
9579 }
9580
9581 // Move all instructions after the sequence to TailMBB.
9582 TailMBB->splice(TailMBB->end(), HeadMBB,
9583 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
9584 // Update machine-CFG edges by transferring all successors of the current
9585 // block to the new block which will contain the Phi nodes for the selects.
9586 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
9587 // Set the successors for HeadMBB.
9588 HeadMBB->addSuccessor(IfFalseMBB);
9589 HeadMBB->addSuccessor(TailMBB);
9590
9591 // Insert appropriate branch.
9592 if (MI.getOperand(2).isImm())
9593 BuildMI(HeadMBB, DL, TII.get(CC))
9594 .addReg(LHS)
9595 .addImm(MI.getOperand(2).getImm())
9596 .addMBB(TailMBB);
9597 else
9598 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
9599
9600 // IfFalseMBB just falls through to TailMBB.
9601 IfFalseMBB->addSuccessor(TailMBB);
9602
9603 // Create PHIs for all of the select pseudo-instructions.
9604 auto SelectMBBI = MI.getIterator();
9605 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
9606 auto InsertionPoint = TailMBB->begin();
9607 while (SelectMBBI != SelectEnd) {
9608 auto Next = std::next(SelectMBBI);
9609 if (isSelectPseudo(*SelectMBBI)) {
9610 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
9611 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
9612 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
9613 .addReg(SelectMBBI->getOperand(4).getReg())
9614 .addMBB(HeadMBB)
9615 .addReg(SelectMBBI->getOperand(5).getReg())
9616 .addMBB(IfFalseMBB);
9617 SelectMBBI->eraseFromParent();
9618 }
9619 SelectMBBI = Next;
9620 }
9621
9622 F->getProperties().resetNoPHIs();
9623 return TailMBB;
9624}
9625
9626MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
9627 MachineInstr &MI, MachineBasicBlock *BB) const {
9628 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9629 DebugLoc DL = MI.getDebugLoc();
9630
9631 switch (MI.getOpcode()) {
9632 default:
9633 llvm_unreachable("Unexpected instr type to insert");
9634 case LoongArch::DIV_W:
9635 case LoongArch::DIV_WU:
9636 case LoongArch::MOD_W:
9637 case LoongArch::MOD_WU:
9638 case LoongArch::DIV_D:
9639 case LoongArch::DIV_DU:
9640 case LoongArch::MOD_D:
9641 case LoongArch::MOD_DU:
9642 return insertDivByZeroTrap(MI, BB);
9643 break;
9644 case LoongArch::WRFCSR: {
9645 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
9646 LoongArch::FCSR0 + MI.getOperand(0).getImm())
9647 .addReg(MI.getOperand(1).getReg());
9648 MI.eraseFromParent();
9649 return BB;
9650 }
9651 case LoongArch::RDFCSR: {
9652 MachineInstr *ReadFCSR =
9653 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
9654 MI.getOperand(0).getReg())
9655 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
9656 ReadFCSR->getOperand(1).setIsUndef();
9657 MI.eraseFromParent();
9658 return BB;
9659 }
9660 case LoongArch::Select_GPR_Using_CC_GPR:
9661 return emitSelectPseudo(MI, BB, Subtarget);
9662 case LoongArch::BuildPairF64Pseudo:
9663 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
9664 case LoongArch::SplitPairF64Pseudo:
9665 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
9666 case LoongArch::PseudoXVINSGR2VR_B:
9667 case LoongArch::PseudoXVINSGR2VR_H:
9668 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
9669 case LoongArch::PseudoCTPOP_B:
9670 case LoongArch::PseudoCTPOP_H:
9671 case LoongArch::PseudoCTPOP_W:
9672 case LoongArch::PseudoCTPOP_D:
9673 case LoongArch::PseudoCTPOP_H_LA32:
9674 case LoongArch::PseudoCTPOP_W_LA32:
9675 return emitPseudoCTPOP(MI, BB, Subtarget);
9676 case LoongArch::PseudoVMSKLTZ_B:
9677 case LoongArch::PseudoVMSKLTZ_H:
9678 case LoongArch::PseudoVMSKLTZ_W:
9679 case LoongArch::PseudoVMSKLTZ_D:
9680 case LoongArch::PseudoVMSKGEZ_B:
9681 case LoongArch::PseudoVMSKEQZ_B:
9682 case LoongArch::PseudoVMSKNEZ_B:
9683 case LoongArch::PseudoXVMSKLTZ_B:
9684 case LoongArch::PseudoXVMSKLTZ_H:
9685 case LoongArch::PseudoXVMSKLTZ_W:
9686 case LoongArch::PseudoXVMSKLTZ_D:
9687 case LoongArch::PseudoXVMSKGEZ_B:
9688 case LoongArch::PseudoXVMSKEQZ_B:
9689 case LoongArch::PseudoXVMSKNEZ_B:
9690 return emitPseudoVMSKCOND(MI, BB, Subtarget);
9691 case TargetOpcode::STATEPOINT:
9692 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
9693 // while bl call instruction (where statepoint will be lowered at the
9694 // end) has implicit def. This def is early-clobber as it will be set at
9695 // the moment of the call and earlier than any use is read.
9696 // Add this implicit dead def here as a workaround.
9697 MI.addOperand(*MI.getMF(),
9699 LoongArch::R1, /*isDef*/ true,
9700 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
9701 /*isUndef*/ false, /*isEarlyClobber*/ true));
9702 if (!Subtarget.is64Bit())
9703 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
9704 return emitPatchPoint(MI, BB);
9705 case LoongArch::PROBED_STACKALLOC_DYN:
9706 return emitDynamicProbedAlloc(MI, BB);
9707 }
9708}
9709
9711 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
9712 unsigned *Fast) const {
9713 if (!Subtarget.hasUAL())
9714 return false;
9715
9716 // TODO: set reasonable speed number.
9717 if (Fast)
9718 *Fast = 1;
9719 return true;
9720}
9721
9722//===----------------------------------------------------------------------===//
9723// Calling Convention Implementation
9724//===----------------------------------------------------------------------===//
9725
9726// Eight general-purpose registers a0-a7 used for passing integer arguments,
9727// with a0-a1 reused to return values. Generally, the GPRs are used to pass
9728// fixed-point arguments, and floating-point arguments when no FPR is available
9729// or with soft float ABI.
9730const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
9731 LoongArch::R7, LoongArch::R8, LoongArch::R9,
9732 LoongArch::R10, LoongArch::R11};
9733
9734// PreserveNone calling convention:
9735// Arguments may be passed in any general-purpose registers except:
9736// - R1 : return address register
9737// - R22 : frame pointer
9738// - R31 : base pointer
9739//
9740// All general-purpose registers are treated as caller-saved,
9741// except R1 (RA) and R22 (FP).
9742//
9743// Non-volatile registers are allocated first so that a function
9744// can call normal functions without having to spill and reload
9745// argument registers.
9747 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
9748 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
9749 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
9750 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
9751 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
9752 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
9753 LoongArch::R20};
9754
9755// Eight floating-point registers fa0-fa7 used for passing floating-point
9756// arguments, and fa0-fa1 are also used to return values.
9757const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
9758 LoongArch::F3, LoongArch::F4, LoongArch::F5,
9759 LoongArch::F6, LoongArch::F7};
9760// FPR32 and FPR64 alias each other.
9762 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
9763 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
9764
9765const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
9766 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
9767 LoongArch::VR6, LoongArch::VR7};
9768
9769const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
9770 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
9771 LoongArch::XR6, LoongArch::XR7};
9772
9774 switch (State.getCallingConv()) {
9776 if (!State.isVarArg())
9777 return State.AllocateReg(PreserveNoneArgGPRs);
9778 [[fallthrough]];
9779 default:
9780 return State.AllocateReg(ArgGPRs);
9781 }
9782}
9783
9784// Pass a 2*GRLen argument that has been split into two GRLen values through
9785// registers or the stack as necessary.
9786static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
9787 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
9788 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
9789 ISD::ArgFlagsTy ArgFlags2) {
9790 unsigned GRLenInBytes = GRLen / 8;
9791 if (Register Reg = allocateArgGPR(State)) {
9792 // At least one half can be passed via register.
9793 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
9794 VA1.getLocVT(), CCValAssign::Full));
9795 } else {
9796 // Both halves must be passed on the stack, with proper alignment.
9797 Align StackAlign =
9798 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
9799 State.addLoc(
9801 State.AllocateStack(GRLenInBytes, StackAlign),
9802 VA1.getLocVT(), CCValAssign::Full));
9803 State.addLoc(CCValAssign::getMem(
9804 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9805 LocVT2, CCValAssign::Full));
9806 return false;
9807 }
9808 if (Register Reg = allocateArgGPR(State)) {
9809 // The second half can also be passed via register.
9810 State.addLoc(
9811 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
9812 } else {
9813 // The second half is passed via the stack, without additional alignment.
9814 State.addLoc(CCValAssign::getMem(
9815 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9816 LocVT2, CCValAssign::Full));
9817 }
9818 return false;
9819}
9820
9821// Implements the LoongArch calling convention. Returns true upon failure.
9823 unsigned ValNo, MVT ValVT,
9824 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
9825 CCState &State, bool IsRet, Type *OrigTy) {
9826 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
9827 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
9828 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
9829 MVT LocVT = ValVT;
9830
9831 // Any return value split into more than two values can't be returned
9832 // directly.
9833 if (IsRet && ValNo > 1)
9834 return true;
9835
9836 // If passing a variadic argument, or if no FPR is available.
9837 bool UseGPRForFloat = true;
9838
9839 switch (ABI) {
9840 default:
9841 llvm_unreachable("Unexpected ABI");
9842 break;
9847 UseGPRForFloat = ArgFlags.isVarArg();
9848 break;
9851 break;
9852 }
9853
9854 // If this is a variadic argument, the LoongArch calling convention requires
9855 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
9856 // byte alignment. An aligned register should be used regardless of whether
9857 // the original argument was split during legalisation or not. The argument
9858 // will not be passed by registers if the original type is larger than
9859 // 2*GRLen, so the register alignment rule does not apply.
9860 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
9861 if (ArgFlags.isVarArg() &&
9862 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
9863 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
9864 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
9865 // Skip 'odd' register if necessary.
9866 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
9867 State.AllocateReg(ArgGPRs);
9868 }
9869
9870 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
9871 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
9872 State.getPendingArgFlags();
9873
9874 assert(PendingLocs.size() == PendingArgFlags.size() &&
9875 "PendingLocs and PendingArgFlags out of sync");
9876
9877 // FPR32 and FPR64 alias each other.
9878 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
9879 UseGPRForFloat = true;
9880
9881 if (UseGPRForFloat && ValVT == MVT::f32) {
9882 LocVT = GRLenVT;
9883 LocInfo = CCValAssign::BCvt;
9884 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
9885 LocVT = MVT::i64;
9886 LocInfo = CCValAssign::BCvt;
9887 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
9888 // Handle passing f64 on LA32D with a soft float ABI or when floating point
9889 // registers are exhausted.
9890 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
9891 // Depending on available argument GPRS, f64 may be passed in a pair of
9892 // GPRs, split between a GPR and the stack, or passed completely on the
9893 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
9894 // cases.
9895 MCRegister Reg = allocateArgGPR(State);
9896 if (!Reg) {
9897 int64_t StackOffset = State.AllocateStack(8, Align(8));
9898 State.addLoc(
9899 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9900 return false;
9901 }
9902 LocVT = MVT::i32;
9903 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9904 MCRegister HiReg = allocateArgGPR(State);
9905 if (HiReg) {
9906 State.addLoc(
9907 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
9908 } else {
9909 int64_t StackOffset = State.AllocateStack(4, Align(4));
9910 State.addLoc(
9911 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9912 }
9913 return false;
9914 }
9915
9916 // Split arguments might be passed indirectly, so keep track of the pending
9917 // values.
9918 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
9919 LocVT = GRLenVT;
9920 LocInfo = CCValAssign::Indirect;
9921 PendingLocs.push_back(
9922 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
9923 PendingArgFlags.push_back(ArgFlags);
9924 if (!ArgFlags.isSplitEnd()) {
9925 return false;
9926 }
9927 }
9928
9929 // If the split argument only had two elements, it should be passed directly
9930 // in registers or on the stack.
9931 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
9932 PendingLocs.size() <= 2) {
9933 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
9934 // Apply the normal calling convention rules to the first half of the
9935 // split argument.
9936 CCValAssign VA = PendingLocs[0];
9937 ISD::ArgFlagsTy AF = PendingArgFlags[0];
9938 PendingLocs.clear();
9939 PendingArgFlags.clear();
9940 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
9941 ArgFlags);
9942 }
9943
9944 // Allocate to a register if possible, or else a stack slot.
9945 Register Reg;
9946 unsigned StoreSizeBytes = GRLen / 8;
9947 Align StackAlign = Align(GRLen / 8);
9948
9949 if (ValVT == MVT::f32 && !UseGPRForFloat) {
9950 Reg = State.AllocateReg(ArgFPR32s);
9951 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
9952 Reg = State.AllocateReg(ArgFPR64s);
9953 } else if (ValVT.is128BitVector()) {
9954 Reg = State.AllocateReg(ArgVRs);
9955 UseGPRForFloat = false;
9956 StoreSizeBytes = 16;
9957 StackAlign = Align(16);
9958 } else if (ValVT.is256BitVector()) {
9959 Reg = State.AllocateReg(ArgXRs);
9960 UseGPRForFloat = false;
9961 StoreSizeBytes = 32;
9962 StackAlign = Align(32);
9963 } else {
9964 Reg = allocateArgGPR(State);
9965 }
9966
9967 unsigned StackOffset =
9968 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
9969
9970 // If we reach this point and PendingLocs is non-empty, we must be at the
9971 // end of a split argument that must be passed indirectly.
9972 if (!PendingLocs.empty()) {
9973 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
9974 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
9975 for (auto &It : PendingLocs) {
9976 if (Reg)
9977 It.convertToReg(Reg);
9978 else
9979 It.convertToMem(StackOffset);
9980 State.addLoc(It);
9981 }
9982 PendingLocs.clear();
9983 PendingArgFlags.clear();
9984 return false;
9985 }
9986 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
9987 "Expected an GRLenVT at this stage");
9988
9989 if (Reg) {
9990 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9991 return false;
9992 }
9993
9994 // When a floating-point value is passed on the stack, no bit-cast is needed.
9995 if (ValVT.isFloatingPoint()) {
9996 LocVT = ValVT;
9997 LocInfo = CCValAssign::Full;
9998 }
9999
10000 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10001 return false;
10002}
10003
10004void LoongArchTargetLowering::analyzeInputArgs(
10005 MachineFunction &MF, CCState &CCInfo,
10006 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
10007 LoongArchCCAssignFn Fn) const {
10008 FunctionType *FType = MF.getFunction().getFunctionType();
10009 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
10010 MVT ArgVT = Ins[i].VT;
10011 Type *ArgTy = nullptr;
10012 if (IsRet)
10013 ArgTy = FType->getReturnType();
10014 else if (Ins[i].isOrigArg())
10015 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
10017 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10018 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
10019 CCInfo, IsRet, ArgTy)) {
10020 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
10021 << '\n');
10022 llvm_unreachable("");
10023 }
10024 }
10025}
10026
10027void LoongArchTargetLowering::analyzeOutputArgs(
10028 MachineFunction &MF, CCState &CCInfo,
10029 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
10030 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
10031 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10032 MVT ArgVT = Outs[i].VT;
10033 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
10035 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10036 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
10037 CCInfo, IsRet, OrigTy)) {
10038 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
10039 << "\n");
10040 llvm_unreachable("");
10041 }
10042 }
10043}
10044
10045// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
10046// values.
10048 const CCValAssign &VA, const SDLoc &DL) {
10049 switch (VA.getLocInfo()) {
10050 default:
10051 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10052 case CCValAssign::Full:
10054 break;
10055 case CCValAssign::BCvt:
10056 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10057 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
10058 else
10059 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10060 break;
10061 }
10062 return Val;
10063}
10064
10066 const CCValAssign &VA, const SDLoc &DL,
10067 const ISD::InputArg &In,
10071 EVT LocVT = VA.getLocVT();
10072 SDValue Val;
10073 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
10074 Register VReg = RegInfo.createVirtualRegister(RC);
10075 RegInfo.addLiveIn(VA.getLocReg(), VReg);
10076 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
10077
10078 // If input is sign extended from 32 bits, note it for the OptW pass.
10079 if (In.isOrigArg()) {
10080 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
10081 if (OrigArg->getType()->isIntegerTy()) {
10082 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
10083 // An input zero extended from i31 can also be considered sign extended.
10084 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
10085 (BitWidth < 32 && In.Flags.isZExt())) {
10088 LAFI->addSExt32Register(VReg);
10089 }
10090 }
10091 }
10092
10093 return convertLocVTToValVT(DAG, Val, VA, DL);
10094}
10095
10096// The caller is responsible for loading the full value if the argument is
10097// passed with CCValAssign::Indirect.
10099 const CCValAssign &VA, const SDLoc &DL) {
10101 MachineFrameInfo &MFI = MF.getFrameInfo();
10102 EVT ValVT = VA.getValVT();
10103 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
10104 /*IsImmutable=*/true);
10105 SDValue FIN = DAG.getFrameIndex(
10107
10108 ISD::LoadExtType ExtType;
10109 switch (VA.getLocInfo()) {
10110 default:
10111 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10112 case CCValAssign::Full:
10114 case CCValAssign::BCvt:
10115 ExtType = ISD::NON_EXTLOAD;
10116 break;
10117 }
10118 return DAG.getExtLoad(
10119 ExtType, DL, VA.getLocVT(), Chain, FIN,
10121}
10122
10124 const CCValAssign &VA,
10125 const CCValAssign &HiVA,
10126 const SDLoc &DL) {
10127 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
10128 "Unexpected VA");
10130 MachineFrameInfo &MFI = MF.getFrameInfo();
10132
10133 assert(VA.isRegLoc() && "Expected register VA assignment");
10134
10135 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10136 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
10137 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
10138 SDValue Hi;
10139 if (HiVA.isMemLoc()) {
10140 // Second half of f64 is passed on the stack.
10141 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
10142 /*IsImmutable=*/true);
10143 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
10144 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
10146 } else {
10147 // Second half of f64 is passed in another GPR.
10148 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10149 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
10150 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
10151 }
10152 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
10153}
10154
10156 const CCValAssign &VA, const SDLoc &DL) {
10157 EVT LocVT = VA.getLocVT();
10158
10159 switch (VA.getLocInfo()) {
10160 default:
10161 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10162 case CCValAssign::Full:
10163 break;
10164 case CCValAssign::BCvt:
10165 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10166 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
10167 else
10168 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10169 break;
10170 }
10171 return Val;
10172}
10173
10174static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
10175 CCValAssign::LocInfo LocInfo,
10176 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
10177 CCState &State) {
10178 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
10179 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
10180 // s0 s1 s2 s3 s4 s5 s6 s7 s8
10181 static const MCPhysReg GPRList[] = {
10182 LoongArch::R23, LoongArch::R24, LoongArch::R25,
10183 LoongArch::R26, LoongArch::R27, LoongArch::R28,
10184 LoongArch::R29, LoongArch::R30, LoongArch::R31};
10185 if (MCRegister Reg = State.AllocateReg(GPRList)) {
10186 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10187 return false;
10188 }
10189 }
10190
10191 if (LocVT == MVT::f32) {
10192 // Pass in STG registers: F1, F2, F3, F4
10193 // fs0,fs1,fs2,fs3
10194 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
10195 LoongArch::F26, LoongArch::F27};
10196 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
10197 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10198 return false;
10199 }
10200 }
10201
10202 if (LocVT == MVT::f64) {
10203 // Pass in STG registers: D1, D2, D3, D4
10204 // fs4,fs5,fs6,fs7
10205 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
10206 LoongArch::F30_64, LoongArch::F31_64};
10207 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
10208 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10209 return false;
10210 }
10211 }
10212
10213 report_fatal_error("No registers left in GHC calling convention");
10214 return true;
10215}
10216
10217// Transform physical registers into virtual registers.
10219 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10220 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
10221 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
10222
10224
10225 switch (CallConv) {
10226 default:
10227 llvm_unreachable("Unsupported calling convention");
10228 case CallingConv::C:
10229 case CallingConv::Fast:
10232 break;
10233 case CallingConv::GHC:
10234 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
10235 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
10237 "GHC calling convention requires the F and D extensions");
10238 }
10239
10240 const Function &Func = MF.getFunction();
10241 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10242 MVT GRLenVT = Subtarget.getGRLenVT();
10243 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
10244
10245 // Check if this function has any musttail calls. If so, incoming indirect
10246 // arg pointers must be saved in virtual registers so they survive across
10247 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
10248 // when needed to avoid adding register pressure to non-musttail functions.
10249 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
10250 return llvm::any_of(BB, [](const Instruction &I) {
10251 if (const auto *CI = dyn_cast<CallInst>(&I))
10252 return CI->isMustTailCall();
10253 return false;
10254 });
10255 });
10256 // Used with varargs to acumulate store chains.
10257 std::vector<SDValue> OutChains;
10258
10259 // Assign locations to all of the incoming arguments.
10261 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10262
10263 if (CallConv == CallingConv::GHC)
10265 else
10266 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
10267
10268 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10269 CCValAssign &VA = ArgLocs[i];
10270 SDValue ArgValue;
10271 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10272 // case.
10273 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10274 assert(VA.needsCustom());
10275 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10276 } else if (VA.isRegLoc())
10277 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10278 else
10279 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10280 if (VA.getLocInfo() == CCValAssign::Indirect) {
10281 // If the original argument was split and passed by reference, we need to
10282 // load all parts of it here (using the same address).
10283 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10285 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10286 if (HasMusttail) {
10289 Register VReg =
10290 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10291 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10292 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10293 }
10294 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10295 assert(ArgPartOffset == 0);
10296 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10297 CCValAssign &PartVA = ArgLocs[i + 1];
10298 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10299 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10300 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10301 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10303 ++i;
10304 ++InsIdx;
10305 }
10306 continue;
10307 }
10308 InVals.push_back(ArgValue);
10309 }
10310
10311 if (IsVarArg) {
10313 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10314 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10315 MachineFrameInfo &MFI = MF.getFrameInfo();
10316 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10317 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10318
10319 // Offset of the first variable argument from stack pointer, and size of
10320 // the vararg save area. For now, the varargs save area is either zero or
10321 // large enough to hold a0-a7.
10322 int VaArgOffset, VarArgsSaveSize;
10323
10324 // If all registers are allocated, then all varargs must be passed on the
10325 // stack and we don't need to save any argregs.
10326 if (ArgRegs.size() == Idx) {
10327 VaArgOffset = CCInfo.getStackSize();
10328 VarArgsSaveSize = 0;
10329 } else {
10330 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10331 VaArgOffset = -VarArgsSaveSize;
10332 }
10333
10334 // Record the frame index of the first variable argument
10335 // which is a value necessary to VASTART.
10336 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10337 LoongArchFI->setVarArgsFrameIndex(FI);
10338
10339 // If saving an odd number of registers then create an extra stack slot to
10340 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10341 // offsets to even-numbered registered remain 2*GRLen-aligned.
10342 if (Idx % 2) {
10343 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10344 true);
10345 VarArgsSaveSize += GRLenInBytes;
10346 }
10347
10348 // Copy the integer registers that may have been used for passing varargs
10349 // to the vararg save area.
10350 for (unsigned I = Idx; I < ArgRegs.size();
10351 ++I, VaArgOffset += GRLenInBytes) {
10352 const Register Reg = RegInfo.createVirtualRegister(RC);
10353 RegInfo.addLiveIn(ArgRegs[I], Reg);
10354 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10355 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10356 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10357 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10359 cast<StoreSDNode>(Store.getNode())
10360 ->getMemOperand()
10361 ->setValue((Value *)nullptr);
10362 OutChains.push_back(Store);
10363 }
10364 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10365 }
10366
10367 // All stores are grouped in one node to allow the matching between
10368 // the size of Ins and InVals. This only happens for vararg functions.
10369 if (!OutChains.empty()) {
10370 OutChains.push_back(Chain);
10371 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10372 }
10373
10374 return Chain;
10375}
10376
10378 return CI->isTailCall();
10379}
10380
10381// Check if the return value is used as only a return value, as otherwise
10382// we can't perform a tail-call.
10384 SDValue &Chain) const {
10385 if (N->getNumValues() != 1)
10386 return false;
10387 if (!N->hasNUsesOfValue(1, 0))
10388 return false;
10389
10390 SDNode *Copy = *N->user_begin();
10391 if (Copy->getOpcode() != ISD::CopyToReg)
10392 return false;
10393
10394 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10395 // isn't safe to perform a tail call.
10396 if (Copy->getGluedNode())
10397 return false;
10398
10399 // The copy must be used by a LoongArchISD::RET, and nothing else.
10400 bool HasRet = false;
10401 for (SDNode *Node : Copy->users()) {
10402 if (Node->getOpcode() != LoongArchISD::RET)
10403 return false;
10404 HasRet = true;
10405 }
10406
10407 if (!HasRet)
10408 return false;
10409
10410 Chain = Copy->getOperand(0);
10411 return true;
10412}
10413
10414// Check whether the call is eligible for tail call optimization.
10415bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10416 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10417 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10418
10419 auto CalleeCC = CLI.CallConv;
10420 auto &Outs = CLI.Outs;
10421 auto &Caller = MF.getFunction();
10422 auto CallerCC = Caller.getCallingConv();
10423
10424 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10425
10426 // Byval parameters hand the function a pointer directly into the stack area
10427 // we want to reuse during a tail call. Working around this *is* possible
10428 // but less efficient and uglier in LowerCall. For musttail, there is no
10429 // workaround today: a byval arg requires a local copy that becomes invalid
10430 // after the tail call deallocates the caller's frame, so rejecting here
10431 // (and triggering reportFatalInternalError in LowerCall) is safer than
10432 // miscompiling.
10433 for (auto &Arg : Outs)
10434 if (Arg.Flags.isByVal())
10435 return false;
10436
10437 // musttail bypasses the remaining checks: the checks either reject cases
10438 // we handle specially (indirect args are forwarded via incoming pointers,
10439 // stack-passed args reuse the matching incoming layout, sret is forwarded
10440 // like any other pointer arg) or are optimizations not applicable to
10441 // mandatory tail calls.
10442 if (IsMustTail)
10443 return true;
10444
10445 // Do not tail call opt if the stack is used to pass parameters.
10446 if (CCInfo.getStackSize() != 0)
10447 return false;
10448
10449 // Do not tail call opt if any parameters need to be passed indirectly.
10450 for (auto &VA : ArgLocs)
10451 if (VA.getLocInfo() == CCValAssign::Indirect)
10452 return false;
10453
10454 // Do not tail call opt if either caller or callee uses struct return
10455 // semantics.
10456 auto IsCallerStructRet = Caller.hasStructRetAttr();
10457 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10458 if (IsCallerStructRet || IsCalleeStructRet)
10459 return false;
10460
10461 // The callee has to preserve all registers the caller needs to preserve.
10462 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10463 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10464 if (CalleeCC != CallerCC) {
10465 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10466 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10467 return false;
10468 }
10469 return true;
10470}
10471
10473 return DAG.getDataLayout().getPrefTypeAlign(
10474 VT.getTypeForEVT(*DAG.getContext()));
10475}
10476
10477// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
10478// and output parameter nodes.
10479SDValue
10481 SmallVectorImpl<SDValue> &InVals) const {
10482 SelectionDAG &DAG = CLI.DAG;
10483 SDLoc &DL = CLI.DL;
10485 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10487 SDValue Chain = CLI.Chain;
10488 SDValue Callee = CLI.Callee;
10489 CallingConv::ID CallConv = CLI.CallConv;
10490 bool IsVarArg = CLI.IsVarArg;
10491 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10492 MVT GRLenVT = Subtarget.getGRLenVT();
10493 bool &IsTailCall = CLI.IsTailCall;
10494
10496
10497 // Analyze the operands of the call, assigning locations to each operand.
10499 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10500
10501 if (CallConv == CallingConv::GHC)
10502 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
10503 else
10504 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
10505
10506 // Check if it's really possible to do a tail call.
10507 if (IsTailCall)
10508 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
10509
10510 if (IsTailCall)
10511 ++NumTailCalls;
10512 else if (CLI.CB && CLI.CB->isMustTailCall())
10513 report_fatal_error("failed to perform tail call elimination on a call "
10514 "site marked musttail");
10515
10516 // Get a count of how many bytes are to be pushed on the stack.
10517 unsigned NumBytes = ArgCCInfo.getStackSize();
10518
10519 // Create local copies for byval args.
10520 SmallVector<SDValue> ByValArgs;
10521 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10522 ISD::ArgFlagsTy Flags = Outs[i].Flags;
10523 if (!Flags.isByVal())
10524 continue;
10525
10526 SDValue Arg = OutVals[i];
10527 unsigned Size = Flags.getByValSize();
10528 Align Alignment = Flags.getNonZeroByValAlign();
10529
10530 int FI =
10531 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
10532 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10533 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
10534
10535 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
10536 /*IsVolatile=*/false,
10537 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
10539 ByValArgs.push_back(FIPtr);
10540 }
10541
10542 if (!IsTailCall)
10543 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
10544
10545 // Copy argument values to their designated locations.
10547 SmallVector<SDValue> MemOpChains;
10548 SDValue StackPtr;
10549 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
10550 ++i, ++OutIdx) {
10551 CCValAssign &VA = ArgLocs[i];
10552 SDValue ArgValue = OutVals[OutIdx];
10553 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
10554
10555 // Handle passing f64 on LA32D with a soft float ABI as a special case.
10556 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10557 assert(VA.isRegLoc() && "Expected register VA assignment");
10558 assert(VA.needsCustom());
10559 SDValue SplitF64 =
10560 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10561 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
10562 SDValue Lo = SplitF64.getValue(0);
10563 SDValue Hi = SplitF64.getValue(1);
10564
10565 Register RegLo = VA.getLocReg();
10566 RegsToPass.push_back(std::make_pair(RegLo, Lo));
10567
10568 // Get the CCValAssign for the Hi part.
10569 CCValAssign &HiVA = ArgLocs[++i];
10570
10571 if (HiVA.isMemLoc()) {
10572 // Second half of f64 is passed on the stack.
10573 if (!StackPtr.getNode())
10574 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10576 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10577 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
10578 // Emit the store.
10579 MemOpChains.push_back(DAG.getStore(
10580 Chain, DL, Hi, Address,
10582 } else {
10583 // Second half of f64 is passed in another GPR.
10584 Register RegHigh = HiVA.getLocReg();
10585 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
10586 }
10587 continue;
10588 }
10589
10590 // Promote the value if needed.
10591 // For now, only handle fully promoted and indirect arguments.
10592 if (VA.getLocInfo() == CCValAssign::Indirect) {
10593 // For musttail calls, reuse incoming indirect pointers instead of
10594 // creating new stack temporaries. The incoming pointers point to the
10595 // caller's caller's frame, which remains valid after a tail call.
10596 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
10599 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
10600
10601 // Resolve which formal parameter is being passed at this call
10602 // position.
10603 //
10604 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
10605 // but Outs[].OrigArgIndex is an index into a filtered arg list
10606 // (empty types removed, via CallLoweringInfo in the target-
10607 // independent layer). IncomingIndirectArgs is keyed by the
10608 // caller's unfiltered Argument::getArgNo(), so we have to walk
10609 // the caller's formals (same filter) to translate the index.
10610 // This target-independent asymmetry should be normalized so
10611 // backends do not need to re-derive the mapping.
10612 //
10613 // Steps:
10614 // 1. Find the call operand at filtered position CallArgIdx.
10615 // 2. If it is an Argument, use getArgNo() directly (same filter
10616 // for caller formals and call operands).
10617 // 3. Otherwise (computed value), walk the caller's formals and
10618 // skip empty types to map the filtered index to getArgNo().
10619 const Argument *FormalArg = nullptr;
10620 unsigned FilteredIdx = 0;
10621 for (const auto &CallArg : CLI.CB->args()) {
10622 if (CallArg->getType()->isEmptyTy())
10623 continue;
10624 if (FilteredIdx == CallArgIdx) {
10625 FormalArg = dyn_cast<Argument>(CallArg);
10626 break;
10627 }
10628 ++FilteredIdx;
10629 }
10630
10631 // For forwarded args, getArgNo() gives the unfiltered index directly.
10632 // For computed args, walk the caller's formals to resolve it.
10633 unsigned FormalArgIdx = CallArgIdx;
10634 if (FormalArg) {
10635 FormalArgIdx = FormalArg->getArgNo();
10636 } else {
10637 FilteredIdx = 0;
10638 for (const auto &Arg : MF.getFunction().args()) {
10639 if (Arg.getType()->isEmptyTy())
10640 continue;
10641 if (FilteredIdx == CallArgIdx) {
10642 FormalArgIdx = Arg.getArgNo();
10643 break;
10644 }
10645 ++FilteredIdx;
10646 }
10647 }
10648
10649 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
10650 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
10651 // Thread the CopyFromReg output chain through MemOpChains so the
10652 // TokenFactor below sequences the copy with any stores we emit
10653 // for this argument.
10654 MemOpChains.push_back(CopyOp.getValue(1));
10655 SDValue IncomingPtr = CopyOp;
10656
10657 if (!FormalArg) {
10658 // Computed value: store into the incoming indirect pointer for the
10659 // same-position formal parameter (musttail guarantees matching
10660 // prototypes, so types match). The pointer survives the tail call
10661 // since it points to the caller's caller's frame.
10662 //
10663 // The data-flow edge through IncomingPtr already prevents the
10664 // store from being scheduled before the CopyFromReg. Threading
10665 // CopyOp.getValue(1) (the copy's output chain) into the store
10666 // makes that ordering explicit on the chain edge as well, which
10667 // is the convention for memory ops chaining off their producers.
10668 MemOpChains.push_back(
10669 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
10671 // Store any split parts at their respective offsets.
10672 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10673 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10674 SDValue PartValue = OutVals[OutIdx + 1];
10675 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10676 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10677 SDValue Addr =
10678 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
10679 MemOpChains.push_back(
10680 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
10682 ++i;
10683 ++OutIdx;
10684 }
10685 }
10686 ArgValue = IncomingPtr;
10687
10688 // Skip any remaining split parts (for forwarded args, they are
10689 // covered by the forwarded pointer).
10690 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10691 ++i;
10692 ++OutIdx;
10693 }
10694 } else {
10695 // Store the argument in a stack slot and pass its address.
10696 Align StackAlign =
10697 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
10698 getPrefTypeAlign(ArgValue.getValueType(), DAG));
10699 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
10700 // If the original argument was split and passed by reference, we need
10701 // to store the required parts of it here (and pass just one address).
10702 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
10703 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10704 assert(ArgPartOffset == 0);
10705 // Calculate the total size to store. We don't have access to what we're
10706 // actually storing other than performing the loop and collecting the
10707 // info.
10709 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
10710 SDValue PartValue = OutVals[OutIdx + 1];
10711 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10712 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10713 EVT PartVT = PartValue.getValueType();
10714 StoredSize += PartVT.getStoreSize();
10715 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
10716 Parts.push_back(std::make_pair(PartValue, Offset));
10717 ++i;
10718 ++OutIdx;
10719 }
10720 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
10721 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
10722 MemOpChains.push_back(
10723 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
10725 for (const auto &Part : Parts) {
10726 SDValue PartValue = Part.first;
10727 SDValue PartOffset = Part.second;
10729 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
10730 MemOpChains.push_back(
10731 DAG.getStore(Chain, DL, PartValue, Address,
10733 }
10734 ArgValue = SpillSlot;
10735 }
10736 } else {
10737 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
10738 }
10739
10740 // Use local copy if it is a byval arg.
10741 if (Flags.isByVal())
10742 ArgValue = ByValArgs[j++];
10743
10744 if (VA.isRegLoc()) {
10745 // Queue up the argument copies and emit them at the end.
10746 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
10747 } else {
10748 assert(VA.isMemLoc() && "Argument not register or memory");
10749 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
10750 "Tail call not allowed if stack is used for passing parameters");
10751
10752 // Work out the address of the stack slot.
10753 if (!StackPtr.getNode())
10754 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10756 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10758
10759 // Emit the store.
10760 MemOpChains.push_back(
10761 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
10762 }
10763 }
10764
10765 // Join the stores, which are independent of one another.
10766 if (!MemOpChains.empty())
10767 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
10768
10769 SDValue Glue;
10770
10771 // Build a sequence of copy-to-reg nodes, chained and glued together.
10772 for (auto &Reg : RegsToPass) {
10773 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
10774 Glue = Chain.getValue(1);
10775 }
10776
10777 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
10778 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
10779 // split it and then direct call can be matched by PseudoCALL_SMALL.
10781 const GlobalValue *GV = S->getGlobal();
10782 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
10785 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
10786 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
10787 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
10790 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
10791 }
10792
10793 // The first call operand is the chain and the second is the target address.
10795 Ops.push_back(Chain);
10796 Ops.push_back(Callee);
10797
10798 // Add argument registers to the end of the list so that they are
10799 // known live into the call.
10800 for (auto &Reg : RegsToPass)
10801 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
10802
10803 if (!IsTailCall) {
10804 // Add a register mask operand representing the call-preserved registers.
10805 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
10806 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
10807 assert(Mask && "Missing call preserved mask for calling convention");
10808 Ops.push_back(DAG.getRegisterMask(Mask));
10809 }
10810
10811 // Glue the call to the argument copies, if any.
10812 if (Glue.getNode())
10813 Ops.push_back(Glue);
10814
10815 // Emit the call.
10816 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
10817 unsigned Op;
10818 switch (DAG.getTarget().getCodeModel()) {
10819 default:
10820 report_fatal_error("Unsupported code model");
10821 case CodeModel::Small:
10822 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
10823 break;
10824 case CodeModel::Medium:
10825 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
10826 break;
10827 case CodeModel::Large:
10828 assert(Subtarget.is64Bit() && "Large code model requires LA64");
10829 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
10830 break;
10831 }
10832
10833 if (IsTailCall) {
10835 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
10836 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
10837 return Ret;
10838 }
10839
10840 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
10841 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
10842 Glue = Chain.getValue(1);
10843
10844 // Mark the end of the call, which is glued to the call itself.
10845 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
10846 Glue = Chain.getValue(1);
10847
10848 // Assign locations to each value returned by this call.
10850 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
10851 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
10852
10853 // Copy all of the result registers out of their specified physreg.
10854 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
10855 auto &VA = RVLocs[i];
10856 // Copy the value out.
10857 SDValue RetValue =
10858 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
10859 // Glue the RetValue to the end of the call sequence.
10860 Chain = RetValue.getValue(1);
10861 Glue = RetValue.getValue(2);
10862
10863 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10864 assert(VA.needsCustom());
10865 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
10866 MVT::i32, Glue);
10867 Chain = RetValue2.getValue(1);
10868 Glue = RetValue2.getValue(2);
10869 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
10870 RetValue, RetValue2);
10871 } else
10872 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
10873
10874 InVals.push_back(RetValue);
10875 }
10876
10877 return Chain;
10878}
10879
10881 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
10882 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
10883 const Type *RetTy) const {
10885 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
10886
10887 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10888 LoongArchABI::ABI ABI =
10889 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10890 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
10891 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
10892 return false;
10893 }
10894 return true;
10895}
10896
10898 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10900 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
10901 SelectionDAG &DAG) const {
10902 // Stores the assignment of the return value to a location.
10904
10905 // Info about the registers and stack slot.
10906 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
10907 *DAG.getContext());
10908
10909 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
10910 nullptr, CC_LoongArch);
10911 if (CallConv == CallingConv::GHC && !RVLocs.empty())
10912 report_fatal_error("GHC functions return void only");
10913 SDValue Glue;
10914 SmallVector<SDValue, 4> RetOps(1, Chain);
10915
10916 // Copy the result values into the output registers.
10917 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
10918 SDValue Val = OutVals[OutIdx];
10919 CCValAssign &VA = RVLocs[i];
10920 assert(VA.isRegLoc() && "Can only return in registers!");
10921
10922 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10923 // Handle returning f64 on LA32D with a soft float ABI.
10924 assert(VA.isRegLoc() && "Expected return via registers");
10925 assert(VA.needsCustom());
10926 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10927 DAG.getVTList(MVT::i32, MVT::i32), Val);
10928 SDValue Lo = SplitF64.getValue(0);
10929 SDValue Hi = SplitF64.getValue(1);
10930 Register RegLo = VA.getLocReg();
10931 Register RegHi = RVLocs[++i].getLocReg();
10932
10933 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
10934 Glue = Chain.getValue(1);
10935 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
10936 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
10937 Glue = Chain.getValue(1);
10938 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
10939 } else {
10940 // Handle a 'normal' return.
10941 Val = convertValVTToLocVT(DAG, Val, VA, DL);
10942 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
10943
10944 // Guarantee that all emitted copies are stuck together.
10945 Glue = Chain.getValue(1);
10946 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
10947 }
10948 }
10949
10950 RetOps[0] = Chain; // Update chain.
10951
10952 // Add the glue node if we have it.
10953 if (Glue.getNode())
10954 RetOps.push_back(Glue);
10955
10956 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
10957}
10958
10959// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
10960// Note: The following prefixes are excluded:
10961// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
10962// as they can be represented using [x]vrepli.[whb]
10964 const APInt &SplatValue, const unsigned SplatBitSize) const {
10965 uint64_t RequiredImm = 0;
10966 uint64_t V = SplatValue.getZExtValue();
10967 if (SplatBitSize == 16 && !(V & 0x00FF)) {
10968 // 4'b0101
10969 RequiredImm = (0b10101 << 8) | (V >> 8);
10970 return {true, RequiredImm};
10971 } else if (SplatBitSize == 32) {
10972 // 4'b0001
10973 if (!(V & 0xFFFF00FF)) {
10974 RequiredImm = (0b10001 << 8) | (V >> 8);
10975 return {true, RequiredImm};
10976 }
10977 // 4'b0010
10978 if (!(V & 0xFF00FFFF)) {
10979 RequiredImm = (0b10010 << 8) | (V >> 16);
10980 return {true, RequiredImm};
10981 }
10982 // 4'b0011
10983 if (!(V & 0x00FFFFFF)) {
10984 RequiredImm = (0b10011 << 8) | (V >> 24);
10985 return {true, RequiredImm};
10986 }
10987 // 4'b0110
10988 if ((V & 0xFFFF00FF) == 0xFF) {
10989 RequiredImm = (0b10110 << 8) | (V >> 8);
10990 return {true, RequiredImm};
10991 }
10992 // 4'b0111
10993 if ((V & 0xFF00FFFF) == 0xFFFF) {
10994 RequiredImm = (0b10111 << 8) | (V >> 16);
10995 return {true, RequiredImm};
10996 }
10997 // 4'b1010
10998 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
10999 RequiredImm =
11000 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11001 return {true, RequiredImm};
11002 }
11003 } else if (SplatBitSize == 64) {
11004 // 4'b1011
11005 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
11006 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
11007 RequiredImm =
11008 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11009 return {true, RequiredImm};
11010 }
11011 // 4'b1100
11012 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
11013 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
11014 RequiredImm =
11015 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
11016 return {true, RequiredImm};
11017 }
11018 // 4'b1001
11019 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
11020 uint8_t res = 0;
11021 for (int i = 0; i < 8; ++i) {
11022 uint8_t byte = x & 0xFF;
11023 if (byte == 0 || byte == 0xFF)
11024 res |= ((byte & 1) << i);
11025 else
11026 return {false, 0};
11027 x >>= 8;
11028 }
11029 return {true, res};
11030 };
11031 auto [IsSame, Suffix] = sameBitsPreByte(V);
11032 if (IsSame) {
11033 RequiredImm = (0b11001 << 8) | Suffix;
11034 return {true, RequiredImm};
11035 }
11036 }
11037 return {false, RequiredImm};
11038}
11039
11041 EVT VT) const {
11042 if (!Subtarget.hasExtLSX())
11043 return false;
11044
11045 if (VT == MVT::f32) {
11046 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
11047 return (masked == 0x3e000000 || masked == 0x40000000);
11048 }
11049
11050 if (VT == MVT::f64) {
11051 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
11052 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
11053 }
11054
11055 return false;
11056}
11057
11058// Only form FP_TO_SINT_SAT from clamp/NaN-guard idioms when it will be lowered
11059// to a single [X]VFTINTRZ/FTINTRZ, otherwise the generic expansion is worse
11060// than the original sequence.
11061bool LoongArchTargetLowering::shouldConvertFpToSat(unsigned Op, EVT FPVT,
11062 EVT VT) const {
11063 if (!isOperationLegalOrCustom(Op, VT))
11064 return false;
11065 if (VT.isVector())
11066 return FPVT.getScalarSizeInBits() == VT.getScalarSizeInBits();
11067 if (FPVT == MVT::f32)
11068 return VT.getSizeInBits() == 32 || Subtarget.hasBasicD();
11069 return FPVT == MVT::f64 && Subtarget.hasBasicD();
11070}
11071
11073LoongArchTargetLowering::getFPImmAction(const APFloat &Imm, EVT VT,
11074 bool ForCodeSize) const {
11075 // TODO: Maybe need more checks here after vector extension is supported.
11076 if (VT == MVT::f32 && !Subtarget.hasBasicF())
11078 if (VT == MVT::f64 && !Subtarget.hasBasicD())
11080 if (Imm.isZero() || isFPImmVLDILegal(Imm, VT))
11081 return FPImmAction::Legal;
11082
11083 // Immediates the size of a GPR are built from their bits. Others are built in
11084 // lowerConstantFP.
11085 if (VT.getSizeInBits() == Subtarget.getGRLen() && isFPImmCheapInGPR(Imm, VT))
11086 return FPImmAction::Bitcast;
11088}
11089
11091 EVT VT) const {
11092 // Count the instructions to generate the bits and move them to a float
11093 // register.
11094 auto Seq =
11095 LoongArchMatInt::generateInstSeq(Imm.bitcastToAPInt().getSExtValue());
11096 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
11097 return InsNum <= MaterializeFPImmInsNum || Imm.isOne();
11098}
11099
11101 return true;
11102}
11103
11105 return true;
11106}
11107
11108bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
11109 const Instruction *I) const {
11110 if (!Subtarget.is64Bit())
11111 return isa<LoadInst>(I) || isa<StoreInst>(I);
11112
11113 if (isa<LoadInst>(I))
11114 return true;
11115
11116 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
11117 // require fences beacuse we can use amswap_db.[w/d].
11118 Type *Ty = I->getOperand(0)->getType();
11119 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
11120 unsigned Size = Ty->getIntegerBitWidth();
11121 return (Size == 8 || Size == 16);
11122 }
11123
11124 return false;
11125}
11126
11128 LLVMContext &Context,
11129 EVT VT) const {
11130 if (!VT.isVector())
11131 return getPointerTy(DL);
11133}
11134
11136 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
11137 // Do not merge to float value size (128 or 256 bits) if no implicit
11138 // float attribute is set.
11139 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
11140 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
11141 if (NoFloat)
11142 return MemVT.getSizeInBits() <= MaxIntSize;
11143
11144 // Make sure we don't merge greater than our maximum supported vector width.
11145 if (Subtarget.hasExtLASX())
11146 MaxIntSize = 256;
11147 else if (Subtarget.hasExtLSX())
11148 MaxIntSize = 128;
11149
11150 return MemVT.getSizeInBits() <= MaxIntSize;
11151}
11152
11154 EVT VT = Y.getValueType();
11155
11156 if (VT.isVector())
11157 return Subtarget.hasExtLSX() && VT.isInteger();
11158
11159 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
11160}
11161
11164 MachineFunction &MF, unsigned Intrinsic) const {
11165 switch (Intrinsic) {
11166 default:
11167 return;
11168 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
11169 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
11170 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
11171 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
11172 IntrinsicInfo Info;
11174 Info.memVT = MVT::i32;
11175 Info.ptrVal = I.getArgOperand(0);
11176 Info.offset = 0;
11177 Info.align = Align(4);
11180 Infos.push_back(Info);
11181 return;
11182 // TODO: Add more Intrinsics later.
11183 }
11184 }
11185}
11186
11187// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
11188// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
11189// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
11190// regression, we need to implement it manually.
11193
11195 Op == AtomicRMWInst::And) &&
11196 "Unable to expand");
11197 unsigned MinWordSize = 4;
11198
11199 IRBuilder<> Builder(AI);
11200 LLVMContext &Ctx = Builder.getContext();
11201 const DataLayout &DL = AI->getDataLayout();
11202 Type *ValueType = AI->getType();
11203 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
11204
11205 Value *Addr = AI->getPointerOperand();
11206 PointerType *PtrTy = cast<PointerType>(Addr->getType());
11207 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
11208
11209 Value *AlignedAddr = Builder.CreateIntrinsic(
11210 Intrinsic::ptrmask, {PtrTy, IntTy},
11211 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
11212 "AlignedAddr");
11213
11214 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
11215 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
11216 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
11217 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
11218 Value *Mask = Builder.CreateShl(
11219 ConstantInt::get(WordType,
11220 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
11221 ShiftAmt, "Mask");
11222 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
11223 Value *ValOperand_Shifted =
11224 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
11225 ShiftAmt, "ValOperand_Shifted");
11226 Value *NewOperand;
11227 if (Op == AtomicRMWInst::And)
11228 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
11229 else
11230 NewOperand = ValOperand_Shifted;
11231
11232 AtomicRMWInst *NewAI =
11233 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
11234 AI->getOrdering(), AI->getSyncScopeID());
11235
11236 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
11237 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
11238 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
11239 AI->replaceAllUsesWith(FinalOldResult);
11240 AI->eraseFromParent();
11241}
11242
11245 const AtomicRMWInst *AI) const {
11246 // TODO: Add more AtomicRMWInst that needs to be extended.
11247
11248 // Since floating-point operation requires a non-trivial set of data
11249 // operations, use CmpXChg to expand.
11250 if (AI->isFloatingPointOperation() ||
11256
11257 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
11260 AI->getOperation() == AtomicRMWInst::Sub)) {
11262 }
11263
11264 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
11265 if (Subtarget.hasLAMCAS()) {
11266 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
11270 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
11272 }
11273
11274 if (Size == 8 || Size == 16)
11277}
11278
11279static Intrinsic::ID
11281 AtomicRMWInst::BinOp BinOp) {
11282 if (GRLen == 64) {
11283 switch (BinOp) {
11284 default:
11285 llvm_unreachable("Unexpected AtomicRMW BinOp");
11287 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
11288 case AtomicRMWInst::Add:
11289 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
11290 case AtomicRMWInst::Sub:
11291 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
11293 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
11295 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
11297 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
11298 case AtomicRMWInst::Max:
11299 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
11300 case AtomicRMWInst::Min:
11301 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11302 // TODO: support other AtomicRMWInst.
11303 }
11304 }
11305
11306 if (GRLen == 32) {
11307 switch (BinOp) {
11308 default:
11309 llvm_unreachable("Unexpected AtomicRMW BinOp");
11311 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11312 case AtomicRMWInst::Add:
11313 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11314 case AtomicRMWInst::Sub:
11315 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11317 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11319 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11321 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11322 case AtomicRMWInst::Max:
11323 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11324 case AtomicRMWInst::Min:
11325 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11326 // TODO: support other AtomicRMWInst.
11327 }
11328 }
11329
11330 llvm_unreachable("Unexpected GRLen\n");
11331}
11332
11335 const AtomicCmpXchgInst *CI) const {
11336
11337 if (Subtarget.hasLAMCAS())
11339
11341 if (Size == 8 || Size == 16)
11344}
11345
11347 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11348 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11349 unsigned GRLen = Subtarget.getGRLen();
11350 AtomicOrdering FailOrd = CI->getFailureOrdering();
11351 Value *FailureOrdering =
11352 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11353 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11354 if (GRLen == 64) {
11355 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11356 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11357 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11358 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11359 }
11360 Type *Tys[] = {AlignedAddr->getType()};
11361 Value *Result = Builder.CreateIntrinsic(
11362 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11363 if (GRLen == 64)
11364 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11365 return Result;
11366}
11367
11369 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11370 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11371 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11372 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11373 // mask, as this produces better code than the LL/SC loop emitted by
11374 // int_loongarch_masked_atomicrmw_xchg.
11375 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11378 if (CVal->isZero())
11379 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11380 Builder.CreateNot(Mask, "Inv_Mask"),
11381 AI->getAlign(), Ord);
11382 if (CVal->isMinusOne())
11383 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11384 AI->getAlign(), Ord);
11385 }
11386
11387 unsigned GRLen = Subtarget.getGRLen();
11388 Value *Ordering =
11389 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11390 Type *Tys[] = {AlignedAddr->getType()};
11392 AI->getModule(),
11394
11395 if (GRLen == 64) {
11396 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11397 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11398 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11399 }
11400
11401 Value *Result;
11402
11403 // Must pass the shift amount needed to sign extend the loaded value prior
11404 // to performing a signed comparison for min/max. ShiftAmt is the number of
11405 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11406 // is the number of bits to left+right shift the value in order to
11407 // sign-extend.
11408 if (AI->getOperation() == AtomicRMWInst::Min ||
11410 const DataLayout &DL = AI->getDataLayout();
11411 unsigned ValWidth =
11412 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11413 Value *SextShamt =
11414 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11415 Result = Builder.CreateCall(LlwOpScwLoop,
11416 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11417 } else {
11418 Result =
11419 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11420 }
11421
11422 if (GRLen == 64)
11423 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11424 return Result;
11425}
11426
11428 const MachineFunction &MF, EVT VT) const {
11429 VT = VT.getScalarType();
11430
11431 if (!VT.isSimple())
11432 return false;
11433
11434 switch (VT.getSimpleVT().SimpleTy) {
11435 case MVT::f32:
11436 case MVT::f64:
11437 return true;
11438 default:
11439 break;
11440 }
11441
11442 return false;
11443}
11444
11446 ExceptionHandling EH, const Constant *PersonalityFn) const {
11447 return LoongArch::R4;
11448}
11449
11451 ExceptionHandling EH, const Constant *PersonalityFn) const {
11452 return LoongArch::R5;
11453}
11454
11455//===----------------------------------------------------------------------===//
11456// Target Optimization Hooks
11457//===----------------------------------------------------------------------===//
11458
11461 // Feature FRECIPE instructions relative accuracy is 2^-14.
11462 // IEEE float has 23 digits and double has 52 digits.
11463 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11464 return RefinementSteps;
11465}
11466
11467static bool
11469 assert(Subtarget.hasFrecipe() &&
11470 "Reciprocal estimate queried on unsupported target");
11471
11472 if (!VT.isSimple())
11473 return false;
11474
11475 switch (VT.getSimpleVT().SimpleTy) {
11476 case MVT::f32:
11477 // f32 is the base type for reciprocal estimate instructions.
11478 return true;
11479
11480 case MVT::f64:
11481 return Subtarget.hasBasicD();
11482
11483 case MVT::v4f32:
11484 case MVT::v2f64:
11485 return Subtarget.hasExtLSX();
11486
11487 case MVT::v8f32:
11488 case MVT::v4f64:
11489 return Subtarget.hasExtLASX();
11490
11491 default:
11492 return false;
11493 }
11494}
11495
11497 SelectionDAG &DAG, int Enabled,
11498 int &RefinementSteps,
11499 bool &UseOneConstNR,
11500 bool Reciprocal) const {
11502 "Enabled should never be Disabled here");
11503
11504 if (!Subtarget.hasFrecipe())
11505 return SDValue();
11506
11507 SDLoc DL(Operand);
11508 EVT VT = Operand.getValueType();
11509
11510 // Check supported types.
11511 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11512 return SDValue();
11513
11514 // Handle refinement steps.
11515 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11516 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11517
11518 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
11519 UseOneConstNR = false;
11520 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
11521
11522 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
11523 // are needed (which rely on the reciprocal form), return the raw reciprocal
11524 // estimate.
11525 if (Reciprocal || RefinementSteps > 0)
11526 return Rsqrt;
11527
11528 // Otherwise, return sqrt(x) by multiplying with the operand.
11529 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
11530}
11531
11533 SelectionDAG &DAG,
11534 int Enabled,
11535 int &RefinementSteps) const {
11537 "Enabled should never be Disabled here");
11538
11539 if (!Subtarget.hasFrecipe())
11540 return SDValue();
11541
11542 SDLoc DL(Operand);
11543 EVT VT = Operand.getValueType();
11544
11545 // Check supported types.
11546 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11547 return SDValue();
11548
11549 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11550 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11551
11552 // FRECIPE computes 1.0 / x.
11553 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
11554}
11555
11556//===----------------------------------------------------------------------===//
11557// LoongArch Inline Assembly Support
11558//===----------------------------------------------------------------------===//
11559
11561LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
11562 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
11563 //
11564 // 'f': A floating-point register (if available).
11565 // 'k': A memory operand whose address is formed by a base register and
11566 // (optionally scaled) index register.
11567 // 'l': A signed 16-bit constant.
11568 // 'm': A memory operand whose address is formed by a base register and
11569 // offset that is suitable for use in instructions with the same
11570 // addressing mode as st.w and ld.w.
11571 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
11572 // instruction)
11573 // 'I': A signed 12-bit constant (for arithmetic instructions).
11574 // 'J': Integer zero.
11575 // 'K': An unsigned 12-bit constant (for logic instructions).
11576 // "ZB": An address that is held in a general-purpose register. The offset is
11577 // zero.
11578 // "ZC": A memory operand whose address is formed by a base register and
11579 // offset that is suitable for use in instructions with the same
11580 // addressing mode as ll.w and sc.w.
11581 if (Constraint.size() == 1) {
11582 switch (Constraint[0]) {
11583 default:
11584 break;
11585 case 'f':
11586 case 'q':
11587 return C_RegisterClass;
11588 case 'l':
11589 case 'I':
11590 case 'J':
11591 case 'K':
11592 return C_Immediate;
11593 case 'k':
11594 return C_Memory;
11595 }
11596 }
11597
11598 if (Constraint == "ZC" || Constraint == "ZB")
11599 return C_Memory;
11600
11601 // 'm' is handled here.
11602 return TargetLowering::getConstraintType(Constraint);
11603}
11604
11605InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
11606 StringRef ConstraintCode) const {
11607 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
11611 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
11612}
11613
11614std::pair<unsigned, const TargetRegisterClass *>
11615LoongArchTargetLowering::getRegForInlineAsmConstraint(
11616 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
11617 // First, see if this is a constraint that directly corresponds to a LoongArch
11618 // register class.
11619 if (Constraint.size() == 1) {
11620 switch (Constraint[0]) {
11621 case 'r':
11622 // TODO: Support fixed vectors up to GRLen?
11623 if (VT.isVector())
11624 break;
11625 return std::make_pair(0U, &LoongArch::GPRRegClass);
11626 case 'q':
11627 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
11628 case 'f':
11629 if (Subtarget.hasBasicF() && VT == MVT::f32)
11630 return std::make_pair(0U, &LoongArch::FPR32RegClass);
11631 if (Subtarget.hasBasicD() && VT == MVT::f64)
11632 return std::make_pair(0U, &LoongArch::FPR64RegClass);
11633 if (Subtarget.hasExtLSX() &&
11634 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
11635 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11636 if (Subtarget.hasExtLSX() && VT == MVT::i128)
11637 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11638 if (Subtarget.hasExtLASX() &&
11639 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
11640 return std::make_pair(0U, &LoongArch::LASX256RegClass);
11641 break;
11642 default:
11643 break;
11644 }
11645 }
11646
11647 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
11648 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
11649 // constraints while the official register name is prefixed with a '$'. So we
11650 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
11651 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
11652 // case insensitive, so no need to convert the constraint to upper case here.
11653 //
11654 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
11655 // decode the usage of register name aliases into their official names. And
11656 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
11657 // official register names.
11658 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
11659 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
11660 bool IsFP = Constraint[2] == 'f';
11661 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
11662 std::pair<unsigned, const TargetRegisterClass *> R;
11664 TRI, join_items("", Temp.first, Temp.second), VT);
11665 // Match those names to the widest floating point register type available.
11666 if (IsFP) {
11667 unsigned RegNo = R.first;
11668 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
11669 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
11670 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
11671 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
11672 }
11673 }
11674 }
11675 return R;
11676 }
11677
11678 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
11679}
11680
11681void LoongArchTargetLowering::LowerAsmOperandForConstraint(
11682 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
11683 SelectionDAG &DAG) const {
11684 // Currently only support length 1 constraints.
11685 if (Constraint.size() == 1) {
11686 switch (Constraint[0]) {
11687 case 'l':
11688 // Validate & create a 16-bit signed immediate operand.
11689 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11690 uint64_t CVal = C->getSExtValue();
11691 if (isInt<16>(CVal))
11692 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11693 Subtarget.getGRLenVT()));
11694 }
11695 return;
11696 case 'I':
11697 // Validate & create a 12-bit signed immediate operand.
11698 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11699 uint64_t CVal = C->getSExtValue();
11700 if (isInt<12>(CVal))
11701 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11702 Subtarget.getGRLenVT()));
11703 }
11704 return;
11705 case 'J':
11706 // Validate & create an integer zero operand.
11707 if (auto *C = dyn_cast<ConstantSDNode>(Op))
11708 if (C->getZExtValue() == 0)
11709 Ops.push_back(
11710 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
11711 return;
11712 case 'K':
11713 // Validate & create a 12-bit unsigned immediate operand.
11714 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11715 uint64_t CVal = C->getZExtValue();
11716 if (isUInt<12>(CVal))
11717 Ops.push_back(
11718 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
11719 }
11720 return;
11721 default:
11722 break;
11723 }
11724 }
11726}
11727
11728#define GET_REGISTER_MATCHER
11729#include "LoongArchGenAsmMatcher.inc"
11730
11733 const MachineFunction &MF) const {
11734 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
11735 std::string NewRegName = Name.second.str();
11736 Register Reg = MatchRegisterAltName(NewRegName);
11737 if (!Reg)
11738 Reg = MatchRegisterName(NewRegName);
11739 if (!Reg)
11740 return Reg;
11741 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
11742 if (!ReservedRegs.test(Reg))
11743 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
11744 StringRef(RegName) + "\"."));
11745 return Reg;
11746}
11747
11749 EVT VT, SDValue C) const {
11750 // TODO: Support vectors.
11751 if (!VT.isScalarInteger())
11752 return false;
11753
11754 // Omit the optimization if the data size exceeds GRLen.
11755 if (VT.getSizeInBits() > Subtarget.getGRLen())
11756 return false;
11757
11758 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
11759 const APInt &Imm = ConstNode->getAPIntValue();
11760 // Break MUL into (SLLI + ADD/SUB) or ALSL.
11761 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
11762 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
11763 return true;
11764 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
11765 if (ConstNode->hasOneUse() &&
11766 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
11767 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
11768 return true;
11769 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
11770 // in which the immediate has two set bits. Or Break (MUL x, imm)
11771 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
11772 // equals to (1 << s0) - (1 << s1).
11773 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
11774 unsigned Shifts = Imm.countr_zero();
11775 // Reject immediates which can be composed via a single LUI.
11776 if (Shifts >= 12)
11777 return false;
11778 // Reject multiplications can be optimized to
11779 // (SLLI (ALSL x, x, 1/2/3/4), s).
11780 APInt ImmPop = Imm.ashr(Shifts);
11781 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
11782 return false;
11783 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
11784 // since it needs one more instruction than other 3 cases.
11785 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
11786 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
11787 (ImmSmall - Imm).isPowerOf2())
11788 return true;
11789 }
11790 }
11791
11792 return false;
11793}
11794
11796 const AddrMode &AM,
11797 Type *Ty, unsigned AS,
11798 Instruction *I) const {
11799 // LoongArch has four basic addressing modes:
11800 // 1. reg
11801 // 2. reg + 12-bit signed offset
11802 // 3. reg + 14-bit signed offset left-shifted by 2
11803 // 4. reg1 + reg2
11804 // TODO: Add more checks after support vector extension.
11805
11806 // No global is ever allowed as a base.
11807 if (AM.BaseGV)
11808 return false;
11809
11810 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
11811 // with `UAL` feature.
11812 if (!isInt<12>(AM.BaseOffs) &&
11813 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
11814 return false;
11815
11816 switch (AM.Scale) {
11817 case 0:
11818 // "r+i" or just "i", depending on HasBaseReg.
11819 break;
11820 case 1:
11821 // "r+r+i" is not allowed.
11822 if (AM.HasBaseReg && AM.BaseOffs)
11823 return false;
11824 // Otherwise we have "r+r" or "r+i".
11825 break;
11826 case 2:
11827 // "2*r+r" or "2*r+i" is not allowed.
11828 if (AM.HasBaseReg || AM.BaseOffs)
11829 return false;
11830 // Allow "2*r" as "r+r".
11831 break;
11832 default:
11833 return false;
11834 }
11835
11836 return true;
11837}
11838
11840 return isInt<12>(Imm);
11841}
11842
11844 return isInt<12>(Imm);
11845}
11846
11848 // Zexts are free if they can be combined with a load.
11849 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
11850 // poorly with type legalization of compares preferring sext.
11851 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
11852 EVT MemVT = LD->getMemoryVT();
11853 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
11854 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
11855 LD->getExtensionType() == ISD::ZEXTLOAD))
11856 return true;
11857 }
11858
11859 return TargetLowering::isZExtFree(Val, VT2);
11860}
11861
11863 EVT DstVT) const {
11864 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
11865}
11866
11868 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
11869}
11870
11872 // TODO: Support vectors.
11873 if (Y.getValueType().isVector())
11874 return false;
11875
11876 return !isa<ConstantSDNode>(Y);
11877}
11878
11880 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
11881 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
11882}
11883
11885 Type *Ty, bool IsSigned) const {
11886 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
11887 return true;
11888
11889 return IsSigned;
11890}
11891
11893 // Return false to suppress the unnecessary extensions if the LibCall
11894 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
11895 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
11896 Type.getSizeInBits() < Subtarget.getGRLen()))
11897 return false;
11898 return true;
11899}
11900
11901// memcpy, and other memory intrinsics, typically tries to use wider load/store
11902// if the source/dest is aligned and the copy size is large enough. We therefore
11903// want to align such objects passed to memory intrinsics.
11905 unsigned &MinSize,
11906 Align &PrefAlign) const {
11907 if (!isa<MemIntrinsic>(CI))
11908 return false;
11909
11910 if (Subtarget.is64Bit()) {
11911 MinSize = 8;
11912 PrefAlign = Align(8);
11913 } else {
11914 MinSize = 4;
11915 PrefAlign = Align(4);
11916 }
11917
11918 return true;
11919}
11920
11923 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
11924 VT.getVectorElementType() != MVT::i1)
11925 return TypeWidenVector;
11926
11928}
11929
11930bool LoongArchTargetLowering::splitValueIntoRegisterParts(
11931 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
11932 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
11933 bool IsABIRegCopy = CC.has_value();
11934 EVT ValueVT = Val.getValueType();
11935
11936 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11937 PartVT == MVT::f32) {
11938 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
11939 // nan, and cast to f32.
11940 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
11941 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
11942 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
11943 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
11944 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
11945 Parts[0] = Val;
11946 return true;
11947 }
11948
11949 return false;
11950}
11951
11952SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
11953 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
11954 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
11955 bool IsABIRegCopy = CC.has_value();
11956
11957 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11958 PartVT == MVT::f32) {
11959 SDValue Val = Parts[0];
11960
11961 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
11962 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
11963 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
11964 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
11965 return Val;
11966 }
11967
11968 return SDValue();
11969}
11970
11971MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
11973 EVT VT) const {
11974 // Use f32 to pass f16.
11975 if (VT == MVT::f16 && Subtarget.hasBasicF())
11976 return MVT::f32;
11977
11979}
11980
11981unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
11983 // Use f32 to pass f16.
11984 if (VT == MVT::f16 && Subtarget.hasBasicF())
11985 return 1;
11986
11988}
11989
11991 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
11992 const SelectionDAG &DAG, unsigned Depth) const {
11993 unsigned Opc = Op.getOpcode();
11994 Known.resetAll();
11995 switch (Opc) {
11996 default:
11997 break;
11998 case LoongArchISD::VANYNONZERO:
11999 case LoongArchISD::VALLZERO:
12000 case LoongArchISD::VALL_ZERO:
12001 case LoongArchISD::VANY_ZERO:
12002 case LoongArchISD::VALL_NONZERO:
12003 case LoongArchISD::VANY_NONZERO: {
12004 // MOVCF2GR zero-extend the i1 cond to GPR.
12005 Known.Zero.setBitsFrom(1);
12006 break;
12007 }
12008 case LoongArchISD::VPICK_ZEXT_ELT: {
12009 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
12010 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
12011 unsigned VTBits = VT.getScalarSizeInBits();
12012 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
12013 Known.Zero.setBitsFrom(VTBits);
12014 break;
12015 }
12016 case LoongArchISD::BSTRINS: {
12017 // BSTRINS X, Y, msb, lsb: replace X[msb:lsb] with Y[msb-lsb:0].
12018 unsigned Msb = Op.getConstantOperandVal(2);
12019 unsigned Lsb = Op.getConstantOperandVal(3);
12020 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12021 KnownBits Known2 = DAG.computeKnownBits(Op.getOperand(1), Depth + 1);
12022 Known.insertBits(Known2.trunc(Msb - Lsb + 1), Lsb);
12023 break;
12024 }
12025 case LoongArchISD::BSTRPICK: {
12026 // BSTRPICK X, msb, lsb: zero-extend X[msb:lsb].
12027 unsigned BitWidth = Known.getBitWidth();
12028 unsigned Msb = Op.getConstantOperandVal(1);
12029 unsigned Lsb = Op.getConstantOperandVal(2);
12030 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12031 Known = Known.extractBits(Msb - Lsb + 1, Lsb).zext(BitWidth);
12032 break;
12033 }
12034 }
12035}
12036
12038 SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
12039 unsigned Depth) const {
12040 switch (Op.getOpcode()) {
12041 default:
12042 break;
12043 case LoongArchISD::BSTRINS: {
12044 unsigned BitWidth = Op.getScalarValueSizeInBits();
12045 unsigned Msb = Op.getConstantOperandVal(2);
12046 unsigned Lsb = Op.getConstantOperandVal(3);
12047 // The bits above msb come from X.
12048 if (Msb != BitWidth - 1) {
12049 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1);
12050 return std::min(Tmp, BitWidth - 1 - Msb);
12051 }
12052 // The high bits come from Y shifted left by lsb.
12053 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(1), Depth + 1);
12054 return Tmp > Lsb ? Tmp - Lsb : 1;
12055 }
12056 }
12057 return 1;
12058}
12059
12061 SDValue Op, const APInt &OriginalDemandedBits,
12062 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
12063 unsigned Depth) const {
12064 EVT VT = Op.getValueType();
12065 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
12066 unsigned Opc = Op.getOpcode();
12067 switch (Opc) {
12068 default:
12069 break;
12070 case LoongArchISD::CRC_W_B_W:
12071 case LoongArchISD::CRC_W_H_W:
12072 case LoongArchISD::CRCC_W_B_W:
12073 case LoongArchISD::CRCC_W_H_W: {
12074 KnownBits KnownSrc;
12075 APInt DemandedSrcBits =
12076 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
12077 Opc == LoongArchISD::CRCC_W_B_W)
12078 ? 8
12079 : 16);
12080 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
12081 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
12082 }
12083 case LoongArchISD::VMSKLTZ:
12084 case LoongArchISD::XVMSKLTZ: {
12085 SDValue Src = Op.getOperand(0);
12086 MVT SrcVT = Src.getSimpleValueType();
12087 unsigned SrcBits = SrcVT.getScalarSizeInBits();
12088 unsigned NumElts = SrcVT.getVectorNumElements();
12089
12090 // If we don't need the sign bits at all just return zero.
12091 if (OriginalDemandedBits.countr_zero() >= NumElts)
12092 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
12093
12094 // Only demand the vector elements of the sign bits we need.
12095 APInt KnownUndef, KnownZero;
12096 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
12097 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
12098 TLO, Depth + 1))
12099 return true;
12100
12101 Known.Zero = KnownZero.zext(BitWidth);
12102 Known.Zero.setHighBits(BitWidth - NumElts);
12103
12104 // [X]VMSKLTZ only uses the MSB from each vector element.
12105 KnownBits KnownSrc;
12106 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
12107 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
12108 Depth + 1))
12109 return true;
12110
12111 if (KnownSrc.One[SrcBits - 1])
12112 Known.One.setLowBits(NumElts);
12113 else if (KnownSrc.Zero[SrcBits - 1])
12114 Known.Zero.setLowBits(NumElts);
12115
12116 // Attempt to avoid multi-use ops if we don't need anything from it.
12118 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
12119 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
12120 return false;
12121 }
12122 }
12123
12125 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
12126}
12127
12129 unsigned Opc = VecOp.getOpcode();
12130
12131 // Assume target opcodes can't be scalarized.
12132 // TODO - do we have any exceptions?
12133 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
12134 return false;
12135
12136 // If the vector op is not supported, try to convert to scalar.
12137 EVT VecVT = VecOp.getValueType();
12139 return true;
12140
12141 // If the vector op is supported, but the scalar op is not, the transform may
12142 // not be worthwhile.
12143 EVT ScalarVT = VecVT.getScalarType();
12144 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
12145}
12146
12149 unsigned Index) const {
12152
12153 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
12154 if (Index == 0)
12157}
12158
12160 unsigned Index) const {
12161 EVT EltVT = VT.getScalarType();
12162
12163 // Extract a scalar FP value from index 0 of a vector is free.
12164 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
12165}
12166
12168 const MachineFunction &MF) const {
12169
12170 // If the function specifically requests inline stack probes, emit them.
12171 if (MF.getFunction().hasFnAttribute("probe-stack"))
12172 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
12173 "inline-asm";
12174
12175 return false;
12176}
12177
12179 Align StackAlign) const {
12180 // The default stack probe size is 4096 if the function has no
12181 // stack-probe-size attribute.
12182 const Function &Fn = MF.getFunction();
12183 unsigned StackProbeSize =
12184 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
12185 // Round down to the stack alignment.
12186 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
12187 return StackProbeSize ? StackProbeSize : StackAlign.value();
12188}
12189
12190SDValue
12191LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
12192 SelectionDAG &DAG) const {
12194 if (!hasInlineStackProbe(MF))
12195 return SDValue();
12196
12197 const MVT GRLenVT = Subtarget.getGRLenVT();
12198 // Get the inputs.
12199 SDValue Chain = Op.getOperand(0);
12200 SDValue Size = Op.getOperand(1);
12201
12202 const MaybeAlign Align =
12203 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
12204 const SDLoc dl(Op);
12205 const EVT VT = Op.getValueType();
12206
12207 // Construct the new SP value in a GPR.
12208 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
12209 Chain = SP.getValue(1);
12210 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
12211 if (Align)
12212 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
12213 DAG.getSignedConstant(-Align->value(), dl, VT));
12214
12215 // Set the real SP to the new value with a probing loop.
12216 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
12217 return DAG.getMergeValues({SP, Chain}, dl);
12218}
12219
12222 MachineBasicBlock *MBB) const {
12223 MachineFunction &MF = *MBB->getParent();
12224 MachineBasicBlock::iterator MBBI = MI.getIterator();
12225 DebugLoc DL = MBB->findDebugLoc(MBBI);
12226 const Register TargetReg = MI.getOperand(0).getReg();
12227
12228 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
12229 const bool IsLA64 = Subtarget.is64Bit();
12230 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
12231 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
12232 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
12233
12234 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
12235 MachineBasicBlock *const LoopTestMBB =
12236 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12237 MF.insert(MBBInsertPoint, LoopTestMBB);
12238 MachineBasicBlock *const ExitMBB =
12239 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12240 MF.insert(MBBInsertPoint, ExitMBB);
12241 const Register SPReg = LoongArch::R3;
12242 const Register ScratchReg =
12243 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
12244
12245 // ScratchReg = ProbeSize
12246 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
12247
12248 // LoopTest:
12249 // sub.{w/d} $sp, $sp, ScratchReg
12250 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12251 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
12252 .addReg(SPReg)
12253 .addReg(ScratchReg);
12254
12255 // st.{w/d} $zero, $sp, 0
12256 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12257 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
12258 .addReg(LoongArch::R0)
12259 .addReg(SPReg)
12260 .addImm(0);
12261
12262 // bltu TargetReg, $sp, LoopTest
12263 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
12264 .addReg(TargetReg)
12265 .addReg(SPReg)
12266 .addMBB(LoopTestMBB);
12267
12268 // move $sp, TargetReg
12269 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
12270 .addReg(TargetReg)
12271 .addReg(LoongArch::R0);
12272
12273 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
12275
12276 LoopTestMBB->addSuccessor(ExitMBB);
12277 LoopTestMBB->addSuccessor(LoopTestMBB);
12278 MBB->addSuccessor(LoopTestMBB);
12279
12280 MI.eraseFromParent();
12281 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
12282 return ExitMBB->begin()->getParent();
12283}
static MCRegister MatchRegisterName(StringRef Name)
static SDValue performSHLCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
If the operand is a bitwise AND with a constant RHS, and the shift has a constant RHS and is the only...
static bool checkValueWidth(SDValue V, unsigned width, ISD::LoadExtType &ExtType)
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
unsigned NumParts
return SDValue()
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSELECT_CCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
const AArch64Subtarget & Subtarget
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
uint64_t uint64_t
uint64_t Imm
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static MCRegister MatchRegisterAltName(StringRef Name)
Maps from the set of all alternative registernames to a register number.
Function Alias Analysis Results
static uint64_t getConstant(const Value *IndexValue)
static SDValue getTargetNode(ConstantPoolSDNode *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG, unsigned Flags)
bpf unwind BPF Unwind Lower
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static MachineBasicBlock * emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode)
static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static bool isSigned(unsigned Opcode)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RegName(no)
static SDValue performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
const MCPhysReg ArgFPR32s[]
static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 128-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
const MCPhysReg ArgVRs[]
static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKEV (if possible).
static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
static SDValue unpackF64OnLA32DSoftABI(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const CCValAssign &HiVA, const SDLoc &DL)
static bool fitsRegularPattern(typename SmallVectorImpl< ValType >::const_iterator Begin, unsigned CheckStride, typename SmallVectorImpl< ValType >::const_iterator End, ValType ExpectedIndex, unsigned ExpectedIndexStride)
Determine whether a range fits a regular pattern of values.
static SDValue lowerVECTOR_SHUFFLE_IsReverse(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE whose result is the reversed source vector.
static SDValue PromoteMaskArithmetic(SDValue N, const SDLoc &DL, EVT VT, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned Depth)
static SDValue performUINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performHorizWideningCombine(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static std::pair< SDValue, EVT > stripSignExtendInReg(SDValue V)
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static SDValue lowerVECTOR_SHUFFLE_XVPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF.
static int getEstimateRefinementSteps(EVT VT, const LoongArchSubtarget &Subtarget)
static bool isSupportedReciprocalEstimateType(EVT VT, const LoongArchSubtarget &Subtarget)
static void emitErrorAndReplaceIntrinsicResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, StringRef ErrorMsg, bool WithChain=true)
static SDValue lowerVECTOR_SHUFFLEAsByteRotate(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE as byte rotate (if possible).
static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVINSVE0(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
static SDValue performMOVFR2GR_SCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVH (if possible).
static SDValue performDemandedBitsCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
static std::tuple< unsigned, SDValue, EVT > matchBinOpWithSharedOperand(SDValue BinV, SDValue X)
static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static SDValue performSPLIT_PAIR_F64Combine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performBITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static MachineBasicBlock * emitSplitPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG)
static SDValue performSETCC_BITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
@ NoMaterializeFPImm
@ MaterializeFPImm2Ins
@ MaterializeFPImm5Ins
@ MaterializeFPImm6Ins
@ MaterializeFPImm3Ins
@ MaterializeFPImm4Ins
static SDValue performEXTENDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
static bool buildVPERMIInfo(ArrayRef< int > Mask, SDValue V1, SDValue V2, SmallVectorImpl< SDValue > &SrcVec, unsigned &MaskImm)
static std::optional< bool > matchSetCC(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue Val)
static SDValue combineAndNotIntoVANDN(SDNode *N, const SDLoc &DL, SelectionDAG &DAG)
Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
static SDValue lowerBUILD_VECTORAsBroadCastLoad(BuildVectorSDNode *BVOp, const SDLoc &DL, SelectionDAG &DAG)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG)
static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size, unsigned Depth)
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
static SDValue lowerVECTOR_SHUFFLEAsShift(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as shift (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, Type *OrigTy, CCState &State)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVECTOR_SHUFFLE_VEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG)
static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKEV (if possible).
static MachineBasicBlock * emitPseudoVMSKCOND(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performVANDNCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
Do target-specific dag combines on LoongArchISD::VANDN nodes.
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVPERMIQ(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
static cl::opt< MaterializeFPImm > MaterializeFPImmInsNum("loongarch-materialize-float-imm", cl::Hidden, cl::desc("Maximum number of instructions used (including code sequence " "to generate the value and moving the value to FPR) when " "materializing floating-point immediates (default = 3)"), cl::init(MaterializeFPImm3Ins), cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"), clEnumValN(MaterializeFPImm2Ins, "2", "Materialize FP immediate within 2 instructions"), clEnumValN(MaterializeFPImm3Ins, "3", "Materialize FP immediate within 3 instructions"), clEnumValN(MaterializeFPImm4Ins, "4", "Materialize FP immediate within 4 instructions"), clEnumValN(MaterializeFPImm5Ins, "5", "Materialize FP immediate within 5 instructions"), clEnumValN(MaterializeFPImm6Ins, "6", "Materialize FP immediate within 6 instructions " "(behaves same as 5 on loongarch64)")))
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
const MCPhysReg ArgXRs[]
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
static unsigned getLoongArchWOpcode(unsigned Opcode)
const MCPhysReg ArgFPR64s[]
static MachineBasicBlock * emitPseudoCTPOP(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performMOVGR2FR_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKOD (if possible).
static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL)
static SDValue isNOT(SDValue V, SelectionDAG &DAG)
static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 256-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
const MCPhysReg PreserveNoneArgGPRs[]
static void fillVector(ArrayRef< SDValue > Ops, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, SDValue &Vector, EVT ResTy)
static SDValue fillSubVectorFromBuildVector(BuildVectorSDNode *Node, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, EVT ResTy, unsigned first)
static bool isSelectPseudo(MachineInstr &MI)
static SDValue foldVMskZeroTest(SDValue LHS, SDValue RHS, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue foldBinOpIntoSelectIfProfitable(SDNode *BO, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
const MCPhysReg ArgGPRs[]
static SDValue lowerVECTOR_SHUFFLE_XVPERM(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERM (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVL (if possible).
static SDValue performFP_TO_INTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, unsigned ExtOpc=ISD::ANY_EXTEND)
static void replaceVecCondBranchResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
#define ASRT_LE_GT_CASE(NAME)
static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex)
static SDValue performBR_CCCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static void computeZeroableShuffleElements(ArrayRef< int > Mask, SDValue V1, SDValue V2, APInt &KnownUndef, APInt &KnownZero)
Compute whether each element of a shuffle is zeroable.
static SDValue combineFP_ROUND(SDValue N, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue performCONCAT_VECTORSCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue widenShuffleMask(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
static bool canonicalizeShuffleVectorByLane(const SDLoc &DL, MutableArrayRef< int > Mask, MVT VT, SDValue &V1, SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Shuffle vectors by lane to generate more optimized instructions.
static SDValue lowerVECTOR_SHUFFLE_XVILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVH (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVSHUF (if possible).
static void replaceCMP_XCHG_128Results(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG)
static SDValue lowerVectorPickVE2GR(SDNode *N, SelectionDAG &DAG, unsigned ResOp)
static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue matchHalfOf128BitLanes(SDValue N, bool isLow)
#define IOCSRRD_CASE(NAME, NODE)
static int matchShuffleAsByteRotate(MVT VT, SDValue &V1, SDValue &V2, ArrayRef< int > Mask)
Attempts to match vector shuffle as byte rotation.
static SDValue lowerVECTOR_SHUFFLE_XVREPLVE0(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode, unsigned ScalarSizeInBits, ArrayRef< int > Mask, int MaskOffset, const APInt &Zeroable)
Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI instruction.
static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVL (if possible).
static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG)
static MachineBasicBlock * emitBuildPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
static void replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
#define CSR_CASE(ID)
static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode, unsigned BlockBits)
static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKOD (if possible).
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS, ISD::CondCode &CC, SelectionDAG &DAG)
static Register allocateArgGPR(CCState &State)
static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT, ArrayRef< int > Mask, SmallVectorImpl< int > &RepeatedMask)
Test whether a shuffle mask is equivalent within each sub-lane.
static SDValue convertRMEncoding(SelectionDAG &DAG, const SDLoc &DL, MVT GRLenVT, SDValue RMValue)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO)
static constexpr MCPhysReg SPReg
MachineBasicBlock * Folded
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
MachineInstr *& Lo
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue, bool AllowSymbol=false)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool isSequentialOrUndefInRange(ArrayRef< int > Mask, unsigned Pos, unsigned Size, int Low, int Step=1)
Return true if every element in Mask, beginning from position Pos and ending in Pos + Size,...
Value * RHS
Value * LHS
bool isZero() const
Definition APFloat.h:1579
APInt bitcastToAPInt() const
Definition APFloat.h:1475
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1350
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:367
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1659
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:431
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1261
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
Definition APInt.h:282
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition Argument.h:50
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
An instruction that atomically checks whether a specified value is in a memory location,...
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ UDecWrap
Decrement one until a minimum value or zero.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
bool isFloatingPointOperation() const
BinOp getOperation() const
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool test(unsigned Idx) const
Returns true if bit Idx is set.
Definition BitVector.h:482
size_type count() const
Returns the number of bits which are set.
Definition BitVector.h:181
A "pseudo-class" with methods for operating on BUILD_VECTORs.
CCState - This class holds information needed while lowering arguments and return values.
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
LLVM_ABI void AnalyzeCallOperands(const SmallVectorImpl< ISD::OutputArg > &Outs, CCAssignFn Fn)
AnalyzeCallOperands - Analyze the outgoing arguments to a call, incorporating info about the passed v...
uint64_t getStackSize() const
Returns the size of the currently allocated portion of the stack.
LLVM_ABI void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
CCValAssign - Represent assignment of one arg/retval to a location.
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP, bool IsCustom=false)
static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP)
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool needsCustom() const
int64_t getLocMemOffset() const
unsigned getValNo() const
static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
const APFloat & getValueAPF() const
This is the shared class of boolean and integer constants.
Definition Constants.h:87
bool isMinusOne() const
This function will return true iff every bit in this constant is set to true.
Definition Constants.h:231
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition Constants.h:219
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
Definition DataLayout.h:501
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
A debug info location.
Definition DebugLoc.h:126
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
iterator_range< arg_iterator > args()
Definition Function.h:877
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:766
uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const
For a string attribute Kind, parse attribute as an integer.
Definition Function.cpp:778
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Argument * getArg(unsigned i) const
Definition Function.h:871
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
bool isDSOLocal() const
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2949
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
LLVM_ABI 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
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
void setIncomingIndirectArg(unsigned ArgIndex, Register Reg)
Register getIncomingIndirectArg(unsigned ArgIndex) const
bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override
Return true if result of the specified node is used by a return node only.
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override
This method will be invoked for all target nodes and for any target-independent nodes that the target...
Register getExceptionPointerRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps, bool &UseOneConstNR, bool Reciprocal) const override
Hooks for building estimates in place of slower divisions and square roots.
unsigned ComputeNumSignBitsForTargetNode(SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
This method can be implemented by targets that want to expose additional information about sign bits ...
bool isLegalICmpImmediate(int64_t Imm) const override
Return true if the specified immediate is legal icmp immediate, that is the target has icmp instructi...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
bool isFPImmCheapInGPR(const APFloat &Imm, EVT VT) const
Returns true if building Imm in a GPR and moving it to a float register is cheaper than loading it fr...
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< bool, uint64_t > isImmVLDILegalForMode1(const APInt &SplatValue, const unsigned SplatBitSize) const
Check if a constant splat can be generated using [x]vldi, where imm[12] is 1.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this function.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
Register getExceptionSelectorRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
bool isExtractVecEltCheap(EVT VT, unsigned Index) const override
Return true if extraction of a scalar element from the given vector type at the given index is cheap.
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override
Return true if sign-extension from FromTy to ToTy is cheaper than zero-extension.
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const override
Determine if the target supports unaligned memory accesses.
bool isCheapToSpeculateCtlz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic ctlz.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
bool shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, Align &PrefAlign) const override
Return true if the pointer arguments to CI should be aligned by aligning the object whose address is ...
Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override
Perform a masked atomicrmw using a target-specific intrinsic.
bool isZExtFree(SDValue Val, EVT VT2) const override
Return true if zero-extending the specific node Val to type VT2 is free (either because it's implicit...
void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
Determine which of the bits specified in Mask are known to be either zero or one and return them in t...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, unsigned Index) const override
Return the cost of extracting a subvector of type ResVT from a vector of type SrcVT,...
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
bool isLegalAddImmediate(int64_t Imm) const override
Return true if the specified immediate is legal add immediate, that is the target has add instruction...
bool isCheapToSpeculateCttz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic cttz.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
MachineBasicBlock * emitDynamicProbedAlloc(MachineInstr &MI, MachineBasicBlock *MBB) const
bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override
Returns true if arguments should be sign-extended in lib calls.
bool shouldScalarizeBinop(SDValue VecOp) const override
Try to convert an extract element of a vector binary operation into an extract element followed by a ...
bool isFPImmVLDILegal(const APFloat &Imm, EVT VT) const
bool shouldExtendTypeInLibCall(EVT Type) const override
Returns true if arguments should be extended in lib calls.
Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override
Return the register ID of the name passed in.
bool hasAndNot(SDValue Y) const override
Return true if the target has a bitwise and-not operation: X = ~A & B This can be used to simplify se...
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override
Return true if folding a constant offset with the given GlobalAddress is legal.
unsigned getStackProbeSize(const MachineFunction &MF, Align StackAlign) const
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const override
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
void emitExpandAtomicRMW(AtomicRMWInst *AI) const override
Perform a atomicrmw expansion using a target-specific way.
ISD::NodeType getExtendForAtomicCmpSwapArg() const override
Returns how the platform's atomic compare and swap expects its comparison value to be extended (ZERO_...
LoongArchTargetLowering(const TargetMachine &TM, const LoongArchSubtarget &STI)
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
bool hasAndNotCompare(SDValue Y) const override
Return true if the target should transform: (X & Y) == Y ---> (~X & Y) == 0 (X & Y) !...
SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps) const override
Return a reciprocal estimate value for the input operand.
bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const override
Returns if it's reasonable to merge stores to MemVT size.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context, const Type *RetTy) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
bool mayBeEmittedAsTailCall(const CallInst *CI) const override
Return true if the target may be able emit the call instruction as a tail call.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
bool hasFeature(unsigned Feature) const
Machine Value Type.
static MVT getFloatingPointVT(unsigned BitWidth)
bool is128BitVector() const
Return true if this is a 128-bit vector type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
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.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool is256BitVector() const
Return true if this is a 256-bit vector type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
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)
MVT getDoubleNumVectorElementsVT() const
MVT getHalfNumVectorElementsVT() const
Return a VT for a vector type with the same element type but half the number of elements.
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
MVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
void push_back(MachineInstr *MI)
void setCallFrameSize(unsigned N)
Set the call frame size on entry to this basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
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 '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
LLVM_ABI void collectDebugValues(SmallVectorImpl< MachineInstr * > &DbgValues)
Scan instructions immediately following MI and collect any matching DBG_VALUEs.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Align getAlign() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const MachinePointerInfo & getPointerInfo() const
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
Class to represent pointers.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
LLVM_ABI bool isOnlyUserOf(const SDNode *N) const
Return true if this node is the only use of N.
size_t use_size() const
Return the number of uses of this node.
MVT getSimpleValueType(unsigned ResNo) const
Return the type of a specified result as a simple type.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
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
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
ISD::CondCode getOperandCondCode(unsigned i) const
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
MVT getSimpleValueType() const
Return the simple ValueType of the referenced return value.
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue FoldSetCC(EVT VT, SDValue N1, SDValue N2, ISD::CondCode Cond, const SDLoc &dl, SDNodeFlags Flags={})
Constant fold a setcc to true or false.
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget=false, bool IsOpaque=false)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getFreeze(SDValue V)
Return a freeze using the SDLoc of the value operand.
bool isSafeToSpeculativelyExecute(unsigned Opcode) const
Some opcodes may create immediate undefined behavior when used with some values (integer division-by-...
SDValue getExtractSubvector(const SDLoc &DL, EVT VT, SDValue Vec, unsigned Idx)
Return the VT typed sub-vector of Vec at Idx.
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
LLVM_ABI SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
SDValue getInsertSubvector(const SDLoc &DL, SDValue Vec, SDValue SubVec, unsigned Idx)
Insert SubVec at the Idx element of Vec.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
LLVM_ABI SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align DstAlign, Align SrcAlign, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
const TargetLowering & getTargetLoweringInfo() const
static constexpr unsigned MaxRecursionDepth
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI bool isSplatValue(SDValue V, const APInt &DemandedElts, APInt &UndefElts, unsigned Depth=0) const
Test whether V has a splatted value for all the demanded elements.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
LLVM_ABI SDValue getNegative(SDValue Val, const SDLoc &DL, EVT VT)
Create negative operation as (SUB 0, Val).
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
LLVM_ABI SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT VT)
Return the expression required to zero extend the Op value assuming it was the smaller SrcTy value.
const DataLayout & getDataLayout() const
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
SDValue getSignedTargetConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI void ReplaceAllUsesWith(SDValue From, SDValue To)
Modify anything using 'From' to use 'To' instead.
LLVM_ABI SDValue getCommutedVectorShuffle(const ShuffleVectorSDNode &SV)
Returns an ISD::VECTOR_SHUFFLE node semantically equivalent to the shuffle node in input but with swa...
LLVM_ABI SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
LLVM_ABI std::pair< SDValue, SDValue > SplitVector(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the vector with EXTRACT_SUBVECTOR using the provided VTs and return the low/high part.
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
SDValue getCALLSEQ_START(SDValue Chain, uint64_t InSize, uint64_t OutSize, const SDLoc &DL)
Return a new CALLSEQ_START node, that starts new call frame, in which InSize bytes are set up inside ...
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Loads are not normal binary operators: their result type is not determined by their operands,...
LLVM_ABI SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDValue > Ops, SDNodeFlags Flags=SDNodeFlags())
LLVM_ABI SDValue getExternalSymbol(const char *Sym, EVT VT)
const TargetMachine & getTarget() const
LLVM_ABI SDValue WidenVector(const SDValue &N, const SDLoc &DL)
Widen the vector up to the next power of two using INSERT_SUBVECTOR.
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI unsigned ComputeNumSignBits(SDValue Op, unsigned Depth=0) const
Return the number of times the sign bit of the register is replicated into the other bits.
SDValue getTargetBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue getVectorIdxConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI void ReplaceAllUsesOfValueWith(SDValue From, SDValue To)
Replace any uses of From with To, leaving uses of other values produced by From.getNode() alone.
MachineFunction & getMachineFunction() const
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
LLVM_ABI SDValue getRegisterMask(const uint32_t *RegMask)
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVM_ABI SDValue getCondCode(ISD::CondCode Cond)
LLVM_ABI bool MaskedValueIsZero(SDValue Op, const APInt &Mask, unsigned Depth=0) const
Return true if 'Op & Mask' is known to be zero.
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
LLVM_ABI SDValue CreateStackTemporary(TypeSize Bytes, Align Alignment)
Create a stack temporary based on the size in bytes and the alignment.
SDValue getTargetConstantPool(const Constant *C, EVT VT, MaybeAlign Align=std::nullopt, int Offset=0, unsigned TargetFlags=0)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
SDValue getSplat(EVT VT, const SDLoc &DL, SDValue Op)
Returns a node representing a splat of one value into all lanes of the provided vector type.
LLVM_ABI std::pair< SDValue, SDValue > SplitScalar(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the scalar node with EXTRACT_ELEMENT using the provided VTs and return the low/high part.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
static LLVM_ABI bool isZeroEltSplatMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask chooses all elements with the same value as the first element of exa...
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
ArrayRef< int > getMask() const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:176
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
void reserve(size_type N)
typename SuperClass::const_iterator const_iterator
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:31
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
TargetInstrInfo - Interface to description of machine instruction set.
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...
MachineBasicBlock * emitPatchPoint(MachineInstr &MI, MachineBasicBlock *MBB) const
Replace/modify any TargetFrameIndex operands with a targte-dependent sequence of memory operands that...
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
virtual unsigned getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain targets require unusual breakdowns of certain types.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain combinations of ABIs, Targets and features require that types are legal for some operations a...
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
void setMaxBytesForAlignment(unsigned MaxBytes)
void setPrefLoopAlignment(Align Alignment)
Set the target's preferred loop alignment.
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 setMinFunctionAlignment(Align Alignment)
Set the target's minimum function alignment.
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.
virtual EVT getTypeToTransformTo(LLVMContext &Context, EVT VT) const
For types supported by the target, this is an identity function.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
ExtractSubvectorCost
Enum that specifies how expensive lowering an EXTRACT_SUBVECTOR is.
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 setPrefFunctionAlignment(Align Alignment)
Set the target's preferred function alignment.
bool isOperationLegal(unsigned Op, EVT VT) const
Return true if the specified operation is legal on this target.
FPImmAction
How the legalizer should materialize a floating-point immediate.
@ ConstantPool
Load the immediate from the constant pool.
@ Legal
The target can instruction select the immediate natively.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
bool isOperationLegalOrCustom(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...
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
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...
LegalizeTypeAction getTypeAction(LLVMContext &Context, EVT VT) const
Return how we should legalize values of this type, either it is already legal (return 'Legal') or we ...
std::vector< ArgListEntry > ArgListTy
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...
bool SimplifyDemandedVectorElts(SDValue Op, const APInt &DemandedEltMask, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Vector Op.
virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const
SDValue SimplifyMultipleUseDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth=0) const
More limited version of SimplifyDemandedBits that can be used to "lookthrough" ops that don't contrib...
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
std::pair< SDValue, SDValue > LowerCallTo(CallLoweringInfo &CLI) const
This function lowers an abstract call to a function into an actual call.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Op.
virtual bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0) const
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
TargetLowering(const TargetLowering &)=delete
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::LibcallImpl LibcallImpl, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
Primary interface to the complete machine description for the target machine.
bool useTLSDESC() const
Returns true if this target uses TLS Descriptors.
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
bool shouldAssumeDSOLocal(const GlobalValue *GV) const
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
This class is used to represent EVT's, which are used to parameterize some operations.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:548
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
Definition CallingConv.h:50
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ PreserveNone
Used for runtime calls that preserves none general registers.
Definition CallingConv.h:90
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI bool isConstantSplatVectorAllOnes(const SDNode *N, bool BuildVectorOnly=false)
Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where all of the elements are ~0 ...
bool isNON_EXTLoad(const SDNode *N)
Returns true if the specified node is a non-extending load.
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition ISDOpcodes.h:43
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:845
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
@ STRICT_FSETCC
STRICT_FSETCC/STRICT_FSETCCS - Constrained versions of SETCC, used for floating-point operands only.
Definition ISDOpcodes.h:516
@ DELETED_NODE
DELETED_NODE - This is an illegal value that is used to catch errors.
Definition ISDOpcodes.h:47
@ POISON
POISON - A poison node.
Definition ISDOpcodes.h:238
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:277
@ INSERT_SUBVECTOR
INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector with VECTOR2 inserted into VECTOR1.
Definition ISDOpcodes.h:605
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:805
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:879
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:523
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ GlobalAddress
Definition ISDOpcodes.h:90
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:906
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:589
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:420
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:765
@ MEMBARRIER
MEMBARRIER - Compiler barrier only; generate a no-op.
@ ATOMIC_FENCE
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition ISDOpcodes.h:936
@ FP16_TO_FP
FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions and truncation for half-preci...
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:256
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:91
@ SET_ROUNDING
Set rounding mode.
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:870
@ AVGCEILS
AVGCEILS/AVGCEILU - Rounding averaging add - Add two integers using an integer of type i[N+2],...
Definition ISDOpcodes.h:725
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:675
@ PREFETCH
PREFETCH - This corresponds to a prefetch intrinsic.
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ BR_CC
BR_CC - Conditional branch.
@ BR_JT
BR_JT - Jumptable branch.
@ FCANONICALIZE
Returns platform specific canonical encoding of a floating point number.
Definition ISDOpcodes.h:546
@ IS_FPCLASS
Performs a check of floating point class property, defined by IEEE-754.
Definition ISDOpcodes.h:553
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:377
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:822
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:235
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
@ VECREDUCE_ADD
Integer reductions may have a result type larger than the vector element type.
@ GET_ROUNDING
Returns current rounding mode: -1 Undefined 0 Round to 0 1 Round to nearest, ties to even 2 Round to ...
Definition ISDOpcodes.h:996
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:714
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:787
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:659
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:619
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Same as FMINNUM/FMAXNUM, except that a signaling NaN operand deterministi...
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition ISDOpcodes.h:141
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:581
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:226
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:876
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition ISDOpcodes.h:837
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ FMINNUM
FMINNUM/FMAXNUM - Same semantics as the llvm.minnum/maxnum intrinsics.
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:914
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:745
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:831
@ EH_DWARF_CFA
EH_DWARF_CFA - This node represents the pointer to the DWARF Canonical Frame Address (CFA),...
Definition ISDOpcodes.h:152
@ BF16_TO_FP
BF16_TO_FP, FP_TO_BF16 - These operators are used to perform promotions and truncation for bfloat16.
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:112
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:952
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:757
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ AVGFLOORS
AVGFLOORS/AVGFLOORU - Averaging add - Add two integers using an integer of type i[N+1],...
Definition ISDOpcodes.h:720
@ FREEZE
FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or is evaluated to UNDEF),...
Definition ISDOpcodes.h:243
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:570
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:55
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:985
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:947
@ 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:971
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:882
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
@ BRCOND
BRCOND - Conditional branch.
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition ISDOpcodes.h:859
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition ISDOpcodes.h:64
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:368
@ ABDS
ABDS/ABDU - Absolute difference - Return the absolute difference between two numbers interpreted as s...
Definition ISDOpcodes.h:740
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
bool isExtVecInRegOpcode(unsigned Opcode)
LLVM_ABI bool isConstantSplatVectorAllZeros(const SDNode *N, bool BuildVectorOnly=false)
Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where all of the elements are 0 o...
LLVM_ABI CondCode getSetCCInverse(CondCode Operation, EVT Type)
Return the operation corresponding to !(X op Y), where 'op' is a valid SetCC operation.
bool isBitwiseLogicOp(unsigned Opcode)
Whether this is bitwise logic opcode.
LLVM_ABI bool isFreezeUndef(const SDNode *N)
Return true if the specified node is FREEZE(UNDEF).
LLVM_ABI CondCode getSetCCSwappedOperands(CondCode Operation)
Return the operation corresponding to (Y op X) when given the operation for (X op Y).
LLVM_ABI bool isBuildVectorAllZeros(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are 0 or undef.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
LLVM_ABI bool isBuildVectorAllOnes(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are ~0 or undef.
LLVM_ABI NodeType getVecReduceBaseOpcode(unsigned VecReduceOpcode)
Get underlying scalar opcode for VECREDUCE opcode.
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
bool isNormalLoad(const SDNode *N)
Returns true if the specified node is a non-extending and unindexed load.
bool isIntEqualitySetCC(CondCode Code)
Return true if this is a setcc instruction that performs an equality comparison when used with intege...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
ABI getTargetABI(StringRef ABIName)
InstSeq generateInstSeq(int64_t Val)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:63
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
Definition PtrState.h:41
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
Definition Threading.h:280
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isIntOrFPConstant(SDValue V)
Return true if V is either a integer or FP constant.
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition bit.h:325
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
Definition MathExtras.h:546
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
LLVM_ABI bool widenShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Try to transform a shuffle mask by replacing elements with the scaled index for an equivalent mask of...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Other
Any other memory.
Definition ModRef.h:68
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:183
constexpr unsigned BitWidth
std::string join_items(Sep Separator, Args &&... Items)
Joins the strings in the parameter pack Items, adding Separator between the elements....
ExceptionHandling
Definition CodeGen.h:54
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isOneConstant(SDValue V)
Returns true if V is a constant integer one.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
LLVM_ABI bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Extended Value Type.
Definition ValueTypes.h:35
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition ValueTypes.h:90
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition ValueTypes.h:433
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:160
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:322
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:338
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:170
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:411
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:423
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:354
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:245
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:419
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition ValueTypes.h:55
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:191
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:361
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:250
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:366
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:180
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:374
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:499
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:175
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
KnownBits trunc(unsigned BitWidth) const
Return known bits for a truncation of the value we're tracking.
Definition KnownBits.h:165
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
This structure contains all information that is necessary for lowering calls.
SmallVector< ISD::InputArg, 32 > Ins
SmallVector< ISD::OutputArg, 32 > Outs
LLVM_ABI SDValue CombineTo(SDNode *N, ArrayRef< SDValue > To, bool AddTo=true)
This structure is used to pass arguments to makeLibCall function.
MakeLibCallOptions & setTypeListBeforeSoften(ArrayRef< EVT > OpsVT, EVT RetVT)
A convenience struct that encapsulates a DAG, and two SDValues for returning information from TargetL...