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.
709 V = peekThroughBitcasts(V);
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
770 const LoongArchSubtarget &Subtarget) {
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 // Construct as integer, and move to float register.
956 APInt INTVal = FPVal.bitcastToAPInt();
957
958 // If more than MaterializeFPImmInsNum instructions will be used to
959 // generate the INTVal and move it to float register, fallback to
960 // use floating point load from the constant pool.
962 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
963 if (InsNum > MaterializeFPImmInsNum && !FPVal.isOne())
964 return SDValue();
965
966 switch (VT.getSimpleVT().SimpleTy) {
967 default:
968 llvm_unreachable("Unexpected floating point type!");
969 break;
970 case MVT::f32: {
971 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i32);
972 if (Subtarget.is64Bit())
973 NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, NewVal);
974 return DAG.getNode(Subtarget.is64Bit() ? LoongArchISD::MOVGR2FR_W_LA64
975 : LoongArchISD::MOVGR2FR_W,
976 DL, VT, NewVal);
977 }
978 case MVT::f64: {
979 if (Subtarget.is64Bit()) {
980 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i64);
981 return DAG.getNode(LoongArchISD::MOVGR2FR_D, DL, VT, NewVal);
982 }
983 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
984 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
985 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
986 }
987 }
988
989 return SDValue();
990}
991
992// Ensure SETCC result and operand have the same bit width; isel does not
993// support mismatched widths.
994SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
995 SelectionDAG &DAG) const {
996 SDLoc DL(Op);
997 EVT ResultVT = Op.getValueType();
998 EVT OperandVT = Op.getOperand(0).getValueType();
999
1000 EVT SetCCResultVT =
1001 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
1002
1003 if (ResultVT == SetCCResultVT)
1004 return Op;
1005
1006 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
1007 "SETCC operands must have the same type!");
1008
1009 SDValue SetCCNode =
1010 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
1011 Op.getOperand(1), Op.getOperand(2));
1012
1013 if (ResultVT.bitsGT(SetCCResultVT))
1014 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
1015 else if (ResultVT.bitsLT(SetCCResultVT))
1016 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
1017
1018 return SetCCNode;
1019}
1020
1021// Lower sext_invec using vslti instructions.
1022// For example:
1023// %b = sext <4 x i16> %a to <4 x i32>
1024// can be lowered to:
1025// VSLTI_H vr2, vr1, 0
1026// VILVL.H vr1, vr2, vr1
1027SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1028 SDValue Op, SelectionDAG &DAG) const {
1029 SDLoc DL(Op);
1030 SDValue Src = Op.getOperand(0);
1031 MVT SrcVT = Src.getSimpleValueType();
1032 MVT DstVT = Op.getSimpleValueType();
1033
1034 if (!SrcVT.is128BitVector())
1035 return SDValue();
1036
1037 // lower to VSLTI + VILVL if extend could be done in single step.
1038 if (DstVT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits() == 2) {
1039 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
1040 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Src, Zero,
1041 DAG.getCondCode(ISD::SETLT));
1042 SDValue LoInterleaved =
1043 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Src);
1044
1045 return DAG.getBitcast(DstVT, LoInterleaved);
1046 }
1047
1048 return SDValue();
1049}
1050
1051// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1052SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1053 SelectionDAG &DAG) const {
1054 assert(Subtarget.hasExtLASX());
1055 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1056 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1057 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1058 Op.getOperand(0));
1059}
1060
1061// Lower vecreduce_add using vhaddw instructions.
1062// For Example:
1063// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1064// can be lowered to:
1065// VHADDW_D_W vr0, vr0, vr0
1066// VHADDW_Q_D vr0, vr0, vr0
1067// VPICKVE2GR_D a0, vr0, 0
1068// ADDI_W a0, a0, 0
1069SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1070 SelectionDAG &DAG) const {
1071
1072 SDLoc DL(Op);
1073 MVT OpVT = Op.getSimpleValueType();
1074 SDValue Val = Op.getOperand(0);
1075
1076 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1077 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1078 unsigned ResBits = OpVT.getScalarSizeInBits();
1079
1080 unsigned LegalVecSize = 128;
1081 bool isLASX256Vector =
1082 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1083
1084 // Ensure operand type legal or enable it legal.
1085 while (!isTypeLegal(Val.getSimpleValueType())) {
1086 Val = DAG.WidenVector(Val, DL);
1087 }
1088
1089 // NumEles is designed for iterations count, v4i32 for LSX
1090 // and v8i32 for LASX should have the same count.
1091 if (isLASX256Vector) {
1092 NumEles /= 2;
1093 LegalVecSize = 256;
1094 }
1095
1096 EleBits *= 2;
1097 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1098 EleBits = std::min(EleBits, 64u);
1099 MVT IntTy = MVT::getIntegerVT(EleBits);
1100 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1101 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1102 }
1103
1104 if (isLASX256Vector) {
1105 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1106 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1107 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1108 }
1109
1110 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1111 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1112 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1113}
1114
1115// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1116// For Example:
1117// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1118// can be lowered to:
1119// VBSRL_V vr1, vr0, 8
1120// VMAX_W vr0, vr1, vr0
1121// VBSRL_V vr1, vr0, 4
1122// VMAX_W vr0, vr1, vr0
1123// VPICKVE2GR_W a0, vr0, 0
1124// For 256 bit vector, it is illegal and will be spilt into
1125// two 128 bit vector by default then processed by this.
1126SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1127 SelectionDAG &DAG) const {
1128 SDLoc DL(Op);
1129
1130 MVT OpVT = Op.getSimpleValueType();
1131 SDValue Val = Op.getOperand(0);
1132
1133 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1134 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1135
1136 // Ensure operand type legal or enable it legal.
1137 while (!isTypeLegal(Val.getSimpleValueType())) {
1138 Val = DAG.WidenVector(Val, DL);
1139 }
1140
1141 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1142 MVT VecTy = Val.getSimpleValueType();
1143 MVT GRLenVT = Subtarget.getGRLenVT();
1144
1145 for (int i = NumEles; i > 1; i /= 2) {
1146 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1147 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1148 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1149 }
1150
1151 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1152 DAG.getConstant(0, DL, GRLenVT));
1153}
1154
1155SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1156 SelectionDAG &DAG) const {
1157 unsigned IsData = Op.getConstantOperandVal(4);
1158
1159 // We don't support non-data prefetch.
1160 // Just preserve the chain.
1161 if (!IsData)
1162 return Op.getOperand(0);
1163
1164 return Op;
1165}
1166
1167SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1168 SelectionDAG &DAG) const {
1169 MVT VT = Op.getSimpleValueType();
1170 assert(VT.isVector() && "Unexpected type");
1171
1172 SDLoc DL(Op);
1173 SDValue R = Op.getOperand(0);
1174 SDValue Amt = Op.getOperand(1);
1175 unsigned Opcode = Op.getOpcode();
1176 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1177
1178 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1179 if (V.getOpcode() != ISD::BUILD_VECTOR)
1180 return false;
1181 if (SDValue SplatValue =
1182 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1183 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1184 CstSplatValue = C->getAPIntValue();
1185 return true;
1186 }
1187 }
1188 return false;
1189 };
1190
1191 // Check for constant splat rotation amount.
1192 APInt CstSplatValue;
1193 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1194 bool isROTL = Opcode == ISD::ROTL;
1195
1196 // Check for splat rotate by zero.
1197 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1198 return R;
1199
1200 // LoongArch targets always prefer ISD::ROTR.
1201 if (isROTL) {
1202 SDValue Zero = DAG.getConstant(0, DL, VT);
1203 return DAG.getNode(ISD::ROTR, DL, VT, R,
1204 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1205 }
1206
1207 // Rotate by a immediate.
1208 if (IsCstSplat) {
1209 // ISD::ROTR: Attemp to rotate by a positive immediate.
1210 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1211 if (SDValue Urem =
1212 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1213 return DAG.getNode(Opcode, DL, VT, R, Urem);
1214 }
1215
1216 return Op;
1217}
1218
1219// Return true if Val is equal to (setcc LHS, RHS, CC).
1220// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1221// Otherwise, return std::nullopt.
1222static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1223 ISD::CondCode CC, SDValue Val) {
1224 assert(Val->getOpcode() == ISD::SETCC);
1225 SDValue LHS2 = Val.getOperand(0);
1226 SDValue RHS2 = Val.getOperand(1);
1227 ISD::CondCode CC2 = cast<CondCodeSDNode>(Val.getOperand(2))->get();
1228
1229 if (LHS == LHS2 && RHS == RHS2) {
1230 if (CC == CC2)
1231 return true;
1232 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1233 return false;
1234 } else if (LHS == RHS2 && RHS == LHS2) {
1236 if (CC == CC2)
1237 return true;
1238 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1239 return false;
1240 }
1241
1242 return std::nullopt;
1243}
1244
1246 const LoongArchSubtarget &Subtarget) {
1247 SDValue CondV = N->getOperand(0);
1248 SDValue TrueV = N->getOperand(1);
1249 SDValue FalseV = N->getOperand(2);
1250 MVT VT = N->getSimpleValueType(0);
1251 SDLoc DL(N);
1252
1253 // (select c, -1, y) -> -c | y
1254 if (isAllOnesConstant(TrueV)) {
1255 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1256 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1257 }
1258 // (select c, y, -1) -> (c-1) | y
1259 if (isAllOnesConstant(FalseV)) {
1260 SDValue Neg =
1261 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1262 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1263 }
1264
1265 // (select c, 0, y) -> (c-1) & y
1266 if (isNullConstant(TrueV)) {
1267 SDValue Neg =
1268 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1269 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1270 }
1271 // (select c, y, 0) -> -c & y
1272 if (isNullConstant(FalseV)) {
1273 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1274 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1275 }
1276
1277 // select c, ~x, x --> xor -c, x
1278 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1279 const APInt &TrueVal = TrueV->getAsAPIntVal();
1280 const APInt &FalseVal = FalseV->getAsAPIntVal();
1281 if (~TrueVal == FalseVal) {
1282 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1283 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1284 }
1285 }
1286
1287 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1288 // when both truev and falsev are also setcc.
1289 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1290 FalseV.getOpcode() == ISD::SETCC) {
1291 SDValue LHS = CondV.getOperand(0);
1292 SDValue RHS = CondV.getOperand(1);
1293 ISD::CondCode CC = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1294
1295 // (select x, x, y) -> x | y
1296 // (select !x, x, y) -> x & y
1297 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1298 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1299 DAG.getFreeze(FalseV));
1300 }
1301 // (select x, y, x) -> x & y
1302 // (select !x, y, x) -> x | y
1303 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1304 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1305 DAG.getFreeze(TrueV), FalseV);
1306 }
1307 }
1308
1309 return SDValue();
1310}
1311
1312// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1313// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1314// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1315// being `0` or `-1`. In such cases we can replace `select` with `and`.
1316// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1317// than `c0`?
1318static SDValue
1320 const LoongArchSubtarget &Subtarget) {
1321 unsigned SelOpNo = 0;
1322 SDValue Sel = BO->getOperand(0);
1323 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1324 SelOpNo = 1;
1325 Sel = BO->getOperand(1);
1326 }
1327
1328 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1329 return SDValue();
1330
1331 unsigned ConstSelOpNo = 1;
1332 unsigned OtherSelOpNo = 2;
1333 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1334 ConstSelOpNo = 2;
1335 OtherSelOpNo = 1;
1336 }
1337 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1338 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1339 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1340 return SDValue();
1341
1342 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1343 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1344 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1345 return SDValue();
1346
1347 SDLoc DL(Sel);
1348 EVT VT = BO->getValueType(0);
1349
1350 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1351 if (SelOpNo == 1)
1352 std::swap(NewConstOps[0], NewConstOps[1]);
1353
1354 SDValue NewConstOp =
1355 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1356 if (!NewConstOp)
1357 return SDValue();
1358
1359 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1360 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1361 return SDValue();
1362
1363 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1364 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1365 if (SelOpNo == 1)
1366 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1367 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1368
1369 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1370 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1371 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1372}
1373
1374// Changes the condition code and swaps operands if necessary, so the SetCC
1375// operation matches one of the comparisons supported directly by branches
1376// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1377// compare with 1/-1.
1379 ISD::CondCode &CC, SelectionDAG &DAG) {
1380 // If this is a single bit test that can't be handled by ANDI, shift the
1381 // bit to be tested to the MSB and perform a signed compare with 0.
1382 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1383 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1384 isa<ConstantSDNode>(LHS.getOperand(1))) {
1385 uint64_t Mask = LHS.getConstantOperandVal(1);
1386 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1387 unsigned ShAmt = 0;
1388 if (isPowerOf2_64(Mask)) {
1389 CC = CC == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
1390 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1391 } else {
1392 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1393 }
1394
1395 LHS = LHS.getOperand(0);
1396 if (ShAmt != 0)
1397 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1398 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1399 return;
1400 }
1401 }
1402
1403 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1404 int64_t C = RHSC->getSExtValue();
1405 switch (CC) {
1406 default:
1407 break;
1408 case ISD::SETGT:
1409 // Convert X > -1 to X >= 0.
1410 if (C == -1) {
1411 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1412 CC = ISD::SETGE;
1413 return;
1414 }
1415 break;
1416 case ISD::SETLT:
1417 // Convert X < 1 to 0 >= X.
1418 if (C == 1) {
1419 RHS = LHS;
1420 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1421 CC = ISD::SETGE;
1422 return;
1423 }
1424 break;
1425 }
1426 }
1427
1428 switch (CC) {
1429 default:
1430 break;
1431 case ISD::SETGT:
1432 case ISD::SETLE:
1433 case ISD::SETUGT:
1434 case ISD::SETULE:
1436 std::swap(LHS, RHS);
1437 break;
1438 }
1439}
1440
1441SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1442 SelectionDAG &DAG) const {
1443 SDValue CondV = Op.getOperand(0);
1444 SDValue TrueV = Op.getOperand(1);
1445 SDValue FalseV = Op.getOperand(2);
1446 SDLoc DL(Op);
1447 MVT VT = Op.getSimpleValueType();
1448 MVT GRLenVT = Subtarget.getGRLenVT();
1449
1450 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1451 return V;
1452
1453 if (Op.hasOneUse()) {
1454 unsigned UseOpc = Op->user_begin()->getOpcode();
1455 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1456 SDNode *BinOp = *Op->user_begin();
1457 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1458 DAG, Subtarget)) {
1459 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1460 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1461 // may return a constant node and cause crash in lowerSELECT.
1462 if (NewSel.getOpcode() == ISD::SELECT)
1463 return lowerSELECT(NewSel, DAG);
1464 return NewSel;
1465 }
1466 }
1467 }
1468
1469 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1470 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1471 // (select condv, truev, falsev)
1472 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1473 if (CondV.getOpcode() != ISD::SETCC ||
1474 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1475 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1476 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1477
1478 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1479
1480 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1481 }
1482
1483 // If the CondV is the output of a SETCC node which operates on GRLenVT
1484 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1485 // to take advantage of the integer compare+branch instructions. i.e.: (select
1486 // (setcc lhs, rhs, cc), truev, falsev)
1487 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1488 SDValue LHS = CondV.getOperand(0);
1489 SDValue RHS = CondV.getOperand(1);
1490 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1491
1492 // Special case for a select of 2 constants that have a difference of 1.
1493 // Normally this is done by DAGCombine, but if the select is introduced by
1494 // type legalization or op legalization, we miss it. Restricting to SETLT
1495 // case for now because that is what signed saturating add/sub need.
1496 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1497 // but we would probably want to swap the true/false values if the condition
1498 // is SETGE/SETLE to avoid an XORI.
1499 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1500 CCVal == ISD::SETLT) {
1501 const APInt &TrueVal = TrueV->getAsAPIntVal();
1502 const APInt &FalseVal = FalseV->getAsAPIntVal();
1503 if (TrueVal - 1 == FalseVal)
1504 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1505 if (TrueVal + 1 == FalseVal)
1506 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1507 }
1508
1509 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1510 // 1 < x ? x : 1 -> 0 < x ? x : 1
1511 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1512 RHS == TrueV && LHS == FalseV) {
1513 LHS = DAG.getConstant(0, DL, VT);
1514 // 0 <u x is the same as x != 0.
1515 if (CCVal == ISD::SETULT) {
1516 std::swap(LHS, RHS);
1517 CCVal = ISD::SETNE;
1518 }
1519 }
1520
1521 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1522 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1523 RHS == FalseV) {
1524 RHS = DAG.getConstant(0, DL, VT);
1525 }
1526
1527 SDValue TargetCC = DAG.getCondCode(CCVal);
1528
1529 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1530 // (select (setcc lhs, rhs, CC), constant, falsev)
1531 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1532 std::swap(TrueV, FalseV);
1533 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1534 }
1535
1536 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1537 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1538}
1539
1540SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1541 SelectionDAG &DAG) const {
1542 SDValue CondV = Op.getOperand(1);
1543 SDLoc DL(Op);
1544 MVT GRLenVT = Subtarget.getGRLenVT();
1545
1546 if (CondV.getOpcode() == ISD::SETCC) {
1547 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1548 SDValue LHS = CondV.getOperand(0);
1549 SDValue RHS = CondV.getOperand(1);
1550 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1551
1552 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1553
1554 SDValue TargetCC = DAG.getCondCode(CCVal);
1555 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1556 Op.getOperand(0), LHS, RHS, TargetCC,
1557 Op.getOperand(2));
1558 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1559 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1560 Op.getOperand(0), CondV, Op.getOperand(2));
1561 }
1562 }
1563
1564 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1565 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1566 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1567}
1568
1569SDValue
1570LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1571 SelectionDAG &DAG) const {
1572 SDLoc DL(Op);
1573 MVT OpVT = Op.getSimpleValueType();
1574
1575 SDValue Vector = DAG.getUNDEF(OpVT);
1576 SDValue Val = Op.getOperand(0);
1577 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1578
1579 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1580}
1581
1582SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1583 SelectionDAG &DAG) const {
1584 EVT ResTy = Op->getValueType(0);
1585 SDValue Src = Op->getOperand(0);
1586 SDLoc DL(Op);
1587
1588 // LoongArchISD::BITREV_8B is not supported on LA32.
1589 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1590 return SDValue();
1591
1592 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1593 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1594 unsigned int NewEltNum = NewVT.getVectorNumElements();
1595
1596 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1597
1599 for (unsigned int i = 0; i < NewEltNum; i++) {
1600 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1601 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1602 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1603 ? (unsigned)LoongArchISD::BITREV_8B
1604 : (unsigned)ISD::BITREVERSE;
1605 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1606 }
1607 SDValue Res =
1608 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1609
1610 switch (ResTy.getSimpleVT().SimpleTy) {
1611 default:
1612 return SDValue();
1613 case MVT::v16i8:
1614 case MVT::v32i8:
1615 return Res;
1616 case MVT::v8i16:
1617 case MVT::v16i16:
1618 case MVT::v4i32:
1619 case MVT::v8i32: {
1621 for (unsigned int i = 0; i < NewEltNum; i++)
1622 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1623 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1624 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1625 }
1626 }
1627}
1628
1629// Widen element type to get a new mask value (if possible).
1630// For example:
1631// shufflevector <4 x i32> %a, <4 x i32> %b,
1632// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1633// is equivalent to:
1634// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1635// can be lowered to:
1636// VPACKOD_D vr0, vr0, vr1
1638 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1639 unsigned EltBits = VT.getScalarSizeInBits();
1640
1641 if (EltBits > 32 || EltBits == 1)
1642 return SDValue();
1643
1644 SmallVector<int, 8> NewMask;
1645 if (widenShuffleMaskElts(Mask, NewMask)) {
1646 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1647 : MVT::getIntegerVT(EltBits * 2);
1648 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1649 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1650 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1651 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1652 return DAG.getBitcast(
1653 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1654 }
1655 }
1656
1657 return SDValue();
1658}
1659
1660/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1661/// instruction.
1662// The funciton matches elements from one of the input vector shuffled to the
1663// left or right with zeroable elements 'shifted in'. It handles both the
1664// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1665// lane.
1666// Mostly copied from X86.
1667static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1668 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1669 int MaskOffset, const APInt &Zeroable) {
1670 int Size = Mask.size();
1671 unsigned SizeInBits = Size * ScalarSizeInBits;
1672
1673 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1674 for (int i = 0; i < Size; i += Scale)
1675 for (int j = 0; j < Shift; ++j)
1676 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1677 return false;
1678
1679 return true;
1680 };
1681
1682 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1683 int Step = 1) {
1684 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1685 if (!(Mask[i] == -1 || Mask[i] == Low))
1686 return false;
1687 return true;
1688 };
1689
1690 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1691 for (int i = 0; i != Size; i += Scale) {
1692 unsigned Pos = Left ? i + Shift : i;
1693 unsigned Low = Left ? i : i + Shift;
1694 unsigned Len = Scale - Shift;
1695 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1696 return -1;
1697 }
1698
1699 int ShiftEltBits = ScalarSizeInBits * Scale;
1700 bool ByteShift = ShiftEltBits > 64;
1701 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1702 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1703 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1704
1705 // Normalize the scale for byte shifts to still produce an i64 element
1706 // type.
1707 Scale = ByteShift ? Scale / 2 : Scale;
1708
1709 // We need to round trip through the appropriate type for the shift.
1710 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1711 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1712 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1713 return (int)ShiftAmt;
1714 };
1715
1716 unsigned MaxWidth = 128;
1717 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1718 for (int Shift = 1; Shift != Scale; ++Shift)
1719 for (bool Left : {true, false})
1720 if (CheckZeros(Shift, Scale, Left)) {
1721 int ShiftAmt = MatchShift(Shift, Scale, Left);
1722 if (0 < ShiftAmt)
1723 return ShiftAmt;
1724 }
1725
1726 // no match
1727 return -1;
1728}
1729
1730/// Lower VECTOR_SHUFFLE as shift (if possible).
1731///
1732/// For example:
1733/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1734/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1735/// is lowered to:
1736/// (VBSLL_V $v0, $v0, 4)
1737///
1738/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1739/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1740/// is lowered to:
1741/// (VSLLI_D $v0, $v0, 32)
1743 MVT VT, SDValue V1, SDValue V2,
1744 SelectionDAG &DAG,
1745 const LoongArchSubtarget &Subtarget,
1746 const APInt &Zeroable) {
1747 int Size = Mask.size();
1748 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1749
1750 MVT ShiftVT;
1751 SDValue V = V1;
1752 unsigned Opcode;
1753
1754 // Try to match shuffle against V1 shift.
1755 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1756 Mask, 0, Zeroable);
1757
1758 // If V1 failed, try to match shuffle against V2 shift.
1759 if (ShiftAmt < 0) {
1760 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1761 Mask, Size, Zeroable);
1762 V = V2;
1763 }
1764
1765 if (ShiftAmt < 0)
1766 return SDValue();
1767
1768 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1769 "Illegal integer vector type");
1770 V = DAG.getBitcast(ShiftVT, V);
1771 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1772 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1773 return DAG.getBitcast(VT, V);
1774}
1775
1776/// Determine whether a range fits a regular pattern of values.
1777/// This function accounts for the possibility of jumping over the End iterator.
1778template <typename ValType>
1779static bool
1781 unsigned CheckStride,
1783 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1784 auto &I = Begin;
1785
1786 while (I != End) {
1787 if (*I != -1 && *I != ExpectedIndex)
1788 return false;
1789 ExpectedIndex += ExpectedIndexStride;
1790
1791 // Incrementing past End is undefined behaviour so we must increment one
1792 // step at a time and check for End at each step.
1793 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1794 ; // Empty loop body.
1795 }
1796 return true;
1797}
1798
1799/// Compute whether each element of a shuffle is zeroable.
1800///
1801/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1803 SDValue V2, APInt &KnownUndef,
1804 APInt &KnownZero) {
1805 int Size = Mask.size();
1806 KnownUndef = KnownZero = APInt::getZero(Size);
1807
1809 V2 = peekThroughBitcasts(V2);
1810
1811 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1812 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1813
1814 int VectorSizeInBits = V1.getValueSizeInBits();
1815 int ScalarSizeInBits = VectorSizeInBits / Size;
1816 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1817 (void)ScalarSizeInBits;
1818
1819 for (int i = 0; i < Size; ++i) {
1820 int M = Mask[i];
1821 if (M < 0) {
1822 KnownUndef.setBit(i);
1823 continue;
1824 }
1825 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1826 KnownZero.setBit(i);
1827 continue;
1828 }
1829 }
1830}
1831
1832/// Test whether a shuffle mask is equivalent within each sub-lane.
1833///
1834/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1835/// non-trivial to compute in the face of undef lanes. The representation is
1836/// suitable for use with existing 128-bit shuffles as entries from the second
1837/// vector have been remapped to [LaneSize, 2*LaneSize).
1838static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1839 ArrayRef<int> Mask,
1840 SmallVectorImpl<int> &RepeatedMask) {
1841 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1842 RepeatedMask.assign(LaneSize, -1);
1843 int Size = Mask.size();
1844 for (int i = 0; i < Size; ++i) {
1845 assert(Mask[i] == -1 || Mask[i] >= 0);
1846 if (Mask[i] < 0)
1847 continue;
1848 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1849 // This entry crosses lanes, so there is no way to model this shuffle.
1850 return false;
1851
1852 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1853 // Adjust second vector indices to start at LaneSize instead of Size.
1854 int LocalM =
1855 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1856 if (RepeatedMask[i % LaneSize] < 0)
1857 // This is the first non-undef entry in this slot of a 128-bit lane.
1858 RepeatedMask[i % LaneSize] = LocalM;
1859 else if (RepeatedMask[i % LaneSize] != LocalM)
1860 // Found a mismatch with the repeated mask.
1861 return false;
1862 }
1863 return true;
1864}
1865
1866/// Attempts to match vector shuffle as byte rotation.
1868 ArrayRef<int> Mask) {
1869
1870 SDValue Lo, Hi;
1871 SmallVector<int, 16> RepeatedMask;
1872
1873 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1874 return -1;
1875
1876 int NumElts = RepeatedMask.size();
1877 int Rotation = 0;
1878 int Scale = 16 / NumElts;
1879
1880 for (int i = 0; i < NumElts; ++i) {
1881 int M = RepeatedMask[i];
1882 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1883 "Unexpected mask index.");
1884 if (M < 0)
1885 continue;
1886
1887 // Determine where a rotated vector would have started.
1888 int StartIdx = i - (M % NumElts);
1889 if (StartIdx == 0)
1890 return -1;
1891
1892 // If we found the tail of a vector the rotation must be the missing
1893 // front. If we found the head of a vector, it must be how much of the
1894 // head.
1895 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1896
1897 if (Rotation == 0)
1898 Rotation = CandidateRotation;
1899 else if (Rotation != CandidateRotation)
1900 return -1;
1901
1902 // Compute which value this mask is pointing at.
1903 SDValue MaskV = M < NumElts ? V1 : V2;
1904
1905 // Compute which of the two target values this index should be assigned
1906 // to. This reflects whether the high elements are remaining or the low
1907 // elements are remaining.
1908 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1909
1910 // Either set up this value if we've not encountered it before, or check
1911 // that it remains consistent.
1912 if (!TargetV)
1913 TargetV = MaskV;
1914 else if (TargetV != MaskV)
1915 return -1;
1916 }
1917
1918 // Check that we successfully analyzed the mask, and normalize the results.
1919 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1920 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1921 if (!Lo)
1922 Lo = Hi;
1923 else if (!Hi)
1924 Hi = Lo;
1925
1926 V1 = Lo;
1927 V2 = Hi;
1928
1929 return Rotation * Scale;
1930}
1931
1932/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
1933///
1934/// For example:
1935/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
1936/// <2 x i32> <i32 3, i32 0>
1937/// is lowered to:
1938/// (VBSRL_V $v1, $v1, 8)
1939/// (VBSLL_V $v0, $v0, 8)
1940/// (VOR_V $v0, $V0, $v1)
1941static SDValue
1943 SDValue V1, SDValue V2, SelectionDAG &DAG,
1944 const LoongArchSubtarget &Subtarget) {
1945
1946 SDValue Lo = V1, Hi = V2;
1947 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
1948 if (ByteRotation <= 0)
1949 return SDValue();
1950
1951 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
1952 Lo = DAG.getBitcast(ByteVT, Lo);
1953 Hi = DAG.getBitcast(ByteVT, Hi);
1954
1955 int LoByteShift = 16 - ByteRotation;
1956 int HiByteShift = ByteRotation;
1957 MVT GRLenVT = Subtarget.getGRLenVT();
1958
1959 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
1960 DAG.getConstant(LoByteShift, DL, GRLenVT));
1961 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
1962 DAG.getConstant(HiByteShift, DL, GRLenVT));
1963 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
1964}
1965
1966/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
1967///
1968/// For example:
1969/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1970/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
1971/// %3 = bitcast <4 x i32> %2 to <2 x i64>
1972/// is lowered to:
1973/// (VREPLI $v1, 0)
1974/// (VILVL $v0, $v1, $v0)
1976 ArrayRef<int> Mask, MVT VT,
1977 SDValue V1, SDValue V2,
1978 SelectionDAG &DAG,
1979 const APInt &Zeroable) {
1980 int Bits = VT.getSizeInBits();
1981 int EltBits = VT.getScalarSizeInBits();
1982 int NumElements = VT.getVectorNumElements();
1983
1984 if (Zeroable.isAllOnes())
1985 return DAG.getConstant(0, DL, VT);
1986
1987 // Define a helper function to check a particular ext-scale and lower to it if
1988 // valid.
1989 auto Lower = [&](int Scale) -> SDValue {
1990 SDValue InputV;
1991 bool AnyExt = true;
1992 int Offset = 0;
1993 for (int i = 0; i < NumElements; i++) {
1994 int M = Mask[i];
1995 if (M < 0)
1996 continue;
1997 if (i % Scale != 0) {
1998 // Each of the extended elements need to be zeroable.
1999 if (!Zeroable[i])
2000 return SDValue();
2001
2002 AnyExt = false;
2003 continue;
2004 }
2005
2006 // Each of the base elements needs to be consecutive indices into the
2007 // same input vector.
2008 SDValue V = M < NumElements ? V1 : V2;
2009 M = M % NumElements;
2010 if (!InputV) {
2011 InputV = V;
2012 Offset = M - (i / Scale);
2013
2014 // These offset can't be handled
2015 if (Offset % (NumElements / Scale))
2016 return SDValue();
2017 } else if (InputV != V)
2018 return SDValue();
2019
2020 if (M != (Offset + (i / Scale)))
2021 return SDValue(); // Non-consecutive strided elements.
2022 }
2023
2024 // If we fail to find an input, we have a zero-shuffle which should always
2025 // have already been handled.
2026 if (!InputV)
2027 return SDValue();
2028
2029 do {
2030 unsigned VilVLoHi = LoongArchISD::VILVL;
2031 if (Offset >= (NumElements / 2)) {
2032 VilVLoHi = LoongArchISD::VILVH;
2033 Offset -= (NumElements / 2);
2034 }
2035
2036 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2037 SDValue Ext =
2038 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2039 InputV = DAG.getBitcast(InputVT, InputV);
2040 Ext = DAG.getBitcast(InputVT, Ext);
2041 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2042 Scale /= 2;
2043 EltBits *= 2;
2044 NumElements /= 2;
2045 } while (Scale > 1);
2046 return DAG.getBitcast(VT, InputV);
2047 };
2048
2049 // Each iteration, try extending the elements half as much, but into twice as
2050 // many elements.
2051 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2052 NumExtElements *= 2) {
2053 if (SDValue V = Lower(NumElements / NumExtElements))
2054 return V;
2055 }
2056 return SDValue();
2057}
2058
2059/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2060///
2061/// VREPLVEI performs vector broadcast based on an element specified by an
2062/// integer immediate, with its mask being similar to:
2063/// <x, x, x, ...>
2064/// where x is any valid index.
2065///
2066/// When undef's appear in the mask they are treated as if they were whatever
2067/// value is necessary in order to fit the above form.
2068static SDValue
2070 SDValue V1, SelectionDAG &DAG,
2071 const LoongArchSubtarget &Subtarget) {
2072 int SplatIndex = -1;
2073 for (const auto &M : Mask) {
2074 if (M != -1) {
2075 SplatIndex = M;
2076 break;
2077 }
2078 }
2079
2080 if (SplatIndex == -1)
2081 return DAG.getUNDEF(VT);
2082
2083 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2084 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2085 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2086 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2087 }
2088
2089 return SDValue();
2090}
2091
2092/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2093///
2094/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2095/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2096///
2097/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2098/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2099/// When undef's appear they are treated as if they were whatever value is
2100/// necessary in order to fit the above forms.
2101///
2102/// For example:
2103/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2104/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2105/// i32 7, i32 6, i32 5, i32 4>
2106/// is lowered to:
2107/// (VSHUF4I_H $v0, $v1, 27)
2108/// where the 27 comes from:
2109/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2110static SDValue
2112 SDValue V1, SDValue V2, SelectionDAG &DAG,
2113 const LoongArchSubtarget &Subtarget) {
2114
2115 unsigned SubVecSize = 4;
2116 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2117 SubVecSize = 2;
2118
2119 int SubMask[4] = {-1, -1, -1, -1};
2120 for (unsigned i = 0; i < SubVecSize; ++i) {
2121 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2122 int M = Mask[j];
2123
2124 // Convert from vector index to 4-element subvector index
2125 // If an index refers to an element outside of the subvector then give up
2126 if (M != -1) {
2127 M -= 4 * (j / SubVecSize);
2128 if (M < 0 || M >= 4)
2129 return SDValue();
2130 }
2131
2132 // If the mask has an undef, replace it with the current index.
2133 // Note that it might still be undef if the current index is also undef
2134 if (SubMask[i] == -1)
2135 SubMask[i] = M;
2136 // Check that non-undef values are the same as in the mask. If they
2137 // aren't then give up
2138 else if (M != -1 && M != SubMask[i])
2139 return SDValue();
2140 }
2141 }
2142
2143 // Calculate the immediate. Replace any remaining undefs with zero
2144 int Imm = 0;
2145 for (int i = SubVecSize - 1; i >= 0; --i) {
2146 int M = SubMask[i];
2147
2148 if (M == -1)
2149 M = 0;
2150
2151 Imm <<= 2;
2152 Imm |= M & 0x3;
2153 }
2154
2155 MVT GRLenVT = Subtarget.getGRLenVT();
2156
2157 // Return vshuf4i.d
2158 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2159 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2160 DAG.getConstant(Imm, DL, GRLenVT));
2161
2162 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2163 DAG.getConstant(Imm, DL, GRLenVT));
2164}
2165
2166/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2167///
2168/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2169/// reverse whose mask likes:
2170/// <7, 6, 5, 4, 3, 2, 1, 0>
2171///
2172/// When undef's appear in the mask they are treated as if they were whatever
2173/// value is necessary in order to fit the above forms.
2174static SDValue
2176 SDValue V1, SelectionDAG &DAG,
2177 const LoongArchSubtarget &Subtarget) {
2178 // Only vectors with i8/i16 elements which cannot match other patterns
2179 // directly needs to do this.
2180 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2181 VT != MVT::v16i16)
2182 return SDValue();
2183
2184 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2185 return SDValue();
2186
2187 int WidenNumElts = VT.getVectorNumElements() / 4;
2188 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2189 for (int i = 0; i < WidenNumElts; ++i)
2190 WidenMask[i] = WidenNumElts - 1 - i;
2191
2192 MVT WidenVT = MVT::getVectorVT(
2193 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2194 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2195 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2196 DAG.getUNDEF(WidenVT), WidenMask);
2197
2198 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2199 DAG.getBitcast(VT, WidenRev),
2200 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2201}
2202
2203/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2204///
2205/// VPACKEV interleaves the even elements from each vector.
2206///
2207/// It is possible to lower into VPACKEV when the mask consists of two of the
2208/// following forms interleaved:
2209/// <0, 2, 4, ...>
2210/// <n, n+2, n+4, ...>
2211/// where n is the number of elements in the vector.
2212/// For example:
2213/// <0, 0, 2, 2, 4, 4, ...>
2214/// <0, n, 2, n+2, 4, n+4, ...>
2215///
2216/// When undef's appear in the mask they are treated as if they were whatever
2217/// value is necessary in order to fit the above forms.
2219 MVT VT, SDValue V1, SDValue V2,
2220 SelectionDAG &DAG) {
2221
2222 const auto &Begin = Mask.begin();
2223 const auto &End = Mask.end();
2224 SDValue OriV1 = V1, OriV2 = V2;
2225
2226 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2227 V1 = OriV1;
2228 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2229 V1 = OriV2;
2230 else
2231 return SDValue();
2232
2233 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2234 V2 = OriV1;
2235 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2236 V2 = OriV2;
2237 else
2238 return SDValue();
2239
2240 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2241}
2242
2243/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2244///
2245/// VPACKOD interleaves the odd elements from each vector.
2246///
2247/// It is possible to lower into VPACKOD when the mask consists of two of the
2248/// following forms interleaved:
2249/// <1, 3, 5, ...>
2250/// <n+1, n+3, n+5, ...>
2251/// where n is the number of elements in the vector.
2252/// For example:
2253/// <1, 1, 3, 3, 5, 5, ...>
2254/// <1, n+1, 3, n+3, 5, n+5, ...>
2255///
2256/// When undef's appear in the mask they are treated as if they were whatever
2257/// value is necessary in order to fit the above forms.
2259 MVT VT, SDValue V1, SDValue V2,
2260 SelectionDAG &DAG) {
2261
2262 const auto &Begin = Mask.begin();
2263 const auto &End = Mask.end();
2264 SDValue OriV1 = V1, OriV2 = V2;
2265
2266 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2267 V1 = OriV1;
2268 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2269 V1 = OriV2;
2270 else
2271 return SDValue();
2272
2273 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2274 V2 = OriV1;
2275 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2276 V2 = OriV2;
2277 else
2278 return SDValue();
2279
2280 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2281}
2282
2283/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2284///
2285/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2286/// of each vector.
2287///
2288/// It is possible to lower into VILVH when the mask consists of two of the
2289/// following forms interleaved:
2290/// <x, x+1, x+2, ...>
2291/// <n+x, n+x+1, n+x+2, ...>
2292/// where n is the number of elements in the vector and x is half n.
2293/// For example:
2294/// <x, x, x+1, x+1, x+2, x+2, ...>
2295/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2296///
2297/// When undef's appear in the mask they are treated as if they were whatever
2298/// value is necessary in order to fit the above forms.
2300 MVT VT, SDValue V1, SDValue V2,
2301 SelectionDAG &DAG) {
2302
2303 const auto &Begin = Mask.begin();
2304 const auto &End = Mask.end();
2305 unsigned HalfSize = Mask.size() / 2;
2306 SDValue OriV1 = V1, OriV2 = V2;
2307
2308 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2309 V1 = OriV1;
2310 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2311 V1 = OriV2;
2312 else
2313 return SDValue();
2314
2315 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2316 V2 = OriV1;
2317 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2318 1))
2319 V2 = OriV2;
2320 else
2321 return SDValue();
2322
2323 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2324}
2325
2326/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2327///
2328/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2329/// of each vector.
2330///
2331/// It is possible to lower into VILVL when the mask consists of two of the
2332/// following forms interleaved:
2333/// <0, 1, 2, ...>
2334/// <n, n+1, n+2, ...>
2335/// where n is the number of elements in the vector.
2336/// For example:
2337/// <0, 0, 1, 1, 2, 2, ...>
2338/// <0, n, 1, n+1, 2, n+2, ...>
2339///
2340/// When undef's appear in the mask they are treated as if they were whatever
2341/// value is necessary in order to fit the above forms.
2343 MVT VT, SDValue V1, SDValue V2,
2344 SelectionDAG &DAG) {
2345
2346 const auto &Begin = Mask.begin();
2347 const auto &End = Mask.end();
2348 SDValue OriV1 = V1, OriV2 = V2;
2349
2350 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2351 V1 = OriV1;
2352 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2353 V1 = OriV2;
2354 else
2355 return SDValue();
2356
2357 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2358 V2 = OriV1;
2359 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2360 V2 = OriV2;
2361 else
2362 return SDValue();
2363
2364 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2365}
2366
2367/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2368///
2369/// VPICKEV copies the even elements of each vector into the result vector.
2370///
2371/// It is possible to lower into VPICKEV when the mask consists of two of the
2372/// following forms concatenated:
2373/// <0, 2, 4, ...>
2374/// <n, n+2, n+4, ...>
2375/// where n is the number of elements in the vector.
2376/// For example:
2377/// <0, 2, 4, ..., 0, 2, 4, ...>
2378/// <0, 2, 4, ..., n, n+2, n+4, ...>
2379///
2380/// When undef's appear in the mask they are treated as if they were whatever
2381/// value is necessary in order to fit the above forms.
2383 MVT VT, SDValue V1, SDValue V2,
2384 SelectionDAG &DAG) {
2385
2386 const auto &Begin = Mask.begin();
2387 const auto &Mid = Mask.begin() + Mask.size() / 2;
2388 const auto &End = Mask.end();
2389 SDValue OriV1 = V1, OriV2 = V2;
2390
2391 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2392 V1 = OriV1;
2393 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2394 V1 = OriV2;
2395 else
2396 return SDValue();
2397
2398 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2399 V2 = OriV1;
2400 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2401 V2 = OriV2;
2402
2403 else
2404 return SDValue();
2405
2406 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2407}
2408
2409/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2410///
2411/// VPICKOD copies the odd elements of each vector into the result vector.
2412///
2413/// It is possible to lower into VPICKOD when the mask consists of two of the
2414/// following forms concatenated:
2415/// <1, 3, 5, ...>
2416/// <n+1, n+3, n+5, ...>
2417/// where n is the number of elements in the vector.
2418/// For example:
2419/// <1, 3, 5, ..., 1, 3, 5, ...>
2420/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2421///
2422/// When undef's appear in the mask they are treated as if they were whatever
2423/// value is necessary in order to fit the above forms.
2425 MVT VT, SDValue V1, SDValue V2,
2426 SelectionDAG &DAG) {
2427
2428 const auto &Begin = Mask.begin();
2429 const auto &Mid = Mask.begin() + Mask.size() / 2;
2430 const auto &End = Mask.end();
2431 SDValue OriV1 = V1, OriV2 = V2;
2432
2433 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2434 V1 = OriV1;
2435 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2436 V1 = OriV2;
2437 else
2438 return SDValue();
2439
2440 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2441 V2 = OriV1;
2442 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2443 V2 = OriV2;
2444 else
2445 return SDValue();
2446
2447 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2448}
2449
2450/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2451///
2452/// VEXTRINS copies one element of a vector into any place of the result
2453/// vector and makes no change to the rest elements of the result vector.
2454///
2455/// It is possible to lower into VEXTRINS when the mask takes the form:
2456/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2457/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2458/// where n is the number of elements in the vector and i is in [0, n).
2459/// For example:
2460/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2461/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2462///
2463/// When undef's appear in the mask they are treated as if they were whatever
2464/// value is necessary in order to fit the above forms.
2465static SDValue
2467 SDValue V1, SDValue V2, SelectionDAG &DAG,
2468 const LoongArchSubtarget &Subtarget) {
2469 unsigned NumElts = VT.getVectorNumElements();
2470 MVT EltVT = VT.getVectorElementType();
2471 MVT GRLenVT = Subtarget.getGRLenVT();
2472
2473 if (Mask.size() != NumElts)
2474 return SDValue();
2475
2476 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2477 int DiffCount = 0;
2478 int DiffPos = -1;
2479 for (unsigned i = 0; i < NumElts; ++i) {
2480 if (Mask[i] == -1)
2481 continue;
2482 if (Mask[i] != int(Base + i)) {
2483 ++DiffCount;
2484 DiffPos = int(i);
2485 if (DiffCount > 1)
2486 return SDValue();
2487 }
2488 }
2489
2490 // Need exactly one differing element to lower into VEXTRINS.
2491 if (DiffCount != 1)
2492 return SDValue();
2493
2494 // DiffMask must be in [0, 2N).
2495 int DiffMask = Mask[DiffPos];
2496 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2497 return SDValue();
2498
2499 // Determine source vector and source index.
2500 SDValue SrcVec;
2501 unsigned SrcIdx;
2502 if (unsigned(DiffMask) < NumElts) {
2503 SrcVec = V1;
2504 SrcIdx = unsigned(DiffMask);
2505 } else {
2506 SrcVec = V2;
2507 SrcIdx = unsigned(DiffMask) - NumElts;
2508 }
2509
2510 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2511 // patterns of VEXTRINS in tablegen.
2512 SDValue Extracted = DAG.getNode(
2513 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2514 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2515 SDValue Result =
2516 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2517 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2518
2519 return Result;
2520 };
2521
2522 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2523 if (SDValue Result = tryLowerToExtrAndIns(0))
2524 return Result;
2525 return tryLowerToExtrAndIns(NumElts);
2526}
2527
2528// Check the Mask and then build SrcVec and MaskImm infos which will
2529// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2530// On success, return true. Otherwise, return false.
2533 unsigned &MaskImm) {
2534 unsigned MaskSize = Mask.size();
2535
2536 auto isValid = [&](int M, int Off) {
2537 return (M == -1) || (M >= Off && M < Off + 4);
2538 };
2539
2540 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2541 auto immPart = [&](int M, unsigned Off) {
2542 return (M == -1 ? 0 : (M - Off)) & 0x3;
2543 };
2544 MaskImm |= immPart(MLo, Off) << (I * 2);
2545 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2546 };
2547
2548 for (unsigned i = 0; i < 4; i += 2) {
2549 int MLo = Mask[i];
2550 int MHi = Mask[i + 1];
2551
2552 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2553 auto isValid2 = [&](int &M, int M2) {
2554 // If high half index is undef, it's always valid.
2555 if (M2 == -1)
2556 return true;
2557 if (M == -1) {
2558 // If low half index is undef, use index from high half,
2559 // remapped to low half.
2560 if ((M2 % MaskSize) < 4)
2561 return false;
2562 M = M2 - 4;
2563 return true;
2564 }
2565 // Index in low half must be same as index in high half.
2566 return M2 == M + 4;
2567 };
2568 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2569 return false;
2570 }
2571
2572 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2573 SrcVec.push_back(V1);
2574 buildImm(MLo, MHi, 0, i);
2575 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2576 SrcVec.push_back(V2);
2577 buildImm(MLo, MHi, MaskSize, i);
2578 } else {
2579 return false;
2580 }
2581 }
2582
2583 return true;
2584}
2585
2586/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2587///
2588/// VPERMI selects two elements from each of the two vectors based on the
2589/// mask and places them in the corresponding positions of the result vector
2590/// in order. Only v4i32 and v4f32 types are allowed.
2591///
2592/// It is possible to lower into VPERMI when the mask consists of two of the
2593/// following forms concatenated:
2594/// <i, j, u, v>
2595/// <u, v, i, j>
2596/// where i,j are in [0,4) and u,v are in [4, 8).
2597/// For example:
2598/// <2, 3, 4, 5>
2599/// <5, 7, 0, 2>
2600///
2601/// When undef's appear in the mask they are treated as if they were whatever
2602/// value is necessary in order to fit the above forms.
2604 MVT VT, SDValue V1, SDValue V2,
2605 SelectionDAG &DAG,
2606 const LoongArchSubtarget &Subtarget) {
2607 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2608 Mask.size() != VT.getVectorNumElements())
2609 return SDValue();
2610
2612 unsigned MaskImm = 0;
2613 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2614 return SDValue();
2615
2616 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2617 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2618}
2619
2620/// Lower VECTOR_SHUFFLE into VSHUF.
2621///
2622/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2623/// adding it as an operand to the resulting VSHUF.
2625 MVT VT, SDValue V1, SDValue V2,
2626 SelectionDAG &DAG,
2627 const LoongArchSubtarget &Subtarget) {
2628
2630 for (auto M : Mask)
2631 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2632
2633 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2634 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2635
2636 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2637 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2638 // VSHF concatenates the vectors in a bitwise fashion:
2639 // <0b00, 0b01> + <0b10, 0b11> ->
2640 // 0b0100 + 0b1110 -> 0b01001110
2641 // <0b10, 0b11, 0b00, 0b01>
2642 // We must therefore swap the operands to get the correct result.
2643 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2644}
2645
2646/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2647///
2648/// This routine breaks down the specific type of 128-bit shuffle and
2649/// dispatches to the lowering routines accordingly.
2651 SDValue V1, SDValue V2, SelectionDAG &DAG,
2652 const LoongArchSubtarget &Subtarget) {
2653 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2654 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2655 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2656 "Vector type is unsupported for lsx!");
2657 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2658 "Two operands have different types!");
2659 assert(VT.getVectorNumElements() == Mask.size() &&
2660 "Unexpected mask size for shuffle!");
2661 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2662
2663 APInt KnownUndef, KnownZero;
2664 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2665 APInt Zeroable = KnownUndef | KnownZero;
2666
2667 SDValue Result;
2668 // TODO: Add more comparison patterns.
2669 if (V2.isUndef()) {
2670 if ((Result =
2671 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2672 return Result;
2673 if ((Result =
2674 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2675 return Result;
2676 if ((Result =
2677 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2678 return Result;
2679
2680 // TODO: This comment may be enabled in the future to better match the
2681 // pattern for instruction selection.
2682 /* V2 = V1; */
2683 }
2684
2685 // It is recommended not to change the pattern comparison order for better
2686 // performance.
2687 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2688 return Result;
2689 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2690 return Result;
2691 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2692 return Result;
2693 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2694 return Result;
2695 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2696 return Result;
2697 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2698 return Result;
2699 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2700 (Result =
2701 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2702 return Result;
2703 if ((Result =
2704 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2705 return Result;
2706 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2707 Zeroable)))
2708 return Result;
2709 if ((Result =
2710 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2711 return Result;
2712 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2713 Zeroable)))
2714 return Result;
2715 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2716 Subtarget)))
2717 return Result;
2718 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2719 return NewShuffle;
2720 if ((Result =
2721 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2722 return Result;
2723 return SDValue();
2724}
2725
2726/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2727///
2728/// It is a XVREPLVEI when the mask is:
2729/// <x, x, x, ..., x+n, x+n, x+n, ...>
2730/// where the number of x is equal to n and n is half the length of vector.
2731///
2732/// When undef's appear in the mask they are treated as if they were whatever
2733/// value is necessary in order to fit the above form.
2734static SDValue
2736 SDValue V1, SelectionDAG &DAG,
2737 const LoongArchSubtarget &Subtarget) {
2738 int SplatIndex = -1;
2739 for (const auto &M : Mask) {
2740 if (M != -1) {
2741 SplatIndex = M;
2742 break;
2743 }
2744 }
2745
2746 if (SplatIndex == -1)
2747 return DAG.getUNDEF(VT);
2748
2749 const auto &Begin = Mask.begin();
2750 const auto &End = Mask.end();
2751 int HalfSize = Mask.size() / 2;
2752
2753 if (SplatIndex >= HalfSize)
2754 return SDValue();
2755
2756 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2757 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2758 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2759 0)) {
2760 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2761 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2762 }
2763
2764 return SDValue();
2765}
2766
2767/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2768static SDValue
2770 SDValue V1, SDValue V2, SelectionDAG &DAG,
2771 const LoongArchSubtarget &Subtarget) {
2772 // XVSHUF4I_D must be handled separately because it is different from other
2773 // types of [X]VSHUF4I instructions.
2774 if (Mask.size() == 4) {
2775 unsigned MaskImm = 0;
2776 for (int i = 1; i >= 0; --i) {
2777 int MLo = Mask[i];
2778 int MHi = Mask[i + 2];
2779 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2780 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2781 return SDValue();
2782 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2783 return SDValue();
2784
2785 MaskImm <<= 2;
2786 if (MLo != -1)
2787 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2788 else if (MHi != -1)
2789 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2790 }
2791
2792 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2793 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2794 }
2795
2796 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2797}
2798
2799/// Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
2800///
2801/// It is a XVREPLVE0 when the VECTOR_SHUFFLE is a broadcast of element 0,
2802/// i.e. the mask is:
2803/// <0, 0, 0, ...>
2804///
2805/// When undef's appear in the mask they are treated as if they were whatever
2806/// value is necessary in order to fit the above form.
2808 ArrayRef<int> Mask, MVT VT,
2809 SDValue V1, SelectionDAG &DAG) {
2810 if (!ShuffleVectorInst::isZeroEltSplatMask(Mask, Mask.size()))
2811 return SDValue();
2812
2813 return DAG.getNode(LoongArchISD::XVREPLVE0, DL, VT, V1);
2814}
2815
2816/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2817static SDValue
2819 SDValue V1, SDValue V2, SelectionDAG &DAG,
2820 const LoongArchSubtarget &Subtarget) {
2821 MVT GRLenVT = Subtarget.getGRLenVT();
2822 unsigned MaskSize = Mask.size();
2823 if (MaskSize != VT.getVectorNumElements())
2824 return SDValue();
2825
2826 // Consider XVPERMI_W.
2827 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2829 unsigned MaskImm = 0;
2830 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2831 return SDValue();
2832
2833 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2834 DAG.getConstant(MaskImm, DL, GRLenVT));
2835 }
2836
2837 // Consider XVPERMI_D.
2838 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2839 unsigned MaskImm = 0;
2840 for (unsigned i = 0; i < MaskSize; ++i) {
2841 if (Mask[i] == -1)
2842 continue;
2843 if (Mask[i] >= (int)MaskSize)
2844 return SDValue();
2845 MaskImm |= Mask[i] << (i * 2);
2846 }
2847
2848 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2849 DAG.getConstant(MaskImm, DL, GRLenVT));
2850 }
2851
2852 return SDValue();
2853}
2854
2855/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2857 MVT VT, SDValue V1, SelectionDAG &DAG,
2858 const LoongArchSubtarget &Subtarget) {
2859 // LoongArch LASX only have XVPERM_W.
2860 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2861 return SDValue();
2862
2863 unsigned NumElts = VT.getVectorNumElements();
2864 unsigned HalfSize = NumElts / 2;
2865 bool FrontLo = true, FrontHi = true;
2866 bool BackLo = true, BackHi = true;
2867
2868 auto inRange = [](int val, int low, int high) {
2869 return (val == -1) || (val >= low && val < high);
2870 };
2871
2872 for (unsigned i = 0; i < HalfSize; ++i) {
2873 int Fronti = Mask[i];
2874 int Backi = Mask[i + HalfSize];
2875
2876 FrontLo &= inRange(Fronti, 0, HalfSize);
2877 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2878 BackLo &= inRange(Backi, 0, HalfSize);
2879 BackHi &= inRange(Backi, HalfSize, NumElts);
2880 }
2881
2882 // If both the lower and upper 128-bit parts access only one half of the
2883 // vector (either lower or upper), avoid using xvperm.w. The latency of
2884 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2885 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2886 return SDValue();
2887
2889 MVT GRLenVT = Subtarget.getGRLenVT();
2890 for (unsigned i = 0; i < NumElts; ++i)
2891 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2892 : DAG.getConstant(Mask[i], DL, GRLenVT));
2893 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2894
2895 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2896}
2897
2898/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2900 MVT VT, SDValue V1, SDValue V2,
2901 SelectionDAG &DAG) {
2902 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2903}
2904
2905/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2907 MVT VT, SDValue V1, SDValue V2,
2908 SelectionDAG &DAG) {
2909 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2910}
2911
2912/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2914 MVT VT, SDValue V1, SDValue V2,
2915 SelectionDAG &DAG) {
2916
2917 const auto &Begin = Mask.begin();
2918 const auto &End = Mask.end();
2919 unsigned HalfSize = Mask.size() / 2;
2920 unsigned LeftSize = HalfSize / 2;
2921 SDValue OriV1 = V1, OriV2 = V2;
2922
2923 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2924 1) &&
2925 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2926 V1 = OriV1;
2927 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2928 Mask.size() + HalfSize - LeftSize, 1) &&
2929 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2930 Mask.size() + HalfSize + LeftSize, 1))
2931 V1 = OriV2;
2932 else
2933 return SDValue();
2934
2935 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
2936 1) &&
2937 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
2938 1))
2939 V2 = OriV1;
2940 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
2941 Mask.size() + HalfSize - LeftSize, 1) &&
2942 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2943 Mask.size() + HalfSize + LeftSize, 1))
2944 V2 = OriV2;
2945 else
2946 return SDValue();
2947
2948 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2949}
2950
2951/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
2953 MVT VT, SDValue V1, SDValue V2,
2954 SelectionDAG &DAG) {
2955
2956 const auto &Begin = Mask.begin();
2957 const auto &End = Mask.end();
2958 unsigned HalfSize = Mask.size() / 2;
2959 SDValue OriV1 = V1, OriV2 = V2;
2960
2961 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
2962 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
2963 V1 = OriV1;
2964 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
2965 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2966 Mask.size() + HalfSize, 1))
2967 V1 = OriV2;
2968 else
2969 return SDValue();
2970
2971 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
2972 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
2973 V2 = OriV1;
2974 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
2975 1) &&
2976 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2977 Mask.size() + HalfSize, 1))
2978 V2 = OriV2;
2979 else
2980 return SDValue();
2981
2982 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2983}
2984
2985/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
2987 MVT VT, SDValue V1, SDValue V2,
2988 SelectionDAG &DAG) {
2989
2990 const auto &Begin = Mask.begin();
2991 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
2992 const auto &Mid = Mask.begin() + Mask.size() / 2;
2993 const auto &RightMid = Mask.end() - Mask.size() / 4;
2994 const auto &End = Mask.end();
2995 unsigned HalfSize = Mask.size() / 2;
2996 SDValue OriV1 = V1, OriV2 = V2;
2997
2998 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
2999 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
3000 V1 = OriV1;
3001 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
3002 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
3003 V1 = OriV2;
3004 else
3005 return SDValue();
3006
3007 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
3008 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
3009 V2 = OriV1;
3010 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
3011 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
3012 V2 = OriV2;
3013
3014 else
3015 return SDValue();
3016
3017 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
3018}
3019
3020/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
3022 MVT VT, SDValue V1, SDValue V2,
3023 SelectionDAG &DAG) {
3024
3025 const auto &Begin = Mask.begin();
3026 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3027 const auto &Mid = Mask.begin() + Mask.size() / 2;
3028 const auto &RightMid = Mask.end() - Mask.size() / 4;
3029 const auto &End = Mask.end();
3030 unsigned HalfSize = Mask.size() / 2;
3031 SDValue OriV1 = V1, OriV2 = V2;
3032
3033 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
3034 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
3035 V1 = OriV1;
3036 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3037 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3038 2))
3039 V1 = OriV2;
3040 else
3041 return SDValue();
3042
3043 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3044 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3045 V2 = OriV1;
3046 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3047 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3048 2))
3049 V2 = OriV2;
3050 else
3051 return SDValue();
3052
3053 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3054}
3055
3056/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3057static SDValue
3059 SDValue V1, SDValue V2, SelectionDAG &DAG,
3060 const LoongArchSubtarget &Subtarget) {
3061 int NumElts = VT.getVectorNumElements();
3062 int HalfSize = NumElts / 2;
3063 MVT EltVT = VT.getVectorElementType();
3064 MVT GRLenVT = Subtarget.getGRLenVT();
3065
3066 if ((int)Mask.size() != NumElts)
3067 return SDValue();
3068
3069 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3070 SmallVector<int> DiffPos;
3071 for (int i = 0; i < NumElts; ++i) {
3072 if (Mask[i] == -1)
3073 continue;
3074 if (Mask[i] != Base + i) {
3075 DiffPos.push_back(i);
3076 if (DiffPos.size() > 2)
3077 return SDValue();
3078 }
3079 }
3080
3081 // Need exactly two differing element to lower into XVEXTRINS.
3082 // If only one differing element, the element at a distance of
3083 // HalfSize from it must be undef.
3084 if (DiffPos.size() == 1) {
3085 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3086 DiffPos.push_back(DiffPos[0] + HalfSize);
3087 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3088 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3089 else
3090 return SDValue();
3091 }
3092 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3093 return SDValue();
3094
3095 // DiffMask must be in its low or high part.
3096 int DiffMaskLo = Mask[DiffPos[0]];
3097 int DiffMaskHi = Mask[DiffPos[1]];
3098 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3099 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3100 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3101 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3102 return SDValue();
3103 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3104 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3105 return SDValue();
3106 if (DiffMaskHi != DiffMaskLo + HalfSize)
3107 return SDValue();
3108
3109 // Determine source vector and source index.
3110 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3111 int SrcIdxLo =
3112 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3113 bool IsEltFP = EltVT.isFloatingPoint();
3114
3115 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3116 // the patterns of XVEXTRINS in tablegen.
3117 SDValue BaseVec = (Base == 0) ? V1 : V2;
3118 SDValue EltLo =
3119 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3120 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3121 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3122 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3123 SDValue EltHi =
3124 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3125 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3126 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3127 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3128
3129 return Result;
3130 };
3131
3132 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3133 if (SDValue Result = tryLowerToExtrAndIns(0))
3134 return Result;
3135 return tryLowerToExtrAndIns(NumElts);
3136}
3137
3138/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3139static SDValue
3141 SDValue V1, SDValue V2, SelectionDAG &DAG,
3142 const LoongArchSubtarget &Subtarget) {
3143 // LoongArch LASX only supports xvinsve0.{w/d}.
3144 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3145 VT != MVT::v4f64)
3146 return SDValue();
3147
3148 MVT GRLenVT = Subtarget.getGRLenVT();
3149 int MaskSize = Mask.size();
3150 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3151
3152 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3153 // all other elements are either 'Base + i' or undef (-1). On success, return
3154 // the index of the replaced element. Otherwise, just return -1.
3155 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3156 int Idx = -1;
3157 for (int i = 0; i < MaskSize; ++i) {
3158 if (Mask[i] == Base + i || Mask[i] == -1)
3159 continue;
3160 if (Mask[i] != Replaced)
3161 return -1;
3162 if (Idx == -1)
3163 Idx = i;
3164 else
3165 return -1;
3166 }
3167 return Idx;
3168 };
3169
3170 // Case 1: the lowest element of V2 replaces one element in V1.
3171 int Idx = checkReplaceOne(0, MaskSize);
3172 if (Idx != -1)
3173 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3174 DAG.getConstant(Idx, DL, GRLenVT));
3175
3176 // Case 2: the lowest element of V1 replaces one element in V2.
3177 Idx = checkReplaceOne(MaskSize, 0);
3178 if (Idx != -1)
3179 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3180 DAG.getConstant(Idx, DL, GRLenVT));
3181
3182 return SDValue();
3183}
3184
3185/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3187 MVT VT, SDValue V1, SDValue V2,
3188 SelectionDAG &DAG) {
3189
3190 int MaskSize = Mask.size();
3191 int HalfSize = Mask.size() / 2;
3192 const auto &Begin = Mask.begin();
3193 const auto &Mid = Mask.begin() + HalfSize;
3194 const auto &End = Mask.end();
3195
3196 // VECTOR_SHUFFLE concatenates the vectors:
3197 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3198 // shuffling ->
3199 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3200 //
3201 // XVSHUF concatenates the vectors:
3202 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3203 // shuffling ->
3204 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3205 SmallVector<SDValue, 8> MaskAlloc;
3206 for (auto it = Begin; it < Mid; it++) {
3207 if (*it < 0) // UNDEF
3208 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3209 else if ((*it >= 0 && *it < HalfSize) ||
3210 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3211 int M = *it < HalfSize ? *it : *it - HalfSize;
3212 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3213 } else
3214 return SDValue();
3215 }
3216 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3217
3218 for (auto it = Mid; it < End; it++) {
3219 if (*it < 0) // UNDEF
3220 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3221 else if ((*it >= HalfSize && *it < MaskSize) ||
3222 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3223 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3224 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3225 } else
3226 return SDValue();
3227 }
3228 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3229
3230 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3231 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3232 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3233}
3234
3235/// Shuffle vectors by lane to generate more optimized instructions.
3236/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3237///
3238/// Therefore, except for the following four cases, other cases are regarded
3239/// as cross-lane shuffles, where optimization is relatively limited.
3240///
3241/// - Shuffle high, low lanes of two inputs vector
3242/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3243/// - Shuffle low, high lanes of two inputs vector
3244/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3245/// - Shuffle low, low lanes of two inputs vector
3246/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3247/// - Shuffle high, high lanes of two inputs vector
3248/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3249///
3250/// The first case is the closest to LoongArch instructions and the other
3251/// cases need to be converted to it for processing.
3252///
3253/// This function will return true for the last three cases above and will
3254/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3255/// cross-lane shuffle cases.
3257 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3258 SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
3259
3260 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3261
3262 int MaskSize = Mask.size();
3263 int HalfSize = Mask.size() / 2;
3264 MVT GRLenVT = Subtarget.getGRLenVT();
3265
3266 HalfMaskType preMask = None, postMask = None;
3267
3268 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3269 return M < 0 || (M >= 0 && M < HalfSize) ||
3270 (M >= MaskSize && M < MaskSize + HalfSize);
3271 }))
3272 preMask = HighLaneTy;
3273 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3274 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3275 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3276 }))
3277 preMask = LowLaneTy;
3278
3279 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3280 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3281 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3282 }))
3283 postMask = LowLaneTy;
3284 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3285 return M < 0 || (M >= 0 && M < HalfSize) ||
3286 (M >= MaskSize && M < MaskSize + HalfSize);
3287 }))
3288 postMask = HighLaneTy;
3289
3290 // The pre-half of mask is high lane type, and the post-half of mask
3291 // is low lane type, which is closest to the LoongArch instructions.
3292 //
3293 // Note: In the LoongArch architecture, the high lane of mask corresponds
3294 // to the lower 128-bit of vector register, and the low lane of mask
3295 // corresponds the higher 128-bit of vector register.
3296 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3297 return false;
3298 }
3299 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3300 V1 = DAG.getBitcast(MVT::v4i64, V1);
3301 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3302 DAG.getConstant(0b01001110, DL, GRLenVT));
3303 V1 = DAG.getBitcast(VT, V1);
3304
3305 if (!V2.isUndef()) {
3306 V2 = DAG.getBitcast(MVT::v4i64, V2);
3307 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3308 DAG.getConstant(0b01001110, DL, GRLenVT));
3309 V2 = DAG.getBitcast(VT, V2);
3310 }
3311
3312 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3313 *it = *it < 0 ? *it : *it - HalfSize;
3314 }
3315 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3316 *it = *it < 0 ? *it : *it + HalfSize;
3317 }
3318 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3319 V1 = DAG.getBitcast(MVT::v4i64, V1);
3320 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3321 DAG.getConstant(0b11101110, DL, GRLenVT));
3322 V1 = DAG.getBitcast(VT, V1);
3323
3324 if (!V2.isUndef()) {
3325 V2 = DAG.getBitcast(MVT::v4i64, V2);
3326 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3327 DAG.getConstant(0b11101110, DL, GRLenVT));
3328 V2 = DAG.getBitcast(VT, V2);
3329 }
3330
3331 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3332 *it = *it < 0 ? *it : *it - HalfSize;
3333 }
3334 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3335 V1 = DAG.getBitcast(MVT::v4i64, V1);
3336 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3337 DAG.getConstant(0b01000100, DL, GRLenVT));
3338 V1 = DAG.getBitcast(VT, V1);
3339
3340 if (!V2.isUndef()) {
3341 V2 = DAG.getBitcast(MVT::v4i64, V2);
3342 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3343 DAG.getConstant(0b01000100, DL, GRLenVT));
3344 V2 = DAG.getBitcast(VT, V2);
3345 }
3346
3347 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3348 *it = *it < 0 ? *it : *it + HalfSize;
3349 }
3350 } else { // cross-lane
3351 return false;
3352 }
3353
3354 return true;
3355}
3356
3357/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3358/// Only for 256-bit vector.
3359///
3360/// For example:
3361/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3362/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3363/// is lowerded to:
3364/// (XVPERMI $xr2, $xr0, 78)
3365/// (XVSHUF $xr1, $xr2, $xr0)
3366/// (XVORI $xr0, $xr1, 0)
3368 ArrayRef<int> Mask,
3369 MVT VT, SDValue V1,
3370 SDValue V2,
3371 SelectionDAG &DAG) {
3372 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3373 int Size = Mask.size();
3374 int LaneSize = Size / 2;
3375
3376 bool LaneCrossing[2] = {false, false};
3377 for (int i = 0; i < Size; ++i)
3378 if (Mask[i] >= 0 && ((Mask[i] % Size) / LaneSize) != (i / LaneSize))
3379 LaneCrossing[(Mask[i] % Size) / LaneSize] = true;
3380
3381 // Ensure that all lanes ared involved.
3382 if (!LaneCrossing[0] && !LaneCrossing[1])
3383 return SDValue();
3384
3385 SmallVector<int> InLaneMask;
3386 InLaneMask.assign(Mask.begin(), Mask.end());
3387 for (int i = 0; i < Size; ++i) {
3388 int &M = InLaneMask[i];
3389 if (M < 0)
3390 continue;
3391 if (((M % Size) / LaneSize) != (i / LaneSize))
3392 M = (M % LaneSize) + ((i / LaneSize) * LaneSize) + Size;
3393 }
3394
3395 SDValue Flipped = DAG.getBitcast(MVT::v4i64, V1);
3396 Flipped = DAG.getVectorShuffle(MVT::v4i64, DL, Flipped,
3397 DAG.getUNDEF(MVT::v4i64), {2, 3, 0, 1});
3398 Flipped = DAG.getBitcast(VT, Flipped);
3399 return DAG.getVectorShuffle(VT, DL, V1, Flipped, InLaneMask);
3400}
3401
3402/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3403///
3404/// This routine breaks down the specific type of 256-bit shuffle and
3405/// dispatches to the lowering routines accordingly.
3407 SDValue V1, SDValue V2, SelectionDAG &DAG,
3408 const LoongArchSubtarget &Subtarget) {
3409 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3410 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3411 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3412 "Vector type is unsupported for lasx!");
3413 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3414 "Two operands have different types!");
3415 assert(VT.getVectorNumElements() == Mask.size() &&
3416 "Unexpected mask size for shuffle!");
3417 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3418 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3419
3420 APInt KnownUndef, KnownZero;
3421 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3422 APInt Zeroable = KnownUndef | KnownZero;
3423
3424 SDValue Result;
3425 // TODO: Add more comparison patterns.
3426 if (V2.isUndef()) {
3427 if ((Result =
3428 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3429 return Result;
3430 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3431 Subtarget)))
3432 return Result;
3433 if ((Result = lowerVECTOR_SHUFFLE_XVREPLVE0(DL, Mask, VT, V1, DAG)))
3434 return Result;
3435 // Try to widen vectors to gain more optimization opportunities.
3436 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3437 return NewShuffle;
3438 if ((Result =
3439 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3440 return Result;
3441 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3442 return Result;
3443 if ((Result =
3444 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3445 return Result;
3446
3447 // TODO: This comment may be enabled in the future to better match the
3448 // pattern for instruction selection.
3449 /* V2 = V1; */
3450 }
3451
3452 // It is recommended not to change the pattern comparison order for better
3453 // performance.
3454 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3455 return Result;
3456 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3457 return Result;
3458 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3459 return Result;
3460 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3461 return Result;
3462 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3463 return Result;
3464 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3465 return Result;
3466 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3467 (Result =
3468 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3469 return Result;
3470 if ((Result =
3471 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3472 return Result;
3473 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3474 Zeroable)))
3475 return Result;
3476 if ((Result =
3477 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3478 return Result;
3479 if ((Result =
3480 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3481 return Result;
3482 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3483 Subtarget)))
3484 return Result;
3485
3486 // canonicalize non cross-lane shuffle vector
3487 SmallVector<int> NewMask(Mask);
3488 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3489 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3490
3491 // FIXME: Handling the remaining cases earlier can degrade performance
3492 // in some situations. Further analysis is required to enable more
3493 // effective optimizations.
3494 if (V2.isUndef()) {
3495 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT,
3496 V1, V2, DAG)))
3497 return Result;
3498 }
3499
3500 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3501 return NewShuffle;
3502 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3503 return Result;
3504
3505 return SDValue();
3506}
3507
3508SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3509 SelectionDAG &DAG) const {
3510 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3511 ArrayRef<int> OrigMask = SVOp->getMask();
3512 SDValue V1 = Op.getOperand(0);
3513 SDValue V2 = Op.getOperand(1);
3514 MVT VT = Op.getSimpleValueType();
3515 int NumElements = VT.getVectorNumElements();
3516 SDLoc DL(Op);
3517
3518 bool V1IsUndef = V1.isUndef();
3519 bool V2IsUndef = V2.isUndef();
3520 if (V1IsUndef && V2IsUndef)
3521 return DAG.getUNDEF(VT);
3522
3523 // When we create a shuffle node we put the UNDEF node to second operand,
3524 // but in some cases the first operand may be transformed to UNDEF.
3525 // In this case we should just commute the node.
3526 if (V1IsUndef)
3527 return DAG.getCommutedVectorShuffle(*SVOp);
3528
3529 // Check for non-undef masks pointing at an undef vector and make the masks
3530 // undef as well. This makes it easier to match the shuffle based solely on
3531 // the mask.
3532 if (V2IsUndef &&
3533 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3534 SmallVector<int, 8> NewMask(OrigMask);
3535 for (int &M : NewMask)
3536 if (M >= NumElements)
3537 M = -1;
3538 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3539 }
3540
3541 // Check for illegal shuffle mask element index values.
3542 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3543 (void)MaskUpperLimit;
3544 assert(llvm::all_of(OrigMask,
3545 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3546 "Out of bounds shuffle index");
3547
3548 // For each vector width, delegate to a specialized lowering routine.
3549 if (VT.is128BitVector())
3550 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3551
3552 if (VT.is256BitVector())
3553 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3554
3555 return SDValue();
3556}
3557
3558SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3559 SelectionDAG &DAG) const {
3560 // Custom lower to ensure the libcall return is passed in an FPR on hard
3561 // float ABIs.
3562 SDLoc DL(Op);
3563 MakeLibCallOptions CallOptions;
3564 SDValue Op0 = Op.getOperand(0);
3565 SDValue Chain = SDValue();
3566 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3567 SDValue Res;
3568 std::tie(Res, Chain) =
3569 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3570 if (Subtarget.is64Bit())
3571 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3572 return DAG.getBitcast(MVT::i32, Res);
3573}
3574
3575SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3576 SelectionDAG &DAG) const {
3577 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3578 // float ABIs.
3579 SDLoc DL(Op);
3580 MakeLibCallOptions CallOptions;
3581 SDValue Op0 = Op.getOperand(0);
3582 SDValue Chain = SDValue();
3583 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3584 DL, MVT::f32, Op0)
3585 : DAG.getBitcast(MVT::f32, Op0);
3586 SDValue Res;
3587 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3588 CallOptions, DL, Chain);
3589 return Res;
3590}
3591
3592SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3593 SelectionDAG &DAG) const {
3594 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3595 SDLoc DL(Op);
3596 MakeLibCallOptions CallOptions;
3597 RTLIB::Libcall LC =
3598 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3599 SDValue Res =
3600 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3601 if (Subtarget.is64Bit())
3602 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3603 return DAG.getBitcast(MVT::i32, Res);
3604}
3605
3606SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3607 SelectionDAG &DAG) const {
3608 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3609 MVT VT = Op.getSimpleValueType();
3610 SDLoc DL(Op);
3611 Op = DAG.getNode(
3612 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3613 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3614 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3615 DL, MVT::f32, Op)
3616 : DAG.getBitcast(MVT::f32, Op);
3617 if (VT != MVT::f32)
3618 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3619 return Res;
3620}
3621
3622// Lower BUILD_VECTOR as broadcast load (if possible).
3623// For example:
3624// %a = load i8, ptr %ptr
3625// %b = build_vector %a, %a, %a, %a
3626// is lowered to :
3627// (VLDREPL_B $a0, 0)
3629 const SDLoc &DL,
3630 SelectionDAG &DAG) {
3631 MVT VT = BVOp->getSimpleValueType(0);
3632 int NumOps = BVOp->getNumOperands();
3633
3634 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3635 "Unsupported vector type for broadcast.");
3636
3637 SDValue IdentitySrc;
3638 bool IsIdeneity = true;
3639
3640 for (int i = 0; i != NumOps; i++) {
3641 SDValue Op = BVOp->getOperand(i);
3642 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3643 IsIdeneity = false;
3644 break;
3645 }
3646 IdentitySrc = BVOp->getOperand(0);
3647 }
3648
3649 // make sure that this load is valid and only has one user.
3650 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3651 return SDValue();
3652
3653 auto *LN = cast<LoadSDNode>(IdentitySrc);
3654 auto ExtType = LN->getExtensionType();
3655
3656 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3657 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3658 // Indexed loads and stores are not supported on LoongArch.
3659 assert(LN->isUnindexed() && "Unexpected indexed load.");
3660
3661 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3662 // The offset operand of unindexed load is always undefined, so there is
3663 // no need to pass it to VLDREPL.
3664 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3665 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3666 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3667 return BCast;
3668 }
3669 return SDValue();
3670}
3671
3672// Sequentially insert elements from Ops into Vector, from low to high indices.
3673// Note: Ops can have fewer elements than Vector.
3675 const LoongArchSubtarget &Subtarget, SDValue &Vector,
3676 EVT ResTy) {
3677 assert(Ops.size() <= ResTy.getVectorNumElements());
3678
3679 SDValue Op0 = Ops[0];
3680 if (!Op0.isUndef())
3681 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3682 for (unsigned i = 1; i < Ops.size(); ++i) {
3683 SDValue Opi = Ops[i];
3684 if (Opi.isUndef())
3685 continue;
3686 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3687 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3688 }
3689}
3690
3691// Build a ResTy subvector from Node, taking NumElts elements starting at index
3692// 'first'.
3694 SelectionDAG &DAG, SDLoc DL,
3695 const LoongArchSubtarget &Subtarget,
3696 EVT ResTy, unsigned first) {
3697 unsigned NumElts = ResTy.getVectorNumElements();
3698
3699 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3700
3701 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3702 Node->op_begin() + first + NumElts);
3703 SDValue Vector = DAG.getUNDEF(ResTy);
3704 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3705 return Vector;
3706}
3707
3708SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3709 SelectionDAG &DAG) const {
3710 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3711 MVT VT = Node->getSimpleValueType(0);
3712 EVT ResTy = Op->getValueType(0);
3713 unsigned NumElts = ResTy.getVectorNumElements();
3714 SDLoc DL(Op);
3715 APInt SplatValue, SplatUndef;
3716 unsigned SplatBitSize;
3717 bool HasAnyUndefs;
3718 bool IsConstant = false;
3719 bool UseSameConstant = true;
3720 SDValue ConstantValue;
3721 bool Is128Vec = ResTy.is128BitVector();
3722 bool Is256Vec = ResTy.is256BitVector();
3723
3724 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3725 (!Subtarget.hasExtLASX() || !Is256Vec))
3726 return SDValue();
3727
3728 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3729 return Result;
3730
3731 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3732 /*MinSplatBits=*/8) &&
3733 SplatBitSize <= 64) {
3734 // We can only cope with 8, 16, 32, or 64-bit elements.
3735 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3736 SplatBitSize != 64)
3737 return SDValue();
3738
3739 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3740 // We can only handle 64-bit elements that are within
3741 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3742 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3743 if (!SplatValue.isSignedIntN(10) &&
3744 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3745 return SDValue();
3746 if ((Is128Vec && ResTy == MVT::v4i32) ||
3747 (Is256Vec && ResTy == MVT::v8i32))
3748 return Op;
3749 }
3750
3751 EVT ViaVecTy;
3752
3753 switch (SplatBitSize) {
3754 default:
3755 return SDValue();
3756 case 8:
3757 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3758 break;
3759 case 16:
3760 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3761 break;
3762 case 32:
3763 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3764 break;
3765 case 64:
3766 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3767 break;
3768 }
3769
3770 // SelectionDAG::getConstant will promote SplatValue appropriately.
3771 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3772
3773 // Bitcast to the type we originally wanted.
3774 if (ViaVecTy != ResTy)
3775 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3776
3777 return Result;
3778 }
3779
3780 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3781 return Op;
3782
3783 for (unsigned i = 0; i < NumElts; ++i) {
3784 SDValue Opi = Node->getOperand(i);
3785 if (isIntOrFPConstant(Opi)) {
3786 IsConstant = true;
3787 if (!ConstantValue.getNode())
3788 ConstantValue = Opi;
3789 else if (ConstantValue != Opi)
3790 UseSameConstant = false;
3791 }
3792 }
3793
3794 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3795 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3796 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3797 for (unsigned i = 0; i < NumElts; ++i) {
3798 SDValue Opi = Node->getOperand(i);
3799 if (!isIntOrFPConstant(Opi))
3800 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3801 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3802 }
3803 return Result;
3804 }
3805
3806 if (!IsConstant) {
3807 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3808 // the sub-sequence of the vector and then broadcast the sub-sequence.
3809 //
3810 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3811 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3812 // generates worse code in some cases. This could be further optimized
3813 // with more consideration.
3815 BitVector UndefElements;
3816 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3817 UndefElements.count() == 0) {
3818 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3819 // because the high part can be simply treated as undef.
3820 SDValue Vector = DAG.getUNDEF(ResTy);
3821 EVT FillTy = Is256Vec
3823 : ResTy;
3824 SDValue FillVec =
3825 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3826
3827 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3828
3829 unsigned SeqLen = Sequence.size();
3830 unsigned SplatLen = NumElts / SeqLen;
3831 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3832 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3833
3834 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3835 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3836 if (SplatEltTy == MVT::i128)
3837 SplatTy = MVT::v4i64;
3838
3839 SDValue SplatVec;
3840 SDValue SrcVec = DAG.getBitcast(
3841 SplatTy,
3842 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3843 if (Is256Vec) {
3844 SplatVec =
3845 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3846 : LoongArchISD::XVREPLVE0,
3847 DL, SplatTy, SrcVec);
3848 } else {
3849 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3850 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3851 }
3852
3853 return DAG.getBitcast(ResTy, SplatVec);
3854 }
3855
3856 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3857 // using memory operations is much lower.
3858 //
3859 // For 256-bit vectors, normally split into two halves and concatenate.
3860 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
3861 // one non-undef element, skip spliting to avoid a worse result.
3862 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
3863 ResTy == MVT::v4f64) {
3864 unsigned NonUndefCount = 0;
3865 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
3866 if (!Node->getOperand(i).isUndef()) {
3867 ++NonUndefCount;
3868 if (NonUndefCount > 1)
3869 break;
3870 }
3871 }
3872 if (NonUndefCount == 1)
3873 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
3874 }
3875
3876 EVT VecTy =
3877 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
3878 SDValue Vector =
3879 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
3880
3881 if (Is128Vec)
3882 return Vector;
3883
3884 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
3885 VecTy, NumElts / 2);
3886
3887 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
3888 }
3889
3890 return SDValue();
3891}
3892
3893SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
3894 SelectionDAG &DAG) const {
3895 SDLoc DL(Op);
3896 MVT ResVT = Op.getSimpleValueType();
3897 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
3898
3899 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
3900 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
3901 return Op;
3902
3903 unsigned NumOperands = Op.getNumOperands();
3904 unsigned NumFreezeUndef = 0;
3905 unsigned NumZero = 0;
3906 unsigned NumNonZero = 0;
3907 unsigned NonZeros = 0;
3908 SmallSet<SDValue, 4> Undefs;
3909 for (unsigned i = 0; i != NumOperands; ++i) {
3910 SDValue SubVec = Op.getOperand(i);
3911 if (SubVec.isUndef())
3912 continue;
3913 if (ISD::isFreezeUndef(SubVec.getNode())) {
3914 // If the freeze(undef) has multiple uses then we must fold to zero.
3915 if (SubVec.hasOneUse()) {
3916 ++NumFreezeUndef;
3917 } else {
3918 ++NumZero;
3919 Undefs.insert(SubVec);
3920 }
3921 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
3922 ++NumZero;
3923 else {
3924 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
3925 NonZeros |= 1 << i;
3926 ++NumNonZero;
3927 }
3928 }
3929
3930 // If we have more than 2 non-zeros, build each half separately.
3931 if (NumNonZero > 2) {
3932 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
3933 ArrayRef<SDUse> Ops = Op->ops();
3934 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3935 Ops.slice(0, NumOperands / 2));
3936 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3937 Ops.slice(NumOperands / 2));
3938 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
3939 }
3940
3941 // Otherwise, build it up through insert_subvectors.
3942 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
3943 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
3944 : DAG.getUNDEF(ResVT));
3945
3946 // Replace Undef operands with ZeroVector.
3947 for (SDValue U : Undefs)
3948 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
3949
3950 MVT SubVT = Op.getOperand(0).getSimpleValueType();
3951 unsigned NumSubElems = SubVT.getVectorNumElements();
3952 for (unsigned i = 0; i != NumOperands; ++i) {
3953 if ((NonZeros & (1 << i)) == 0)
3954 continue;
3955
3956 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
3957 DAG.getVectorIdxConstant(i * NumSubElems, DL));
3958 }
3959
3960 return Vec;
3961}
3962
3963SDValue
3964LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
3965 SelectionDAG &DAG) const {
3966 MVT EltVT = Op.getSimpleValueType();
3967 SDValue Vec = Op->getOperand(0);
3968 EVT VecTy = Vec->getValueType(0);
3969 SDValue Idx = Op->getOperand(1);
3970 SDLoc DL(Op);
3971 MVT GRLenVT = Subtarget.getGRLenVT();
3972
3973 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
3974
3975 if (isa<ConstantSDNode>(Idx))
3976 return Op;
3977
3978 switch (VecTy.getSimpleVT().SimpleTy) {
3979 default:
3980 llvm_unreachable("Unexpected type");
3981 case MVT::v32i8:
3982 case MVT::v16i16:
3983 case MVT::v4i64:
3984 case MVT::v4f64: {
3985 // Extract the high half subvector and place it to the low half of a new
3986 // vector. It doesn't matter what the high half of the new vector is.
3987 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
3988 SDValue VecHi =
3989 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
3990 SDValue TmpVec =
3991 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
3992 VecHi, DAG.getConstant(0, DL, GRLenVT));
3993
3994 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
3995 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
3996 // desired element.
3997 SDValue IdxCp =
3998 Subtarget.is64Bit()
3999 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
4000 : DAG.getBitcast(MVT::f32, Idx);
4001 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
4002 SDValue MaskVec =
4003 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
4004 SDValue ResVec =
4005 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
4006
4007 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
4008 DAG.getConstant(0, DL, GRLenVT));
4009 }
4010 case MVT::v8i32:
4011 case MVT::v8f32: {
4012 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
4013 SDValue SplatValue =
4014 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
4015
4016 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
4017 DAG.getConstant(0, DL, GRLenVT));
4018 }
4019 }
4020}
4021
4022SDValue
4023LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
4024 SelectionDAG &DAG) const {
4025 MVT VT = Op.getSimpleValueType();
4026 MVT EltVT = VT.getVectorElementType();
4027 unsigned NumElts = VT.getVectorNumElements();
4028 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
4029 SDLoc DL(Op);
4030 SDValue Op0 = Op.getOperand(0);
4031 SDValue Op1 = Op.getOperand(1);
4032 SDValue Op2 = Op.getOperand(2);
4033
4034 if (isa<ConstantSDNode>(Op2))
4035 return Op;
4036
4037 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4038 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4039
4040 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4041 return SDValue();
4042
4043 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4044 SmallVector<SDValue, 32> RawIndices;
4045 SDValue SplatIdx;
4046 SDValue Indices;
4047
4048 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4049 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4050 for (unsigned i = 0; i < NumElts; ++i) {
4051 RawIndices.push_back(Op2);
4052 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4053 }
4054 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4055 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4056
4057 RawIndices.clear();
4058 for (unsigned i = 0; i < NumElts; ++i) {
4059 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4060 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4061 }
4062 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4063 Indices = DAG.getBitcast(IdxVTy, Indices);
4064 } else {
4065 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4066
4067 for (unsigned i = 0; i < NumElts; ++i)
4068 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4069 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4070 }
4071
4072 // insert vec, elt, idx
4073 // =>
4074 // select (splatidx == {0,1,2...}) ? splatelt : vec
4075 SDValue SelectCC =
4076 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4077 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4078}
4079
4080SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4081 SelectionDAG &DAG) const {
4082 SDLoc DL(Op);
4083 SyncScope::ID FenceSSID =
4084 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4085
4086 // singlethread fences only synchronize with signal handlers on the same
4087 // thread and thus only need to preserve instruction order, not actually
4088 // enforce memory ordering.
4089 if (FenceSSID == SyncScope::SingleThread)
4090 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4091 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4092
4093 return Op;
4094}
4095
4097 MVT GRLenVT, SDValue RMValue) {
4098 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4099 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4100 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4101 //
4102 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4103 // Since the transformation is self-inverse, it applies in both directions:
4104 // LLVM RM <-> LoongArch FCSR RM
4105 //
4106 // Transformation: RM ^ (~(RM >> 1) & 1)
4107 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4108 DAG.getConstant(1, DL, GRLenVT));
4109
4110 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4111 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4112 DAG.getConstant(1, DL, GRLenVT)),
4113 DAG.getConstant(1, DL, GRLenVT));
4114
4115 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4116}
4117
4118SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4119 SelectionDAG &DAG) const {
4120 MVT GRLenVT = Subtarget.getGRLenVT();
4121 SDLoc DL(Op);
4122 SDValue Chain = Op.getOperand(0);
4123 SDValue RMValue = Op.getOperand(1);
4124
4125 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4126 uint64_t RM = CVal->getZExtValue();
4127 if (RM > 3) {
4129 LLVMContext &C = MF.getFunction().getContext();
4130 C.diagnose(DiagnosticInfoUnsupported(
4131 MF.getFunction(),
4132 "rounding mode is not supported by LoongArch hardware",
4133 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4134 return Chain;
4135 }
4136 }
4137
4138 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4139 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4140
4141 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4142 // into position before writing via WRFCSR.
4143 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4144 DAG.getConstant(8, DL, GRLenVT));
4145
4146 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4147 // unrelated fields in FCSR0.
4148 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4149 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4150 FCSRNo, RMValue, Chain);
4151 return SDValue(RN, 0);
4152}
4153
4154SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4155 SelectionDAG &DAG) const {
4156 MVT GRLenVT = Subtarget.getGRLenVT();
4157 SDLoc DL(Op);
4158 SDValue Chain = Op->getOperand(0);
4159
4160 // FCSR3 is an alias of the RM field.
4161 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4162 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4163 MVT::Other, FCSRNo, Chain);
4164 SDValue RMValue = SDValue(FCSR, 0);
4165 Chain = SDValue(FCSR, 1);
4166
4167 // The RM field in FCSR is at bits [9:8].
4168 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4169 DAG.getConstant(8, DL, GRLenVT));
4170 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4171
4172 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4173 return DAG.getMergeValues({RetVal, Chain}, DL);
4174}
4175
4176SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4177 SelectionDAG &DAG) const {
4178
4179 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4180 DAG.getContext()->emitError(
4181 "On LA64, only 64-bit registers can be written.");
4182 return Op.getOperand(0);
4183 }
4184
4185 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4186 DAG.getContext()->emitError(
4187 "On LA32, only 32-bit registers can be written.");
4188 return Op.getOperand(0);
4189 }
4190
4191 return Op;
4192}
4193
4194SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4195 SelectionDAG &DAG) const {
4196 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4197 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4198 "be a constant integer");
4199 return SDValue();
4200 }
4201
4204 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4205 EVT VT = Op.getValueType();
4206 SDLoc DL(Op);
4207 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4208 unsigned Depth = Op.getConstantOperandVal(0);
4209 int GRLenInBytes = Subtarget.getGRLen() / 8;
4210
4211 while (Depth--) {
4212 int Offset = -(GRLenInBytes * 2);
4213 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4214 DAG.getSignedConstant(Offset, DL, VT));
4215 FrameAddr =
4216 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4217 }
4218 return FrameAddr;
4219}
4220
4221SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4222 SelectionDAG &DAG) const {
4223 // Currently only support lowering return address for current frame.
4224 if (Op.getConstantOperandVal(0) != 0) {
4225 DAG.getContext()->emitError(
4226 "return address can only be determined for the current frame");
4227 return SDValue();
4228 }
4229
4232 MVT GRLenVT = Subtarget.getGRLenVT();
4233
4234 // Return the value of the return address register, marking it an implicit
4235 // live-in.
4236 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4237 getRegClassFor(GRLenVT));
4238 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4239}
4240
4241SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4242 SelectionDAG &DAG) const {
4244 auto Size = Subtarget.getGRLen() / 8;
4245 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4246 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4247}
4248
4249SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4250 SelectionDAG &DAG) const {
4252 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4253
4254 SDLoc DL(Op);
4255 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4257
4258 // vastart just stores the address of the VarArgsFrameIndex slot into the
4259 // memory location argument.
4260 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4261 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4262 MachinePointerInfo(SV));
4263}
4264
4265SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4266 SelectionDAG &DAG) const {
4267 SDLoc DL(Op);
4268 SDValue Op0 = Op.getOperand(0);
4269 EVT VT = Op.getValueType();
4270 EVT Op0VT = Op0.getValueType();
4271
4272 if (VT.isVector()) {
4273 if (VT.getScalarSizeInBits() != Op0VT.getScalarSizeInBits())
4274 return SDValue();
4275 return Op;
4276 }
4277
4278 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4281 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4282
4283 // We can't do uint64 -> double -> float because of double-rounding issue.
4284 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4285 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4286 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4287 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4288 DAG.getIntPtrConstant(0, DL));
4289 return Conv;
4290 }
4291
4292 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4293 return SDValue();
4294
4295 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4296 !Subtarget.hasBasicD() && "unexpected target features");
4297
4298 if (Op0->getOpcode() == ISD::AND) {
4299 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4300 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4301 return Op;
4302 }
4303
4304 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4305 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4306 Op0.getConstantOperandVal(2) == UINT64_C(0))
4307 return Op;
4308
4309 if (Op0.getOpcode() == ISD::AssertZext &&
4310 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4311 return Op;
4312
4313 EVT OpVT = Op0.getValueType();
4314 EVT RetVT = Op.getValueType();
4315 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4316 MakeLibCallOptions CallOptions;
4317 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4318 SDValue Chain = SDValue();
4319 SDValue Result;
4320 std::tie(Result, Chain) =
4321 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4322 return Result;
4323}
4324
4325SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4326 SelectionDAG &DAG) const {
4327 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4328 !Subtarget.hasBasicD() && "unexpected target features");
4329
4330 SDLoc DL(Op);
4331 SDValue Op0 = Op.getOperand(0);
4332
4333 if ((Op0.getOpcode() == ISD::AssertSext ||
4335 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4336 return Op;
4337
4338 EVT OpVT = Op0.getValueType();
4339 EVT RetVT = Op.getValueType();
4340 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4341 MakeLibCallOptions CallOptions;
4342 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4343 SDValue Chain = SDValue();
4344 SDValue Result;
4345 std::tie(Result, Chain) =
4346 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4347 return Result;
4348}
4349
4350SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4351 SelectionDAG &DAG) const {
4352
4353 SDLoc DL(Op);
4354 EVT VT = Op.getValueType();
4355 SDValue Op0 = Op.getOperand(0);
4356 EVT Op0VT = Op0.getValueType();
4357
4358 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4359 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4360 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4361 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4362 }
4363 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4364 SDValue Lo, Hi;
4365 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4366 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4367 }
4368 return Op;
4369}
4370
4371SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4372 SelectionDAG &DAG) const {
4373
4374 SDLoc DL(Op);
4375 SDValue Op0 = Op.getOperand(0);
4376
4377 if (Op0.getValueType() == MVT::f16)
4378 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4379
4380 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4381 !Subtarget.hasBasicD()) {
4382 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4383 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4384 }
4385
4386 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4387 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4388 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4389}
4390
4391// [X]VFTINTRZ and FTINTRZ saturate out-of-range values and convert NaN to 0,
4392// which is exactly the semantics of FP_TO_SINT_SAT with a native saturation
4393// width.
4394SDValue LoongArchTargetLowering::lowerFP_TO_SINT_SAT(SDValue Op,
4395 SelectionDAG &DAG) const {
4396 SDLoc DL(Op);
4397 SDValue Src = Op.getOperand(0);
4398 EVT VT = Op.getValueType();
4399 EVT SrcVT = Src.getValueType();
4400 unsigned SatWidth = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
4401
4402 // Vectors are selected by patterns.
4403 if (VT.isVector()) {
4404 if (SatWidth == VT.getScalarSizeInBits() &&
4405 SatWidth == SrcVT.getScalarSizeInBits())
4406 return Op;
4407 return SDValue();
4408 }
4409
4410 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4411 return SDValue();
4412
4413 if (SatWidth == 32) {
4414 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Src);
4415 if (Subtarget.is64Bit())
4416 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, VT, Ftint);
4417 return DAG.getBitcast(VT, Ftint);
4418 }
4419
4420 if (SatWidth == 64 && Subtarget.is64Bit() && Subtarget.hasBasicD()) {
4421 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f64, Src);
4422 return DAG.getBitcast(VT, Ftint);
4423 }
4424
4425 return SDValue();
4426}
4427
4428SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4429 SelectionDAG &DAG) const {
4430 if (!Subtarget.hasExtLSX())
4431 return SDValue();
4432
4433 SDLoc DL(Op);
4434 SDValue Src = Op.getOperand(0);
4435 EVT VT = Op.getValueType();
4436 EVT SrcVT = Src.getValueType();
4437
4438 if (VT != MVT::i64)
4439 return SDValue();
4440
4441 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4442 return SDValue();
4443
4444 if (SrcVT == MVT::f32)
4445 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4446 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4447 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4448 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4449 DAG.getIntPtrConstant(0, DL));
4450}
4451
4453 SelectionDAG &DAG, unsigned Flags) {
4454 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4455}
4456
4458 SelectionDAG &DAG, unsigned Flags) {
4459 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4460 Flags);
4461}
4462
4464 SelectionDAG &DAG, unsigned Flags) {
4465 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4466 N->getOffset(), Flags);
4467}
4468
4470 SelectionDAG &DAG, unsigned Flags) {
4471 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4472}
4473
4474template <class NodeTy>
4475SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4477 bool IsLocal) const {
4478 SDLoc DL(N);
4479 EVT Ty = getPointerTy(DAG.getDataLayout());
4480 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4481 SDValue Load;
4482
4483 switch (M) {
4484 default:
4485 report_fatal_error("Unsupported code model");
4486
4487 case CodeModel::Large: {
4488 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4489
4490 // This is not actually used, but is necessary for successfully matching
4491 // the PseudoLA_*_LARGE nodes.
4492 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4493 if (IsLocal) {
4494 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4495 // eventually becomes the desired 5-insn code sequence.
4496 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4497 Tmp, Addr),
4498 0);
4499 } else {
4500 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4501 // eventually becomes the desired 5-insn code sequence.
4502 Load = SDValue(
4503 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4504 0);
4505 }
4506 break;
4507 }
4508
4509 case CodeModel::Small:
4510 case CodeModel::Medium:
4511 if (IsLocal) {
4512 // This generates the pattern (PseudoLA_PCREL sym), which
4513 //
4514 // for la32r expands to:
4515 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4516 //
4517 // for la32s and la64 expands to:
4518 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4519 Load = SDValue(
4520 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4521 } else {
4522 // This generates the pattern (PseudoLA_GOT sym), which
4523 //
4524 // for la32r expands to:
4525 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4526 //
4527 // for la32s and la64 expands to:
4528 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4529 Load =
4530 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4531 }
4532 }
4533
4534 if (!IsLocal) {
4535 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4537 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4541 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4542 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4543 }
4544
4545 return Load;
4546}
4547
4548SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4549 SelectionDAG &DAG) const {
4550 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4551 DAG.getTarget().getCodeModel());
4552}
4553
4554SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4555 SelectionDAG &DAG) const {
4556 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4557 DAG.getTarget().getCodeModel());
4558}
4559
4560SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4561 SelectionDAG &DAG) const {
4562 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4563 DAG.getTarget().getCodeModel());
4564}
4565
4566SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4567 SelectionDAG &DAG) const {
4568 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4569 assert(N->getOffset() == 0 && "unexpected offset in global node");
4570 auto CM = DAG.getTarget().getCodeModel();
4571 const GlobalValue *GV = N->getGlobal();
4572
4573 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4574 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4575 CM = *GCM;
4576 }
4577
4578 return getAddr(N, DAG, CM, GV->isDSOLocal());
4579}
4580
4581SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4582 SelectionDAG &DAG,
4583 unsigned Opc, bool UseGOT,
4584 bool Large) const {
4585 SDLoc DL(N);
4586 EVT Ty = getPointerTy(DAG.getDataLayout());
4587 MVT GRLenVT = Subtarget.getGRLenVT();
4588
4589 // This is not actually used, but is necessary for successfully matching the
4590 // PseudoLA_*_LARGE nodes.
4591 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4592 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4593
4594 // Only IE needs an extra argument for large code model.
4595 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4596 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4597 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4598
4599 // If it is LE for normal/medium code model, the add tp operation will occur
4600 // during the pseudo-instruction expansion.
4601 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4602 return Offset;
4603
4604 if (UseGOT) {
4605 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4607 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4611 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4612 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4613 }
4614
4615 // Add the thread pointer.
4616 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4617 DAG.getRegister(LoongArch::R2, GRLenVT));
4618}
4619
4620SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4621 SelectionDAG &DAG,
4622 unsigned Opc,
4623 bool Large) const {
4624 SDLoc DL(N);
4625 EVT Ty = getPointerTy(DAG.getDataLayout());
4626 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4627
4628 // This is not actually used, but is necessary for successfully matching the
4629 // PseudoLA_*_LARGE nodes.
4630 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4631
4632 // Use a PC-relative addressing mode to access the dynamic GOT address.
4633 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4634 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4635 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4636
4637 // Prepare argument list to generate call.
4639 Args.emplace_back(Load, CallTy);
4640
4641 // Setup call to __tls_get_addr.
4642 TargetLowering::CallLoweringInfo CLI(DAG);
4643 CLI.setDebugLoc(DL)
4644 .setChain(DAG.getEntryNode())
4645 .setLibCallee(CallingConv::C, CallTy,
4646 DAG.getExternalSymbol("__tls_get_addr", Ty),
4647 std::move(Args));
4648
4649 return LowerCallTo(CLI).first;
4650}
4651
4652SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4653 SelectionDAG &DAG, unsigned Opc,
4654 bool Large) const {
4655 SDLoc DL(N);
4656 EVT Ty = getPointerTy(DAG.getDataLayout());
4657 const GlobalValue *GV = N->getGlobal();
4658
4659 // This is not actually used, but is necessary for successfully matching the
4660 // PseudoLA_*_LARGE nodes.
4661 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4662
4663 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4664 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4665 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4666 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4667 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4668}
4669
4670SDValue
4671LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4672 SelectionDAG &DAG) const {
4675 report_fatal_error("In GHC calling convention TLS is not supported");
4676
4677 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4678 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4679
4680 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4681 assert(N->getOffset() == 0 && "unexpected offset in global node");
4682
4683 if (DAG.getTarget().useEmulatedTLS())
4684 reportFatalUsageError("the emulated TLS is prohibited");
4685
4686 bool IsDesc = DAG.getTarget().useTLSDESC();
4687
4688 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4690 // In this model, application code calls the dynamic linker function
4691 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4692 // runtime.
4693 if (!IsDesc)
4694 return getDynamicTLSAddr(N, DAG,
4695 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4696 : LoongArch::PseudoLA_TLS_GD,
4697 Large);
4698 break;
4700 // Same as GeneralDynamic, except for assembly modifiers and relocation
4701 // records.
4702 if (!IsDesc)
4703 return getDynamicTLSAddr(N, DAG,
4704 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4705 : LoongArch::PseudoLA_TLS_LD,
4706 Large);
4707 break;
4709 // This model uses the GOT to resolve TLS offsets.
4710 return getStaticTLSAddr(N, DAG,
4711 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4712 : LoongArch::PseudoLA_TLS_IE,
4713 /*UseGOT=*/true, Large);
4715 // This model is used when static linking as the TLS offsets are resolved
4716 // during program linking.
4717 //
4718 // This node doesn't need an extra argument for the large code model.
4719 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4720 /*UseGOT=*/false, Large);
4721 }
4722
4723 return getTLSDescAddr(N, DAG,
4724 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4725 : LoongArch::PseudoLA_TLS_DESC,
4726 Large);
4727}
4728
4729template <unsigned N>
4731 SelectionDAG &DAG, bool IsSigned = false) {
4732 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4733 // Check the ImmArg.
4734 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4735 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4736 DAG.getContext()->emitError(Op->getOperationName(0) +
4737 ": argument out of range.");
4738 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4739 }
4740 return SDValue();
4741}
4742
4743SDValue
4744LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4745 SelectionDAG &DAG) const {
4746 switch (Op.getConstantOperandVal(0)) {
4747 default:
4748 return SDValue(); // Don't custom lower most intrinsics.
4749 case Intrinsic::thread_pointer: {
4750 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4751 return DAG.getRegister(LoongArch::R2, PtrVT);
4752 }
4753 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4754 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4755 case Intrinsic::loongarch_lsx_vreplvei_d:
4756 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4757 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4758 case Intrinsic::loongarch_lsx_vreplvei_w:
4759 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4760 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4761 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
4762 case Intrinsic::loongarch_lasx_xvpickve_d:
4763 case Intrinsic::loongarch_lasx_xvpickve_d_f:
4764 return checkIntrinsicImmArg<2>(Op, 2, DAG);
4765 case Intrinsic::loongarch_lasx_xvinsve0_d:
4766 return checkIntrinsicImmArg<2>(Op, 3, DAG);
4767 case Intrinsic::loongarch_lsx_vsat_b:
4768 case Intrinsic::loongarch_lsx_vsat_bu:
4769 case Intrinsic::loongarch_lsx_vrotri_b:
4770 case Intrinsic::loongarch_lsx_vsllwil_h_b:
4771 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
4772 case Intrinsic::loongarch_lsx_vsrlri_b:
4773 case Intrinsic::loongarch_lsx_vsrari_b:
4774 case Intrinsic::loongarch_lsx_vreplvei_h:
4775 case Intrinsic::loongarch_lasx_xvsat_b:
4776 case Intrinsic::loongarch_lasx_xvsat_bu:
4777 case Intrinsic::loongarch_lasx_xvrotri_b:
4778 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
4779 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
4780 case Intrinsic::loongarch_lasx_xvsrlri_b:
4781 case Intrinsic::loongarch_lasx_xvsrari_b:
4782 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
4783 case Intrinsic::loongarch_lasx_xvpickve_w:
4784 case Intrinsic::loongarch_lasx_xvpickve_w_f:
4785 return checkIntrinsicImmArg<3>(Op, 2, DAG);
4786 case Intrinsic::loongarch_lasx_xvinsve0_w:
4787 return checkIntrinsicImmArg<3>(Op, 3, DAG);
4788 case Intrinsic::loongarch_lsx_vsat_h:
4789 case Intrinsic::loongarch_lsx_vsat_hu:
4790 case Intrinsic::loongarch_lsx_vrotri_h:
4791 case Intrinsic::loongarch_lsx_vsllwil_w_h:
4792 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
4793 case Intrinsic::loongarch_lsx_vsrlri_h:
4794 case Intrinsic::loongarch_lsx_vsrari_h:
4795 case Intrinsic::loongarch_lsx_vreplvei_b:
4796 case Intrinsic::loongarch_lasx_xvsat_h:
4797 case Intrinsic::loongarch_lasx_xvsat_hu:
4798 case Intrinsic::loongarch_lasx_xvrotri_h:
4799 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
4800 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
4801 case Intrinsic::loongarch_lasx_xvsrlri_h:
4802 case Intrinsic::loongarch_lasx_xvsrari_h:
4803 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
4804 return checkIntrinsicImmArg<4>(Op, 2, DAG);
4805 case Intrinsic::loongarch_lsx_vsrlni_b_h:
4806 case Intrinsic::loongarch_lsx_vsrani_b_h:
4807 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
4808 case Intrinsic::loongarch_lsx_vsrarni_b_h:
4809 case Intrinsic::loongarch_lsx_vssrlni_b_h:
4810 case Intrinsic::loongarch_lsx_vssrani_b_h:
4811 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
4812 case Intrinsic::loongarch_lsx_vssrani_bu_h:
4813 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
4814 case Intrinsic::loongarch_lsx_vssrarni_b_h:
4815 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
4816 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
4817 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
4818 case Intrinsic::loongarch_lasx_xvsrani_b_h:
4819 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
4820 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
4821 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
4822 case Intrinsic::loongarch_lasx_xvssrani_b_h:
4823 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
4824 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
4825 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
4826 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
4827 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
4828 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
4829 return checkIntrinsicImmArg<4>(Op, 3, DAG);
4830 case Intrinsic::loongarch_lsx_vsat_w:
4831 case Intrinsic::loongarch_lsx_vsat_wu:
4832 case Intrinsic::loongarch_lsx_vrotri_w:
4833 case Intrinsic::loongarch_lsx_vsllwil_d_w:
4834 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
4835 case Intrinsic::loongarch_lsx_vsrlri_w:
4836 case Intrinsic::loongarch_lsx_vsrari_w:
4837 case Intrinsic::loongarch_lsx_vslei_bu:
4838 case Intrinsic::loongarch_lsx_vslei_hu:
4839 case Intrinsic::loongarch_lsx_vslei_wu:
4840 case Intrinsic::loongarch_lsx_vslei_du:
4841 case Intrinsic::loongarch_lsx_vslti_bu:
4842 case Intrinsic::loongarch_lsx_vslti_hu:
4843 case Intrinsic::loongarch_lsx_vslti_wu:
4844 case Intrinsic::loongarch_lsx_vslti_du:
4845 case Intrinsic::loongarch_lsx_vbsll_v:
4846 case Intrinsic::loongarch_lsx_vbsrl_v:
4847 case Intrinsic::loongarch_lasx_xvsat_w:
4848 case Intrinsic::loongarch_lasx_xvsat_wu:
4849 case Intrinsic::loongarch_lasx_xvrotri_w:
4850 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
4851 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
4852 case Intrinsic::loongarch_lasx_xvsrlri_w:
4853 case Intrinsic::loongarch_lasx_xvsrari_w:
4854 case Intrinsic::loongarch_lasx_xvslei_bu:
4855 case Intrinsic::loongarch_lasx_xvslei_hu:
4856 case Intrinsic::loongarch_lasx_xvslei_wu:
4857 case Intrinsic::loongarch_lasx_xvslei_du:
4858 case Intrinsic::loongarch_lasx_xvslti_bu:
4859 case Intrinsic::loongarch_lasx_xvslti_hu:
4860 case Intrinsic::loongarch_lasx_xvslti_wu:
4861 case Intrinsic::loongarch_lasx_xvslti_du:
4862 case Intrinsic::loongarch_lasx_xvbsll_v:
4863 case Intrinsic::loongarch_lasx_xvbsrl_v:
4864 return checkIntrinsicImmArg<5>(Op, 2, DAG);
4865 case Intrinsic::loongarch_lsx_vseqi_b:
4866 case Intrinsic::loongarch_lsx_vseqi_h:
4867 case Intrinsic::loongarch_lsx_vseqi_w:
4868 case Intrinsic::loongarch_lsx_vseqi_d:
4869 case Intrinsic::loongarch_lsx_vslei_b:
4870 case Intrinsic::loongarch_lsx_vslei_h:
4871 case Intrinsic::loongarch_lsx_vslei_w:
4872 case Intrinsic::loongarch_lsx_vslei_d:
4873 case Intrinsic::loongarch_lsx_vslti_b:
4874 case Intrinsic::loongarch_lsx_vslti_h:
4875 case Intrinsic::loongarch_lsx_vslti_w:
4876 case Intrinsic::loongarch_lsx_vslti_d:
4877 case Intrinsic::loongarch_lasx_xvseqi_b:
4878 case Intrinsic::loongarch_lasx_xvseqi_h:
4879 case Intrinsic::loongarch_lasx_xvseqi_w:
4880 case Intrinsic::loongarch_lasx_xvseqi_d:
4881 case Intrinsic::loongarch_lasx_xvslei_b:
4882 case Intrinsic::loongarch_lasx_xvslei_h:
4883 case Intrinsic::loongarch_lasx_xvslei_w:
4884 case Intrinsic::loongarch_lasx_xvslei_d:
4885 case Intrinsic::loongarch_lasx_xvslti_b:
4886 case Intrinsic::loongarch_lasx_xvslti_h:
4887 case Intrinsic::loongarch_lasx_xvslti_w:
4888 case Intrinsic::loongarch_lasx_xvslti_d:
4889 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
4890 case Intrinsic::loongarch_lsx_vsrlni_h_w:
4891 case Intrinsic::loongarch_lsx_vsrani_h_w:
4892 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
4893 case Intrinsic::loongarch_lsx_vsrarni_h_w:
4894 case Intrinsic::loongarch_lsx_vssrlni_h_w:
4895 case Intrinsic::loongarch_lsx_vssrani_h_w:
4896 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
4897 case Intrinsic::loongarch_lsx_vssrani_hu_w:
4898 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
4899 case Intrinsic::loongarch_lsx_vssrarni_h_w:
4900 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
4901 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
4902 case Intrinsic::loongarch_lsx_vfrstpi_b:
4903 case Intrinsic::loongarch_lsx_vfrstpi_h:
4904 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
4905 case Intrinsic::loongarch_lasx_xvsrani_h_w:
4906 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
4907 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
4908 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
4909 case Intrinsic::loongarch_lasx_xvssrani_h_w:
4910 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
4911 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
4912 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
4913 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
4914 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
4915 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
4916 case Intrinsic::loongarch_lasx_xvfrstpi_b:
4917 case Intrinsic::loongarch_lasx_xvfrstpi_h:
4918 return checkIntrinsicImmArg<5>(Op, 3, DAG);
4919 case Intrinsic::loongarch_lsx_vsat_d:
4920 case Intrinsic::loongarch_lsx_vsat_du:
4921 case Intrinsic::loongarch_lsx_vrotri_d:
4922 case Intrinsic::loongarch_lsx_vsrlri_d:
4923 case Intrinsic::loongarch_lsx_vsrari_d:
4924 case Intrinsic::loongarch_lasx_xvsat_d:
4925 case Intrinsic::loongarch_lasx_xvsat_du:
4926 case Intrinsic::loongarch_lasx_xvrotri_d:
4927 case Intrinsic::loongarch_lasx_xvsrlri_d:
4928 case Intrinsic::loongarch_lasx_xvsrari_d:
4929 return checkIntrinsicImmArg<6>(Op, 2, DAG);
4930 case Intrinsic::loongarch_lsx_vsrlni_w_d:
4931 case Intrinsic::loongarch_lsx_vsrani_w_d:
4932 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
4933 case Intrinsic::loongarch_lsx_vsrarni_w_d:
4934 case Intrinsic::loongarch_lsx_vssrlni_w_d:
4935 case Intrinsic::loongarch_lsx_vssrani_w_d:
4936 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
4937 case Intrinsic::loongarch_lsx_vssrani_wu_d:
4938 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
4939 case Intrinsic::loongarch_lsx_vssrarni_w_d:
4940 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
4941 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
4942 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
4943 case Intrinsic::loongarch_lasx_xvsrani_w_d:
4944 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
4945 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
4946 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
4947 case Intrinsic::loongarch_lasx_xvssrani_w_d:
4948 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
4949 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
4950 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
4951 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
4952 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
4953 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
4954 return checkIntrinsicImmArg<6>(Op, 3, DAG);
4955 case Intrinsic::loongarch_lsx_vsrlni_d_q:
4956 case Intrinsic::loongarch_lsx_vsrani_d_q:
4957 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
4958 case Intrinsic::loongarch_lsx_vsrarni_d_q:
4959 case Intrinsic::loongarch_lsx_vssrlni_d_q:
4960 case Intrinsic::loongarch_lsx_vssrani_d_q:
4961 case Intrinsic::loongarch_lsx_vssrlni_du_q:
4962 case Intrinsic::loongarch_lsx_vssrani_du_q:
4963 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
4964 case Intrinsic::loongarch_lsx_vssrarni_d_q:
4965 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
4966 case Intrinsic::loongarch_lsx_vssrarni_du_q:
4967 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
4968 case Intrinsic::loongarch_lasx_xvsrani_d_q:
4969 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
4970 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
4971 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
4972 case Intrinsic::loongarch_lasx_xvssrani_d_q:
4973 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
4974 case Intrinsic::loongarch_lasx_xvssrani_du_q:
4975 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
4976 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
4977 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
4978 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
4979 return checkIntrinsicImmArg<7>(Op, 3, DAG);
4980 case Intrinsic::loongarch_lsx_vnori_b:
4981 case Intrinsic::loongarch_lsx_vshuf4i_b:
4982 case Intrinsic::loongarch_lsx_vshuf4i_h:
4983 case Intrinsic::loongarch_lsx_vshuf4i_w:
4984 case Intrinsic::loongarch_lasx_xvnori_b:
4985 case Intrinsic::loongarch_lasx_xvshuf4i_b:
4986 case Intrinsic::loongarch_lasx_xvshuf4i_h:
4987 case Intrinsic::loongarch_lasx_xvshuf4i_w:
4988 case Intrinsic::loongarch_lasx_xvpermi_d:
4989 return checkIntrinsicImmArg<8>(Op, 2, DAG);
4990 case Intrinsic::loongarch_lsx_vshuf4i_d:
4991 case Intrinsic::loongarch_lsx_vpermi_w:
4992 case Intrinsic::loongarch_lsx_vbitseli_b:
4993 case Intrinsic::loongarch_lsx_vextrins_b:
4994 case Intrinsic::loongarch_lsx_vextrins_h:
4995 case Intrinsic::loongarch_lsx_vextrins_w:
4996 case Intrinsic::loongarch_lsx_vextrins_d:
4997 case Intrinsic::loongarch_lasx_xvshuf4i_d:
4998 case Intrinsic::loongarch_lasx_xvpermi_w:
4999 case Intrinsic::loongarch_lasx_xvpermi_q:
5000 case Intrinsic::loongarch_lasx_xvbitseli_b:
5001 case Intrinsic::loongarch_lasx_xvextrins_b:
5002 case Intrinsic::loongarch_lasx_xvextrins_h:
5003 case Intrinsic::loongarch_lasx_xvextrins_w:
5004 case Intrinsic::loongarch_lasx_xvextrins_d:
5005 return checkIntrinsicImmArg<8>(Op, 3, DAG);
5006 case Intrinsic::loongarch_lsx_vrepli_b:
5007 case Intrinsic::loongarch_lsx_vrepli_h:
5008 case Intrinsic::loongarch_lsx_vrepli_w:
5009 case Intrinsic::loongarch_lsx_vrepli_d:
5010 case Intrinsic::loongarch_lasx_xvrepli_b:
5011 case Intrinsic::loongarch_lasx_xvrepli_h:
5012 case Intrinsic::loongarch_lasx_xvrepli_w:
5013 case Intrinsic::loongarch_lasx_xvrepli_d:
5014 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
5015 case Intrinsic::loongarch_lsx_vldi:
5016 case Intrinsic::loongarch_lasx_xvldi:
5017 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
5018 }
5019}
5020
5021// Helper function that emits error message for intrinsics with chain and return
5022// merge values of a UNDEF and the chain.
5024 StringRef ErrorMsg,
5025 SelectionDAG &DAG) {
5026 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5027 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
5028 SDLoc(Op));
5029}
5030
5031SDValue
5032LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
5033 SelectionDAG &DAG) const {
5034 SDLoc DL(Op);
5035 MVT GRLenVT = Subtarget.getGRLenVT();
5036 EVT VT = Op.getValueType();
5037 SDValue Chain = Op.getOperand(0);
5038 const StringRef ErrorMsgOOR = "argument out of range";
5039 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5040 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5041
5042 switch (Op.getConstantOperandVal(1)) {
5043 default:
5044 return Op;
5045 case Intrinsic::loongarch_crc_w_b_w:
5046 case Intrinsic::loongarch_crc_w_h_w:
5047 case Intrinsic::loongarch_crc_w_w_w:
5048 case Intrinsic::loongarch_crc_w_d_w:
5049 case Intrinsic::loongarch_crcc_w_b_w:
5050 case Intrinsic::loongarch_crcc_w_h_w:
5051 case Intrinsic::loongarch_crcc_w_w_w:
5052 case Intrinsic::loongarch_crcc_w_d_w:
5053 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
5054 case Intrinsic::loongarch_csrrd_w:
5055 case Intrinsic::loongarch_csrrd_d: {
5056 unsigned Imm = Op.getConstantOperandVal(2);
5057 return !isUInt<14>(Imm)
5058 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5059 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5060 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5061 }
5062 case Intrinsic::loongarch_csrwr_w:
5063 case Intrinsic::loongarch_csrwr_d: {
5064 unsigned Imm = Op.getConstantOperandVal(3);
5065 return !isUInt<14>(Imm)
5066 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5067 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5068 {Chain, Op.getOperand(2),
5069 DAG.getConstant(Imm, DL, GRLenVT)});
5070 }
5071 case Intrinsic::loongarch_csrxchg_w:
5072 case Intrinsic::loongarch_csrxchg_d: {
5073 unsigned Imm = Op.getConstantOperandVal(4);
5074 return !isUInt<14>(Imm)
5075 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5076 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5077 {Chain, Op.getOperand(2), Op.getOperand(3),
5078 DAG.getConstant(Imm, DL, GRLenVT)});
5079 }
5080 case Intrinsic::loongarch_iocsrrd_d: {
5081 return DAG.getNode(
5082 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5083 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5084 }
5085#define IOCSRRD_CASE(NAME, NODE) \
5086 case Intrinsic::loongarch_##NAME: { \
5087 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5088 {Chain, Op.getOperand(2)}); \
5089 }
5090 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5091 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5092 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5093#undef IOCSRRD_CASE
5094 case Intrinsic::loongarch_cpucfg: {
5095 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5096 {Chain, Op.getOperand(2)});
5097 }
5098 case Intrinsic::loongarch_lddir_d: {
5099 unsigned Imm = Op.getConstantOperandVal(3);
5100 return !isUInt<8>(Imm)
5101 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5102 : Op;
5103 }
5104 case Intrinsic::loongarch_movfcsr2gr: {
5105 if (!Subtarget.hasBasicF())
5106 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5107 unsigned Imm = Op.getConstantOperandVal(2);
5108 return !isUInt<2>(Imm)
5109 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5110 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5111 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5112 }
5113 case Intrinsic::loongarch_lsx_vld:
5114 case Intrinsic::loongarch_lsx_vldrepl_b:
5115 case Intrinsic::loongarch_lasx_xvld:
5116 case Intrinsic::loongarch_lasx_xvldrepl_b:
5117 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5118 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5119 : SDValue();
5120 case Intrinsic::loongarch_lsx_vldrepl_h:
5121 case Intrinsic::loongarch_lasx_xvldrepl_h:
5122 return !isShiftedInt<11, 1>(
5123 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5125 Op, "argument out of range or not a multiple of 2", DAG)
5126 : SDValue();
5127 case Intrinsic::loongarch_lsx_vldrepl_w:
5128 case Intrinsic::loongarch_lasx_xvldrepl_w:
5129 return !isShiftedInt<10, 2>(
5130 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5132 Op, "argument out of range or not a multiple of 4", DAG)
5133 : SDValue();
5134 case Intrinsic::loongarch_lsx_vldrepl_d:
5135 case Intrinsic::loongarch_lasx_xvldrepl_d:
5136 return !isShiftedInt<9, 3>(
5137 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5139 Op, "argument out of range or not a multiple of 8", DAG)
5140 : SDValue();
5141 }
5142}
5143
5144// Helper function that emits error message for intrinsics with void return
5145// value and return the chain.
5147 SelectionDAG &DAG) {
5148
5149 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5150 return Op.getOperand(0);
5151}
5152
5153SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5154 SelectionDAG &DAG) const {
5155 SDLoc DL(Op);
5156 MVT GRLenVT = Subtarget.getGRLenVT();
5157 SDValue Chain = Op.getOperand(0);
5158 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5159 SDValue Op2 = Op.getOperand(2);
5160 const StringRef ErrorMsgOOR = "argument out of range";
5161 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5162 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5163 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5164
5165 switch (IntrinsicEnum) {
5166 default:
5167 // TODO: Add more Intrinsics.
5168 return SDValue();
5169 case Intrinsic::loongarch_cacop_d:
5170 case Intrinsic::loongarch_cacop_w: {
5171 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5172 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5173 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5174 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5175 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5176 unsigned Imm1 = Op2->getAsZExtVal();
5177 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5178 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5179 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5180 return Op;
5181 }
5182 case Intrinsic::loongarch_dbar: {
5183 unsigned Imm = Op2->getAsZExtVal();
5184 return !isUInt<15>(Imm)
5185 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5186 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5187 DAG.getConstant(Imm, DL, GRLenVT));
5188 }
5189 case Intrinsic::loongarch_ibar: {
5190 unsigned Imm = Op2->getAsZExtVal();
5191 return !isUInt<15>(Imm)
5192 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5193 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5194 DAG.getConstant(Imm, DL, GRLenVT));
5195 }
5196 case Intrinsic::loongarch_break: {
5197 unsigned Imm = Op2->getAsZExtVal();
5198 return !isUInt<15>(Imm)
5199 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5200 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5201 DAG.getConstant(Imm, DL, GRLenVT));
5202 }
5203 case Intrinsic::loongarch_movgr2fcsr: {
5204 if (!Subtarget.hasBasicF())
5205 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5206 unsigned Imm = Op2->getAsZExtVal();
5207 return !isUInt<2>(Imm)
5208 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5209 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5210 DAG.getConstant(Imm, DL, GRLenVT),
5211 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5212 Op.getOperand(3)));
5213 }
5214 case Intrinsic::loongarch_syscall: {
5215 unsigned Imm = Op2->getAsZExtVal();
5216 return !isUInt<15>(Imm)
5217 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5218 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5219 DAG.getConstant(Imm, DL, GRLenVT));
5220 }
5221#define IOCSRWR_CASE(NAME, NODE) \
5222 case Intrinsic::loongarch_##NAME: { \
5223 SDValue Op3 = Op.getOperand(3); \
5224 return Subtarget.is64Bit() \
5225 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5226 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5227 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5228 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5229 Op3); \
5230 }
5231 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5232 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5233 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5234#undef IOCSRWR_CASE
5235 case Intrinsic::loongarch_iocsrwr_d: {
5236 return !Subtarget.is64Bit()
5237 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5238 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5239 Op2,
5240 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5241 Op.getOperand(3)));
5242 }
5243#define ASRT_LE_GT_CASE(NAME) \
5244 case Intrinsic::loongarch_##NAME: { \
5245 return !Subtarget.is64Bit() \
5246 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5247 : Op; \
5248 }
5249 ASRT_LE_GT_CASE(asrtle_d)
5250 ASRT_LE_GT_CASE(asrtgt_d)
5251#undef ASRT_LE_GT_CASE
5252 case Intrinsic::loongarch_ldpte_d: {
5253 unsigned Imm = Op.getConstantOperandVal(3);
5254 return !Subtarget.is64Bit()
5255 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5256 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5257 : Op;
5258 }
5259 case Intrinsic::loongarch_lsx_vst:
5260 case Intrinsic::loongarch_lasx_xvst:
5261 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5262 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5263 : SDValue();
5264 case Intrinsic::loongarch_lasx_xvstelm_b:
5265 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5266 !isUInt<5>(Op.getConstantOperandVal(5)))
5267 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5268 : SDValue();
5269 case Intrinsic::loongarch_lsx_vstelm_b:
5270 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5271 !isUInt<4>(Op.getConstantOperandVal(5)))
5272 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5273 : SDValue();
5274 case Intrinsic::loongarch_lasx_xvstelm_h:
5275 return (!isShiftedInt<8, 1>(
5276 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5277 !isUInt<4>(Op.getConstantOperandVal(5)))
5279 Op, "argument out of range or not a multiple of 2", DAG)
5280 : SDValue();
5281 case Intrinsic::loongarch_lsx_vstelm_h:
5282 return (!isShiftedInt<8, 1>(
5283 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5284 !isUInt<3>(Op.getConstantOperandVal(5)))
5286 Op, "argument out of range or not a multiple of 2", DAG)
5287 : SDValue();
5288 case Intrinsic::loongarch_lasx_xvstelm_w:
5289 return (!isShiftedInt<8, 2>(
5290 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5291 !isUInt<3>(Op.getConstantOperandVal(5)))
5293 Op, "argument out of range or not a multiple of 4", DAG)
5294 : SDValue();
5295 case Intrinsic::loongarch_lsx_vstelm_w:
5296 return (!isShiftedInt<8, 2>(
5297 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5298 !isUInt<2>(Op.getConstantOperandVal(5)))
5300 Op, "argument out of range or not a multiple of 4", DAG)
5301 : SDValue();
5302 case Intrinsic::loongarch_lasx_xvstelm_d:
5303 return (!isShiftedInt<8, 3>(
5304 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5305 !isUInt<2>(Op.getConstantOperandVal(5)))
5307 Op, "argument out of range or not a multiple of 8", DAG)
5308 : SDValue();
5309 case Intrinsic::loongarch_lsx_vstelm_d:
5310 return (!isShiftedInt<8, 3>(
5311 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5312 !isUInt<1>(Op.getConstantOperandVal(5)))
5314 Op, "argument out of range or not a multiple of 8", DAG)
5315 : SDValue();
5316 }
5317}
5318
5319SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5320 SelectionDAG &DAG) const {
5321 SDLoc DL(Op);
5322 SDValue Lo = Op.getOperand(0);
5323 SDValue Hi = Op.getOperand(1);
5324 SDValue Shamt = Op.getOperand(2);
5325 EVT VT = Lo.getValueType();
5326
5327 // if Shamt-GRLen < 0: // Shamt < GRLen
5328 // Lo = Lo << Shamt
5329 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5330 // else:
5331 // Lo = 0
5332 // Hi = Lo << (Shamt-GRLen)
5333
5334 SDValue Zero = DAG.getConstant(0, DL, VT);
5335 SDValue One = DAG.getConstant(1, DL, VT);
5336 SDValue MinusGRLen =
5337 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5338 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5339 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5340 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5341
5342 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5343 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5344 SDValue ShiftRightLo =
5345 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5346 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5347 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5348 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5349
5350 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5351
5352 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5353 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5354
5355 SDValue Parts[2] = {Lo, Hi};
5356 return DAG.getMergeValues(Parts, DL);
5357}
5358
5359SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5360 SelectionDAG &DAG,
5361 bool IsSRA) const {
5362 SDLoc DL(Op);
5363 SDValue Lo = Op.getOperand(0);
5364 SDValue Hi = Op.getOperand(1);
5365 SDValue Shamt = Op.getOperand(2);
5366 EVT VT = Lo.getValueType();
5367
5368 // SRA expansion:
5369 // if Shamt-GRLen < 0: // Shamt < GRLen
5370 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5371 // Hi = Hi >>s Shamt
5372 // else:
5373 // Lo = Hi >>s (Shamt-GRLen);
5374 // Hi = Hi >>s (GRLen-1)
5375 //
5376 // SRL expansion:
5377 // if Shamt-GRLen < 0: // Shamt < GRLen
5378 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5379 // Hi = Hi >>u Shamt
5380 // else:
5381 // Lo = Hi >>u (Shamt-GRLen);
5382 // Hi = 0;
5383
5384 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5385
5386 SDValue Zero = DAG.getConstant(0, DL, VT);
5387 SDValue One = DAG.getConstant(1, DL, VT);
5388 SDValue MinusGRLen =
5389 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5390 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5391 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5392 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5393
5394 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5395 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5396 SDValue ShiftLeftHi =
5397 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5398 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5399 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5400 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5401 SDValue HiFalse =
5402 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5403
5404 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5405
5406 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5407 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5408
5409 SDValue Parts[2] = {Lo, Hi};
5410 return DAG.getMergeValues(Parts, DL);
5411}
5412
5413// Returns the opcode of the target-specific SDNode that implements the 32-bit
5414// form of the given Opcode.
5415static unsigned getLoongArchWOpcode(unsigned Opcode) {
5416 switch (Opcode) {
5417 default:
5418 llvm_unreachable("Unexpected opcode");
5419 case ISD::SDIV:
5420 return LoongArchISD::DIV_W;
5421 case ISD::UDIV:
5422 return LoongArchISD::DIV_WU;
5423 case ISD::SREM:
5424 return LoongArchISD::MOD_W;
5425 case ISD::UREM:
5426 return LoongArchISD::MOD_WU;
5427 case ISD::SHL:
5428 return LoongArchISD::SLL_W;
5429 case ISD::SRA:
5430 return LoongArchISD::SRA_W;
5431 case ISD::SRL:
5432 return LoongArchISD::SRL_W;
5433 case ISD::ROTL:
5434 case ISD::ROTR:
5435 return LoongArchISD::ROTR_W;
5436 case ISD::CTTZ:
5437 return LoongArchISD::CTZ_W;
5438 case ISD::CTLZ:
5439 return LoongArchISD::CLZ_W;
5440 }
5441}
5442
5443// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5444// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5445// otherwise be promoted to i64, making it difficult to select the
5446// SLL_W/.../*W later one because the fact the operation was originally of
5447// type i8/i16/i32 is lost.
5449 unsigned ExtOpc = ISD::ANY_EXTEND) {
5450 SDLoc DL(N);
5451 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5452 SDValue NewOp0, NewRes;
5453
5454 switch (NumOp) {
5455 default:
5456 llvm_unreachable("Unexpected NumOp");
5457 case 1: {
5458 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5459 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5460 break;
5461 }
5462 case 2: {
5463 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5464 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5465 if (N->getOpcode() == ISD::ROTL) {
5466 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5467 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5468 }
5469 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5470 break;
5471 }
5472 // TODO:Handle more NumOp.
5473 }
5474
5475 // ReplaceNodeResults requires we maintain the same type for the return
5476 // value.
5477 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5478}
5479
5480// Converts the given 32-bit operation to a i64 operation with signed extension
5481// semantic to reduce the signed extension instructions.
5483 SDLoc DL(N);
5484 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5485 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5486 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5487 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5488 DAG.getValueType(MVT::i32));
5489 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5490}
5491
5492// Helper function that emits error message for intrinsics with/without chain
5493// and return a UNDEF or and the chain as the results.
5496 StringRef ErrorMsg, bool WithChain = true) {
5497 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5498 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5499 if (!WithChain)
5500 return;
5501 Results.push_back(N->getOperand(0));
5502}
5503
5504template <unsigned N>
5505static void
5507 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
5508 unsigned ResOp) {
5509 const StringRef ErrorMsgOOR = "argument out of range";
5510 unsigned Imm = Node->getConstantOperandVal(2);
5511 if (!isUInt<N>(Imm)) {
5513 /*WithChain=*/false);
5514 return;
5515 }
5516 SDLoc DL(Node);
5517 SDValue Vec = Node->getOperand(1);
5518
5519 SDValue PickElt =
5520 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5521 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5523 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5524 PickElt.getValue(0)));
5525}
5526
5529 SelectionDAG &DAG,
5530 const LoongArchSubtarget &Subtarget,
5531 unsigned ResOp) {
5532 SDLoc DL(N);
5533 SDValue Vec = N->getOperand(1);
5534
5535 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5536 Results.push_back(
5537 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5538}
5539
5540static void
5542 SelectionDAG &DAG,
5543 const LoongArchSubtarget &Subtarget) {
5544 switch (N->getConstantOperandVal(0)) {
5545 default:
5546 llvm_unreachable("Unexpected Intrinsic.");
5547 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5548 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5549 LoongArchISD::VPICK_SEXT_ELT);
5550 break;
5551 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5552 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5553 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5554 LoongArchISD::VPICK_SEXT_ELT);
5555 break;
5556 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5557 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5558 LoongArchISD::VPICK_SEXT_ELT);
5559 break;
5560 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5561 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5562 LoongArchISD::VPICK_ZEXT_ELT);
5563 break;
5564 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5565 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5566 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5567 LoongArchISD::VPICK_ZEXT_ELT);
5568 break;
5569 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5570 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5571 LoongArchISD::VPICK_ZEXT_ELT);
5572 break;
5573 case Intrinsic::loongarch_lsx_bz_b:
5574 case Intrinsic::loongarch_lsx_bz_h:
5575 case Intrinsic::loongarch_lsx_bz_w:
5576 case Intrinsic::loongarch_lsx_bz_d:
5577 case Intrinsic::loongarch_lasx_xbz_b:
5578 case Intrinsic::loongarch_lasx_xbz_h:
5579 case Intrinsic::loongarch_lasx_xbz_w:
5580 case Intrinsic::loongarch_lasx_xbz_d:
5581 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5582 LoongArchISD::VALL_ZERO);
5583 break;
5584 case Intrinsic::loongarch_lsx_bz_v:
5585 case Intrinsic::loongarch_lasx_xbz_v:
5586 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5587 LoongArchISD::VANY_ZERO);
5588 break;
5589 case Intrinsic::loongarch_lsx_bnz_b:
5590 case Intrinsic::loongarch_lsx_bnz_h:
5591 case Intrinsic::loongarch_lsx_bnz_w:
5592 case Intrinsic::loongarch_lsx_bnz_d:
5593 case Intrinsic::loongarch_lasx_xbnz_b:
5594 case Intrinsic::loongarch_lasx_xbnz_h:
5595 case Intrinsic::loongarch_lasx_xbnz_w:
5596 case Intrinsic::loongarch_lasx_xbnz_d:
5597 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5598 LoongArchISD::VALL_NONZERO);
5599 break;
5600 case Intrinsic::loongarch_lsx_bnz_v:
5601 case Intrinsic::loongarch_lasx_xbnz_v:
5602 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5603 LoongArchISD::VANY_NONZERO);
5604 break;
5605 }
5606}
5607
5610 SelectionDAG &DAG) {
5611 assert(N->getValueType(0) == MVT::i128 &&
5612 "AtomicCmpSwap on types less than 128 should be legal");
5613 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5614
5615 unsigned Opcode;
5616 switch (MemOp->getMergedOrdering()) {
5620 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5621 break;
5624 Opcode = LoongArch::PseudoCmpXchg128;
5625 break;
5626 default:
5627 llvm_unreachable("Unexpected ordering!");
5628 }
5629
5630 SDLoc DL(N);
5631 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5632 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5633 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5634 NewVal.first, NewVal.second, N->getOperand(0)};
5635
5636 SDNode *CmpSwap = DAG.getMachineNode(
5637 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5638 Ops);
5639 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5640 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5641 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5642 Results.push_back(SDValue(CmpSwap, 3));
5643}
5644
5647 SDLoc DL(N);
5648 EVT VT = N->getValueType(0);
5649 switch (N->getOpcode()) {
5650 default:
5651 llvm_unreachable("Don't know how to legalize this operation");
5652 case ISD::ADD:
5653 case ISD::SUB:
5654 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5655 "Unexpected custom legalisation");
5656 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5657 break;
5658 case ISD::SDIV:
5659 case ISD::UDIV:
5660 case ISD::SREM:
5661 case ISD::UREM:
5662 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5663 "Unexpected custom legalisation");
5664 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5665 Subtarget.hasDiv32() && VT == MVT::i32
5667 : ISD::SIGN_EXTEND));
5668 break;
5669 case ISD::SHL:
5670 case ISD::SRA:
5671 case ISD::SRL:
5672 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5673 "Unexpected custom legalisation");
5674 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5675 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5676 break;
5677 }
5678 break;
5679 case ISD::ROTL:
5680 case ISD::ROTR:
5681 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5682 "Unexpected custom legalisation");
5683 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5684 break;
5685 case ISD::LOAD: {
5686 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5687 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5688 // cast since type legalization will try to use an i64 load.
5689 MVT VT = N->getSimpleValueType(0);
5690 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5691 "Unexpected custom legalisation");
5693 "Unexpected type action!");
5694 if (!ISD::isNON_EXTLoad(N))
5695 return;
5696 auto *Ld = cast<LoadSDNode>(N);
5697 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5698 Ld->getPointerInfo(), Ld->getBaseAlign(),
5699 Ld->getMemOperand()->getFlags());
5700 SDValue Chain = Res.getValue(1);
5701 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5702 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5703 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5704 Res = DAG.getBitcast(WideVT, Res);
5705 Results.push_back(Res);
5706 Results.push_back(Chain);
5707 break;
5708 }
5709 case ISD::FP_TO_SINT: {
5710 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5711 "Unexpected custom legalisation");
5712 SDValue Src = N->getOperand(0);
5713 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5714 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5716 if (!isTypeLegal(Src.getValueType()))
5717 return;
5718 if (Src.getValueType() == MVT::f16)
5719 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5720 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5721 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5722 return;
5723 }
5724 // If the FP type needs to be softened, emit a library call using the 'si'
5725 // version. If we left it to default legalization we'd end up with 'di'.
5726 RTLIB::Libcall LC;
5727 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5728 MakeLibCallOptions CallOptions;
5729 EVT OpVT = Src.getValueType();
5730 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5731 SDValue Chain = SDValue();
5732 SDValue Result;
5733 std::tie(Result, Chain) =
5734 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5735 Results.push_back(Result);
5736 break;
5737 }
5738 case ISD::BITCAST: {
5739 SDValue Src = N->getOperand(0);
5740 EVT SrcVT = Src.getValueType();
5741 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5742 Subtarget.hasBasicF()) {
5743 SDValue Dst =
5744 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5745 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5746 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5747 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5748 DAG.getVTList(MVT::i32, MVT::i32), Src);
5749 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5750 NewReg.getValue(0), NewReg.getValue(1));
5751 Results.push_back(RetReg);
5752 }
5753 break;
5754 }
5755 case ISD::FP_TO_UINT: {
5756 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5757 "Unexpected custom legalisation");
5758 auto &TLI = DAG.getTargetLoweringInfo();
5759 SDValue Tmp1, Tmp2;
5760 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5761 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
5762 break;
5763 }
5764 case ISD::FP_ROUND: {
5765 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5766 "Unexpected custom legalisation");
5767 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
5768 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
5769 // a target-specific LoongArchISD::VFCVT to optimize it.
5770 SDValue Op0 = N->getOperand(0);
5771 EVT OpVT = Op0.getValueType();
5772 if (OpVT == MVT::v2f64) {
5773 SDValue Undef = DAG.getUNDEF(OpVT);
5774 SDValue Dst =
5775 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
5776 Results.push_back(Dst);
5777 }
5778 break;
5779 }
5780 case ISD::BSWAP: {
5781 SDValue Src = N->getOperand(0);
5782 assert((VT == MVT::i16 || VT == MVT::i32) &&
5783 "Unexpected custom legalization");
5784 MVT GRLenVT = Subtarget.getGRLenVT();
5785 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5786 SDValue Tmp;
5787 switch (VT.getSizeInBits()) {
5788 default:
5789 llvm_unreachable("Unexpected operand width");
5790 case 16:
5791 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
5792 break;
5793 case 32:
5794 // Only LA64 will get to here due to the size mismatch between VT and
5795 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
5796 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
5797 break;
5798 }
5799 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5800 break;
5801 }
5802 case ISD::BITREVERSE: {
5803 SDValue Src = N->getOperand(0);
5804 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
5805 "Unexpected custom legalization");
5806 MVT GRLenVT = Subtarget.getGRLenVT();
5807 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5808 SDValue Tmp;
5809 switch (VT.getSizeInBits()) {
5810 default:
5811 llvm_unreachable("Unexpected operand width");
5812 case 8:
5813 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
5814 break;
5815 case 32:
5816 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
5817 break;
5818 }
5819 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5820 break;
5821 }
5822 case ISD::CTLZ:
5823 case ISD::CTTZ: {
5824 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5825 "Unexpected custom legalisation");
5826 Results.push_back(customLegalizeToWOp(N, DAG, 1));
5827 break;
5828 }
5830 SDValue Chain = N->getOperand(0);
5831 SDValue Op2 = N->getOperand(2);
5832 MVT GRLenVT = Subtarget.getGRLenVT();
5833 const StringRef ErrorMsgOOR = "argument out of range";
5834 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5835 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5836
5837 switch (N->getConstantOperandVal(1)) {
5838 default:
5839 llvm_unreachable("Unexpected Intrinsic.");
5840 case Intrinsic::loongarch_movfcsr2gr: {
5841 if (!Subtarget.hasBasicF()) {
5842 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
5843 return;
5844 }
5845 unsigned Imm = Op2->getAsZExtVal();
5846 if (!isUInt<2>(Imm)) {
5847 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5848 return;
5849 }
5850 SDValue MOVFCSR2GRResults = DAG.getNode(
5851 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
5852 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5853 Results.push_back(
5854 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
5855 Results.push_back(MOVFCSR2GRResults.getValue(1));
5856 break;
5857 }
5858#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
5859 case Intrinsic::loongarch_##NAME: { \
5860 SDValue NODE = DAG.getNode( \
5861 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5862 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5863 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5864 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5865 Results.push_back(NODE.getValue(1)); \
5866 break; \
5867 }
5868 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
5869 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
5870 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
5871 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
5872 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
5873 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
5874#undef CRC_CASE_EXT_BINARYOP
5875
5876#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
5877 case Intrinsic::loongarch_##NAME: { \
5878 SDValue NODE = DAG.getNode( \
5879 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5880 {Chain, Op2, \
5881 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5882 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5883 Results.push_back(NODE.getValue(1)); \
5884 break; \
5885 }
5886 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
5887 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
5888#undef CRC_CASE_EXT_UNARYOP
5889#define CSR_CASE(ID) \
5890 case Intrinsic::loongarch_##ID: { \
5891 if (!Subtarget.is64Bit()) \
5892 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
5893 break; \
5894 }
5895 CSR_CASE(csrrd_d);
5896 CSR_CASE(csrwr_d);
5897 CSR_CASE(csrxchg_d);
5898 CSR_CASE(iocsrrd_d);
5899#undef CSR_CASE
5900 case Intrinsic::loongarch_csrrd_w: {
5901 unsigned Imm = Op2->getAsZExtVal();
5902 if (!isUInt<14>(Imm)) {
5903 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5904 return;
5905 }
5906 SDValue CSRRDResults =
5907 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5908 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5909 Results.push_back(
5910 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
5911 Results.push_back(CSRRDResults.getValue(1));
5912 break;
5913 }
5914 case Intrinsic::loongarch_csrwr_w: {
5915 unsigned Imm = N->getConstantOperandVal(3);
5916 if (!isUInt<14>(Imm)) {
5917 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5918 return;
5919 }
5920 SDValue CSRWRResults =
5921 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5922 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5923 DAG.getConstant(Imm, DL, GRLenVT)});
5924 Results.push_back(
5925 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
5926 Results.push_back(CSRWRResults.getValue(1));
5927 break;
5928 }
5929 case Intrinsic::loongarch_csrxchg_w: {
5930 unsigned Imm = N->getConstantOperandVal(4);
5931 if (!isUInt<14>(Imm)) {
5932 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5933 return;
5934 }
5935 SDValue CSRXCHGResults = DAG.getNode(
5936 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5937 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5938 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
5939 DAG.getConstant(Imm, DL, GRLenVT)});
5940 Results.push_back(
5941 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
5942 Results.push_back(CSRXCHGResults.getValue(1));
5943 break;
5944 }
5945#define IOCSRRD_CASE(NAME, NODE) \
5946 case Intrinsic::loongarch_##NAME: { \
5947 SDValue IOCSRRDResults = \
5948 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5949 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
5950 Results.push_back( \
5951 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
5952 Results.push_back(IOCSRRDResults.getValue(1)); \
5953 break; \
5954 }
5955 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5956 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5957 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5958#undef IOCSRRD_CASE
5959 case Intrinsic::loongarch_cpucfg: {
5960 SDValue CPUCFGResults =
5961 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5962 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
5963 Results.push_back(
5964 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
5965 Results.push_back(CPUCFGResults.getValue(1));
5966 break;
5967 }
5968 case Intrinsic::loongarch_lddir_d: {
5969 if (!Subtarget.is64Bit()) {
5970 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
5971 return;
5972 }
5973 break;
5974 }
5975 }
5976 break;
5977 }
5978 case ISD::READ_REGISTER: {
5979 if (Subtarget.is64Bit())
5980 DAG.getContext()->emitError(
5981 "On LA64, only 64-bit registers can be read.");
5982 else
5983 DAG.getContext()->emitError(
5984 "On LA32, only 32-bit registers can be read.");
5985 Results.push_back(DAG.getUNDEF(VT));
5986 Results.push_back(N->getOperand(0));
5987 break;
5988 }
5990 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
5991 break;
5992 }
5993 case ISD::LROUND: {
5994 SDValue Op0 = N->getOperand(0);
5995 EVT OpVT = Op0.getValueType();
5996 RTLIB::Libcall LC =
5997 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
5998 MakeLibCallOptions CallOptions;
5999 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
6000 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
6001 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
6002 Results.push_back(Result);
6003 break;
6004 }
6005 case ISD::ATOMIC_CMP_SWAP: {
6007 break;
6008 }
6009 case ISD::TRUNCATE: {
6010 MVT VT = N->getSimpleValueType(0);
6011 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
6012 return;
6013
6014 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
6015 SDValue In = N->getOperand(0);
6016 EVT InVT = In.getValueType();
6017 EVT InEltVT = InVT.getVectorElementType();
6018 EVT EltVT = VT.getVectorElementType();
6019 unsigned MinElts = VT.getVectorNumElements();
6020 unsigned WidenNumElts = WidenVT.getVectorNumElements();
6021 unsigned InBits = InVT.getSizeInBits();
6022
6023 // v8i64 -> (v8i32) -> v8i8
6024 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
6025 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
6026 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6027 InBits = 256;
6028 }
6029
6030 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
6031 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
6032 WidenVT.is128BitVector()) {
6033 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
6034 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6035 InBits = 128;
6036 InEltVT = InVT.getVectorElementType();
6037 }
6038
6039 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
6040 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
6041 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
6042 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
6043 for (unsigned I = 0; I < MinElts; ++I)
6044 TruncMask[I] = Scale * I;
6045
6046 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
6047 MVT SVT = In.getSimpleValueType().getScalarType();
6048 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
6049 SDValue WidenIn =
6050 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
6051 DAG.getVectorIdxConstant(0, DL));
6052 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
6053 "Illegal vector type in truncation");
6054 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
6055 Results.push_back(
6056 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
6057 return;
6058 }
6059 }
6060
6061 break;
6062 }
6063 case ISD::SIGN_EXTEND: {
6064 // LASX has native VEXT2XV_* for sign extension.
6065 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
6066 return;
6067
6068 EVT DstVT = N->getValueType(0);
6069 SDValue Src = N->getOperand(0);
6070 MVT SrcVT = Src.getSimpleValueType();
6071
6072 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
6073 unsigned DstEltBits = DstVT.getScalarSizeInBits();
6074 unsigned NumElts = DstVT.getVectorNumElements();
6075
6076 if (SrcVT.getSizeInBits() > 128)
6077 return;
6078
6079 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6080 return;
6081
6082 // Legalize and extend the src to 128-bit first.
6083 if (SrcVT.getSizeInBits() < 128) {
6084 unsigned WidenSrcElts = 128 / SrcEltBits;
6085 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6086 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6087 DAG.getUNDEF(WidenSrcVT), Src,
6088 DAG.getVectorIdxConstant(0, DL));
6089 SrcVT = WidenSrcVT;
6090
6091 unsigned FirstStageEltBits = 128 / NumElts;
6092 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6093 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6094 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6095 SrcVT = FirstStageVT;
6096 SrcEltBits = FirstStageEltBits;
6097 }
6098
6100 Blocks.push_back(Src);
6101
6102 // Sign-extend the src by using SLTI + VILVL + VILVH recursively.
6103 while (SrcEltBits < DstEltBits) {
6104 unsigned NextEltBits = SrcEltBits * 2;
6105 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6106 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6107 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6108 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6109
6110 SmallVector<SDValue, 8> NextBlocks;
6111 NextBlocks.reserve(Blocks.size() * 2);
6112 for (SDValue Block : Blocks) {
6113 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
6114 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Block, Zero,
6115 DAG.getCondCode(ISD::SETLT));
6116 SDValue LoInterleaved =
6117 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Block);
6118 SDValue HiInterleaved =
6119 DAG.getNode(LoongArchISD::VILVH, DL, SrcVT, Mask, Block);
6120
6121 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, LoInterleaved));
6122 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, HiInterleaved));
6123 }
6124
6125 Blocks = std::move(NextBlocks);
6126 SrcVT = NextBlockVT;
6127 SrcEltBits = NextEltBits;
6128 }
6129
6130 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6131 break;
6132 }
6133 case ISD::FP_EXTEND:
6134 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6135 // no target-specific lowering is required. Leave it unchanged and rely on
6136 // the default type legalization.
6137 break;
6138 }
6139}
6140
6141/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6143 SelectionDAG &DAG) {
6144 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6145
6146 MVT VT = N->getSimpleValueType(0);
6147 if (!VT.is128BitVector() && !VT.is256BitVector())
6148 return SDValue();
6149
6150 SDValue X, Y;
6151 SDValue N0 = N->getOperand(0);
6152 SDValue N1 = N->getOperand(1);
6153
6154 if (SDValue Not = isNOT(N0, DAG)) {
6155 X = Not;
6156 Y = N1;
6157 } else if (SDValue Not = isNOT(N1, DAG)) {
6158 X = Not;
6159 Y = N0;
6160 } else
6161 return SDValue();
6162
6163 X = DAG.getBitcast(VT, X);
6164 Y = DAG.getBitcast(VT, Y);
6165 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6166}
6167
6168static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6169 unsigned MinSizeInBits) {
6172
6173 if (!Node)
6174 return false;
6175
6176 APInt SplatUndef;
6177 unsigned SplatBitSize;
6178 bool HasAnyUndefs;
6179
6180 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6181 HasAnyUndefs, MinSizeInBits,
6182 /*IsBigEndian=*/false);
6183}
6184
6185static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6186 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6187 if (!BV)
6188 return SDValue();
6189
6190 SDValue Src;
6191 int Start = -1;
6192
6193 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6194 SDValue Op = BV->getOperand(i);
6195 if (Op.isUndef())
6196 continue;
6197 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6198 return SDValue();
6199
6200 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6201 if (!IdxC)
6202 return SDValue();
6203
6204 unsigned EltIdx = IdxC->getZExtValue();
6205 if (Start < 0)
6206 Start = (int)EltIdx - (int)(i * 2);
6207 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6208 return SDValue();
6209
6210 SDValue CurSrc = Op.getOperand(0);
6211 if (!Src)
6212 Src = CurSrc;
6213 else if (Src != CurSrc)
6214 return SDValue();
6215 }
6216
6217 if (!Src || Start < 0)
6218 return SDValue();
6219
6220 StartIndex = (unsigned)Start;
6221 return Src;
6222}
6223
6224static SDValue
6226 const LoongArchSubtarget &Subtarget) {
6227 if (!Subtarget.hasExtLSX())
6228 return SDValue();
6229
6230 unsigned Opc = N->getOpcode();
6231 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6232
6233 EVT VT = N->getValueType(0);
6234 SDLoc DL(N);
6235
6236 SDValue LHS = N->getOperand(0);
6237 SDValue RHS = N->getOperand(1);
6238
6239 bool isSigned;
6240 unsigned ExtOpc = LHS.getOpcode();
6241 if (ExtOpc == ISD::SIGN_EXTEND)
6242 isSigned = true;
6243 else if (ExtOpc == ISD::ZERO_EXTEND)
6244 isSigned = false;
6245 else
6246 return SDValue();
6247
6248 if (ExtOpc != RHS.getOpcode())
6249 return SDValue();
6250
6251 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6252 return SDValue();
6253
6254 unsigned OddIdx, EvenIdx;
6255 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6256 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6257
6258 if (!LHSVec || !RHSVec)
6259 return SDValue();
6260 if (OddIdx != 1 || EvenIdx != 0)
6261 return SDValue();
6262 if (LHSVec.getValueType() != RHSVec.getValueType())
6263 return SDValue();
6264
6265 EVT SrcVT = LHSVec.getValueType();
6266 EVT SrcEltVT = SrcVT.getVectorElementType();
6267 EVT DstEltVT = VT.getVectorElementType();
6268 auto &TLI = DAG.getTargetLoweringInfo();
6269
6270 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6271 return SDValue();
6272 if (!SrcVT.isVector() || !VT.isVector())
6273 return SDValue();
6274 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6275 return SDValue();
6276 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6277 return SDValue();
6278 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6279 return SDValue();
6280
6281 unsigned TargetOpc;
6282 if (Opc == ISD::ADD)
6283 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6284 else
6285 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6286
6287 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6288}
6289
6292 const LoongArchSubtarget &Subtarget) {
6293 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6294 return V;
6295
6296 if (DCI.isBeforeLegalizeOps())
6297 return SDValue();
6298
6299 EVT VT = N->getValueType(0);
6300 if (!VT.isVector())
6301 return SDValue();
6302
6303 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6304 return SDValue();
6305
6306 EVT EltVT = VT.getVectorElementType();
6307 if (!EltVT.isInteger())
6308 return SDValue();
6309
6310 // match:
6311 //
6312 // add
6313 // (and
6314 // (srl X, shift-1) / X
6315 // 1)
6316 // (srl/sra X, shift)
6317
6318 SDValue Add0 = N->getOperand(0);
6319 SDValue Add1 = N->getOperand(1);
6320 SDValue And;
6321 SDValue Shr;
6322
6323 if (Add0.getOpcode() == ISD::AND) {
6324 And = Add0;
6325 Shr = Add1;
6326 } else if (Add1.getOpcode() == ISD::AND) {
6327 And = Add1;
6328 Shr = Add0;
6329 } else {
6330 return SDValue();
6331 }
6332
6333 // match:
6334 //
6335 // srl/sra X, shift
6336
6337 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6338 return SDValue();
6339
6340 SDValue X = Shr.getOperand(0);
6341 SDValue Shift = Shr.getOperand(1);
6342 APInt ShiftVal;
6343
6344 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6345 return SDValue();
6346
6347 if (ShiftVal == 0)
6348 return SDValue();
6349
6350 // match:
6351 //
6352 // and
6353 // (srl X, shift-1) / X
6354 // 1
6355
6356 SDValue One = And.getOperand(1);
6357 APInt SplatVal;
6358
6359 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6360 return SDValue();
6361
6362 if (SplatVal != 1)
6363 return SDValue();
6364
6365 if (And.getOperand(0) == X) {
6366 // match:
6367 //
6368 // shift == 1
6369
6370 if (ShiftVal != 1)
6371 return SDValue();
6372 } else {
6373 // match:
6374 //
6375 // srl X, shift-1
6376
6377 SDValue Srl = And.getOperand(0);
6378
6379 if (Srl.getOpcode() != ISD::SRL)
6380 return SDValue();
6381
6382 if (Srl.getOperand(0) != X)
6383 return SDValue();
6384
6385 // match:
6386 //
6387 // shift-1
6388
6389 SDValue ShiftMinus1 = Srl.getOperand(1);
6390
6391 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6392 return SDValue();
6393
6394 if (ShiftVal != (SplatVal + 1))
6395 return SDValue();
6396 }
6397
6398 // We matched a rounded right shift pattern and can lower it
6399 // to a single vector rounded shift instruction.
6400
6401 SDLoc DL(N);
6402 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6403 : LoongArchISD::VSRAR,
6404 DL, VT, X, Shift);
6405}
6406
6409 const LoongArchSubtarget &Subtarget) {
6410 if (DCI.isBeforeLegalizeOps())
6411 return SDValue();
6412
6413 SDValue FirstOperand = N->getOperand(0);
6414 SDValue SecondOperand = N->getOperand(1);
6415 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6416 EVT ValTy = N->getValueType(0);
6417 SDLoc DL(N);
6418 uint64_t lsb, msb;
6419 unsigned SMIdx, SMLen;
6420 ConstantSDNode *CN;
6421 SDValue NewOperand;
6422 MVT GRLenVT = Subtarget.getGRLenVT();
6423
6424 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6425 return R;
6426
6427 // BSTRPICK requires the 32S feature.
6428 if (!Subtarget.has32S())
6429 return SDValue();
6430
6431 // Op's second operand must be a shifted mask.
6432 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6433 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6434 return SDValue();
6435
6436 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6437 // Pattern match BSTRPICK.
6438 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6439 // => BSTRPICK $dst, $src, msb, lsb
6440 // where msb = lsb + len - 1
6441
6442 // The second operand of the shift must be an immediate.
6443 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6444 return SDValue();
6445
6446 lsb = CN->getZExtValue();
6447
6448 // Return if the shifted mask does not start at bit 0 or the sum of its
6449 // length and lsb exceeds the word's size.
6450 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6451 return SDValue();
6452
6453 NewOperand = FirstOperand.getOperand(0);
6454 } else {
6455 // Pattern match BSTRPICK.
6456 // $dst = and $src, (2**len- 1) , if len > 12
6457 // => BSTRPICK $dst, $src, msb, lsb
6458 // where lsb = 0 and msb = len - 1
6459
6460 // If the mask is <= 0xfff, andi can be used instead.
6461 if (CN->getZExtValue() <= 0xfff)
6462 return SDValue();
6463
6464 // Return if the MSB exceeds.
6465 if (SMIdx + SMLen > ValTy.getSizeInBits())
6466 return SDValue();
6467
6468 if (SMIdx > 0) {
6469 // Omit if the constant has more than 2 uses. This a conservative
6470 // decision. Whether it is a win depends on the HW microarchitecture.
6471 // However it should always be better for 1 and 2 uses.
6472 if (CN->use_size() > 2)
6473 return SDValue();
6474 // Return if the constant can be composed by a single LU12I.W.
6475 if ((CN->getZExtValue() & 0xfff) == 0)
6476 return SDValue();
6477 // Return if the constand can be composed by a single ADDI with
6478 // the zero register.
6479 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6480 return SDValue();
6481 }
6482
6483 lsb = SMIdx;
6484 NewOperand = FirstOperand;
6485 }
6486
6487 msb = lsb + SMLen - 1;
6488 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6489 DAG.getConstant(msb, DL, GRLenVT),
6490 DAG.getConstant(lsb, DL, GRLenVT));
6491 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6492 return NR0;
6493 // Try to optimize to
6494 // bstrpick $Rd, $Rs, msb, lsb
6495 // slli $Rd, $Rd, lsb
6496 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6497 DAG.getConstant(lsb, DL, GRLenVT));
6498}
6499
6500// Return the original source vector if N consists of the half
6501// of each 128-bit lane.
6504
6505 EVT DstVT = N.getValueType();
6506 if (!DstVT.isVector())
6507 return SDValue();
6508
6509 unsigned NumElts = DstVT.getVectorNumElements();
6510
6511 // LSX canonical form:
6512 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6513 SDValue Src = N.getOperand(0);
6514 EVT SrcVT = Src.getValueType();
6515
6516 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6517 return SDValue();
6518 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6519 return SDValue();
6520 if (SrcVT.getVectorNumElements() != NumElts * 2)
6521 return SDValue();
6522 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6523 return SDValue();
6524
6525 return Src;
6526 }
6527
6528 // LASX canonical form:
6529 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6530 if (!BV)
6531 return SDValue();
6532
6533 if (NumElts % 2 != 0)
6534 return SDValue();
6535
6536 SDValue Src;
6537 EVT SrcVT;
6538
6539 for (unsigned I = 0; I != NumElts; ++I) {
6540 SDValue Elt = BV->getOperand(I);
6541 if (Elt.isUndef())
6542 continue;
6544 return SDValue();
6545
6546 SDValue ThisSrc = Elt.getOperand(0);
6547 SDValue Idx = Elt.getOperand(1);
6548 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6549 if (!CI)
6550 return SDValue();
6551
6552 if (!Src) {
6553 Src = ThisSrc;
6554 SrcVT = Src.getValueType();
6555 if (!SrcVT.isVector())
6556 return SDValue();
6557
6558 if (!SrcVT.is256BitVector())
6559 return SDValue();
6560 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6561 return SDValue();
6562 if (SrcVT.getVectorNumElements() != NumElts * 2)
6563 return SDValue();
6564 } else if (ThisSrc != Src) {
6565 return SDValue();
6566 }
6567
6568 unsigned Half = NumElts / 2;
6569 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6570 ExpectedIdx += isLow ? 0 : Half;
6571
6572 if (CI->getZExtValue() != ExpectedIdx)
6573 return SDValue();
6574 }
6575
6576 return Src;
6577}
6578
6581 const LoongArchSubtarget &Subtarget) {
6582 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6583
6584 EVT VT = N->getValueType(0);
6585 SDLoc DL(N);
6586
6587 SDValue LHS = N->getOperand(0);
6588 SDValue RHS = N->getOperand(1);
6589
6590 bool isSigned;
6591 unsigned ExtOpc = LHS.getOpcode();
6592 if (ExtOpc == ISD::SIGN_EXTEND)
6593 isSigned = true;
6594 else if (ExtOpc == ISD::ZERO_EXTEND)
6595 isSigned = false;
6596 else
6597 return SDValue();
6598
6599 if (!LHS.hasOneUse())
6600 return SDValue();
6601
6602 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
6603 N->getValueSizeInBits(0) != LHS->getOperand(0).getValueSizeInBits() * 2)
6604 return SDValue();
6605
6606 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6607 if (!Vec)
6608 return SDValue();
6609
6610 EVT SrcVT = Vec.getValueType();
6611 EVT SrcEltVT = SrcVT.getVectorElementType();
6612 EVT DstEltVT = VT.getVectorElementType();
6613 APInt Imm;
6614 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6615 return SDValue();
6616 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6617 return SDValue();
6618
6619 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6620 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6621 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6622}
6623
6626 const LoongArchSubtarget &Subtarget) {
6627 // BSTRPICK requires the 32S feature.
6628 if (!Subtarget.has32S())
6629 return SDValue();
6630
6631 if (DCI.isBeforeLegalizeOps())
6632 return SDValue();
6633
6634 // $dst = srl (and $src, Mask), Shamt
6635 // =>
6636 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6637 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6638 //
6639
6640 SDValue FirstOperand = N->getOperand(0);
6641 ConstantSDNode *CN;
6642 EVT ValTy = N->getValueType(0);
6643 SDLoc DL(N);
6644 MVT GRLenVT = Subtarget.getGRLenVT();
6645 unsigned MaskIdx, MaskLen;
6646 uint64_t Shamt;
6647
6648 // The first operand must be an AND and the second operand of the AND must be
6649 // a shifted mask.
6650 if (FirstOperand.getOpcode() != ISD::AND ||
6651 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6652 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6653 return SDValue();
6654
6655 // The second operand (shift amount) must be an immediate.
6656 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6657 return SDValue();
6658
6659 Shamt = CN->getZExtValue();
6660 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6661 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6662 FirstOperand->getOperand(0),
6663 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6664 DAG.getConstant(Shamt, DL, GRLenVT));
6665
6666 return SDValue();
6667}
6668
6671 const LoongArchSubtarget &Subtarget) {
6672 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6673 return V;
6674
6675 return SDValue();
6676}
6677
6678// Helper to peek through bitops/trunc/setcc to determine size of source vector.
6679// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
6680static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
6681 unsigned Depth) {
6682 // Limit recursion.
6684 return false;
6685 switch (Src.getOpcode()) {
6686 case ISD::SETCC:
6687 case ISD::TRUNCATE:
6688 return Src.getOperand(0).getValueSizeInBits() == Size;
6689 case ISD::FREEZE:
6690 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
6691 case ISD::AND:
6692 case ISD::XOR:
6693 case ISD::OR:
6694 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
6695 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
6696 case ISD::SELECT:
6697 case ISD::VSELECT:
6698 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
6699 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
6700 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
6701 case ISD::BUILD_VECTOR:
6702 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
6703 ISD::isBuildVectorAllOnes(Src.getNode());
6704 }
6705 return false;
6706}
6707
6708// Helper to push sign extension of vXi1 SETCC result through bitops.
6710 SDValue Src, const SDLoc &DL) {
6711 switch (Src.getOpcode()) {
6712 case ISD::SETCC:
6713 case ISD::FREEZE:
6714 case ISD::TRUNCATE:
6715 case ISD::BUILD_VECTOR:
6716 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6717 case ISD::AND:
6718 case ISD::XOR:
6719 case ISD::OR:
6720 return DAG.getNode(
6721 Src.getOpcode(), DL, SExtVT,
6722 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
6723 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
6724 case ISD::SELECT:
6725 case ISD::VSELECT:
6726 return DAG.getSelect(
6727 DL, SExtVT, Src.getOperand(0),
6728 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
6729 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
6730 }
6731 llvm_unreachable("Unexpected node type for vXi1 sign extension");
6732}
6733
6734static SDValue
6737 const LoongArchSubtarget &Subtarget) {
6738 SDLoc DL(N);
6739 EVT VT = N->getValueType(0);
6740 SDValue Src = N->getOperand(0);
6741 EVT SrcVT = Src.getValueType();
6742
6743 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
6744 return SDValue();
6745
6746 bool UseLASX;
6747 unsigned Opc = ISD::DELETED_NODE;
6748 EVT CmpVT = Src.getOperand(0).getValueType();
6749 EVT EltVT = CmpVT.getVectorElementType();
6750
6751 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
6752 UseLASX = false;
6753 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
6754 CmpVT.getSizeInBits() == 256)
6755 UseLASX = true;
6756 else
6757 return SDValue();
6758
6759 SDValue SrcN1 = Src.getOperand(1);
6760 switch (cast<CondCodeSDNode>(Src.getOperand(2))->get()) {
6761 default:
6762 break;
6763 case ISD::SETEQ:
6764 // x == 0 => not (vmsknez.b x)
6765 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6766 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
6767 break;
6768 case ISD::SETGT:
6769 // x > -1 => vmskgez.b x
6770 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
6771 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6772 break;
6773 case ISD::SETGE:
6774 // x >= 0 => vmskgez.b x
6775 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6776 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6777 break;
6778 case ISD::SETLT:
6779 // x < 0 => vmskltz.{b,h,w,d} x
6780 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
6781 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6782 EltVT == MVT::i64))
6783 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6784 break;
6785 case ISD::SETLE:
6786 // x <= -1 => vmskltz.{b,h,w,d} x
6787 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
6788 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6789 EltVT == MVT::i64))
6790 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6791 break;
6792 case ISD::SETNE:
6793 // x != 0 => vmsknez.b x
6794 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6795 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
6796 break;
6797 }
6798
6799 if (Opc == ISD::DELETED_NODE)
6800 return SDValue();
6801
6802 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
6804 V = DAG.getZExtOrTrunc(V, DL, T);
6805 return DAG.getBitcast(VT, V);
6806}
6807
6810 const LoongArchSubtarget &Subtarget) {
6811 SDLoc DL(N);
6812 EVT VT = N->getValueType(0);
6813 SDValue Src = N->getOperand(0);
6814 EVT SrcVT = Src.getValueType();
6815 MVT GRLenVT = Subtarget.getGRLenVT();
6816
6817 if (!DCI.isBeforeLegalizeOps())
6818 return SDValue();
6819
6820 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
6821 return SDValue();
6822
6823 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
6824 SDValue Res = performSETCC_BITCASTCombine(N, DAG, DCI, Subtarget);
6825 if (Res)
6826 return Res;
6827
6828 // Generate vXi1 using [X]VMSKLTZ
6829 MVT SExtVT;
6830 unsigned Opc;
6831 bool UseLASX = false;
6832 bool PropagateSExt = false;
6833
6834 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
6835 EVT CmpVT = Src.getOperand(0).getValueType();
6836 if (CmpVT.getSizeInBits() > 256)
6837 return SDValue();
6838 }
6839
6840 switch (SrcVT.getSimpleVT().SimpleTy) {
6841 default:
6842 return SDValue();
6843 case MVT::v2i1:
6844 SExtVT = MVT::v2i64;
6845 break;
6846 case MVT::v4i1:
6847 SExtVT = MVT::v4i32;
6848 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6849 SExtVT = MVT::v4i64;
6850 UseLASX = true;
6851 PropagateSExt = true;
6852 }
6853 break;
6854 case MVT::v8i1:
6855 SExtVT = MVT::v8i16;
6856 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6857 SExtVT = MVT::v8i32;
6858 UseLASX = true;
6859 PropagateSExt = true;
6860 }
6861 break;
6862 case MVT::v16i1:
6863 SExtVT = MVT::v16i8;
6864 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6865 SExtVT = MVT::v16i16;
6866 UseLASX = true;
6867 PropagateSExt = true;
6868 }
6869 break;
6870 case MVT::v32i1:
6871 SExtVT = MVT::v32i8;
6872 UseLASX = true;
6873 break;
6874 };
6875 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
6876 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6877
6878 SDValue V;
6879 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
6880 if (Src.getSimpleValueType() == MVT::v32i8) {
6881 SDValue Lo, Hi;
6882 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
6883 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
6884 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
6885 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
6886 DAG.getShiftAmountConstant(16, GRLenVT, DL));
6887 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
6888 } else if (UseLASX) {
6889 return SDValue();
6890 }
6891 }
6892
6893 if (!V) {
6894 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6895 V = DAG.getNode(Opc, DL, GRLenVT, Src);
6896 }
6897
6899 V = DAG.getZExtOrTrunc(V, DL, T);
6900 return DAG.getBitcast(VT, V);
6901}
6902
6905 const LoongArchSubtarget &Subtarget) {
6906 MVT GRLenVT = Subtarget.getGRLenVT();
6907 EVT ValTy = N->getValueType(0);
6908 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
6909 ConstantSDNode *CN0, *CN1;
6910 SDLoc DL(N);
6911 unsigned ValBits = ValTy.getSizeInBits();
6912 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
6913 unsigned Shamt;
6914 bool SwapAndRetried = false;
6915
6916 // BSTRPICK requires the 32S feature.
6917 if (!Subtarget.has32S())
6918 return SDValue();
6919
6920 if (DCI.isBeforeLegalizeOps())
6921 return SDValue();
6922
6923 if (ValBits != 32 && ValBits != 64)
6924 return SDValue();
6925
6926Retry:
6927 // 1st pattern to match BSTRINS:
6928 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
6929 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
6930 // =>
6931 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6932 if (N0.getOpcode() == ISD::AND &&
6933 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6934 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6935 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
6936 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6937 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6938 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
6939 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6940 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6941 (MaskIdx0 + MaskLen0 <= ValBits)) {
6942 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
6943 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6944 N1.getOperand(0).getOperand(0),
6945 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6946 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6947 }
6948
6949 // 2nd pattern to match BSTRINS:
6950 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
6951 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
6952 // =>
6953 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6954 if (N0.getOpcode() == ISD::AND &&
6955 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6956 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6957 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
6958 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6959 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6960 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6961 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6962 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
6963 (MaskIdx0 + MaskLen0 <= ValBits)) {
6964 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
6965 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6966 N1.getOperand(0).getOperand(0),
6967 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6968 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6969 }
6970
6971 // 3rd pattern to match BSTRINS:
6972 // R = or (and X, mask0), (and Y, mask1)
6973 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
6974 // =>
6975 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
6976 // where msb = lsb + size - 1
6977 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
6978 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6979 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6980 (MaskIdx0 + MaskLen0 <= 64) &&
6981 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
6982 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
6983 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
6984 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6985 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
6986 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
6987 DAG.getConstant(ValBits == 32
6988 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
6989 : (MaskIdx0 + MaskLen0 - 1),
6990 DL, GRLenVT),
6991 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6992 }
6993
6994 // 4th pattern to match BSTRINS:
6995 // R = or (and X, mask), (shl Y, shamt)
6996 // where mask = (2**shamt - 1)
6997 // =>
6998 // R = BSTRINS X, Y, ValBits - 1, shamt
6999 // where ValBits = 32 or 64
7000 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
7001 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7002 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
7003 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7004 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
7005 (MaskIdx0 + MaskLen0 <= ValBits)) {
7006 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
7007 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7008 N1.getOperand(0),
7009 DAG.getConstant((ValBits - 1), DL, GRLenVT),
7010 DAG.getConstant(Shamt, DL, GRLenVT));
7011 }
7012
7013 // 5th pattern to match BSTRINS:
7014 // R = or (and X, mask), const
7015 // where ~mask = (2**size - 1) << lsb, mask & const = 0
7016 // =>
7017 // R = BSTRINS X, (const >> lsb), msb, lsb
7018 // where msb = lsb + size - 1
7019 if (N0.getOpcode() == ISD::AND &&
7020 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7021 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7022 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
7023 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7024 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
7025 return DAG.getNode(
7026 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7027 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
7028 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7029 : (MaskIdx0 + MaskLen0 - 1),
7030 DL, GRLenVT),
7031 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7032 }
7033
7034 // 6th pattern.
7035 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
7036 // by the incoming bits are known to be zero.
7037 // =>
7038 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
7039 //
7040 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
7041 // pattern is more common than the 1st. So we put the 1st before the 6th in
7042 // order to match as many nodes as possible.
7043 ConstantSDNode *CNMask, *CNShamt;
7044 unsigned MaskIdx, MaskLen;
7045 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7046 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7047 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7048 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7049 CNShamt->getZExtValue() + MaskLen <= ValBits) {
7050 Shamt = CNShamt->getZExtValue();
7051 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
7052 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7053 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
7054 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7055 N1.getOperand(0).getOperand(0),
7056 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
7057 DAG.getConstant(Shamt, DL, GRLenVT));
7058 }
7059 }
7060
7061 // 7th pattern.
7062 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
7063 // overwritten by the incoming bits are known to be zero.
7064 // =>
7065 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7066 //
7067 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7068 // before the 7th in order to match as many nodes as possible.
7069 if (N1.getOpcode() == ISD::AND &&
7070 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7071 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7072 N1.getOperand(0).getOpcode() == ISD::SHL &&
7073 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7074 CNShamt->getZExtValue() == MaskIdx) {
7075 APInt ShMask(ValBits, CNMask->getZExtValue());
7076 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7077 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7078 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7079 N1.getOperand(0).getOperand(0),
7080 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7081 DAG.getConstant(MaskIdx, DL, GRLenVT));
7082 }
7083 }
7084
7085 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7086 if (!SwapAndRetried) {
7087 std::swap(N0, N1);
7088 SwapAndRetried = true;
7089 goto Retry;
7090 }
7091
7092 SwapAndRetried = false;
7093Retry2:
7094 // 8th pattern.
7095 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7096 // the incoming bits are known to be zero.
7097 // =>
7098 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7099 //
7100 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7101 // we put it here in order to match as many nodes as possible or generate less
7102 // instructions.
7103 if (N1.getOpcode() == ISD::AND &&
7104 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7105 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7106 APInt ShMask(ValBits, CNMask->getZExtValue());
7107 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7108 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7109 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7110 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7111 N1->getOperand(0),
7112 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7113 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7114 DAG.getConstant(MaskIdx, DL, GRLenVT));
7115 }
7116 }
7117 // Swap N0/N1 and retry.
7118 if (!SwapAndRetried) {
7119 std::swap(N0, N1);
7120 SwapAndRetried = true;
7121 goto Retry2;
7122 }
7123
7124 return SDValue();
7125}
7126
7127static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
7128 ExtType = ISD::NON_EXTLOAD;
7129
7130 switch (V.getNode()->getOpcode()) {
7131 case ISD::LOAD: {
7132 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7133 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7134 (LoadNode->getMemoryVT() == MVT::i16)) {
7135 ExtType = LoadNode->getExtensionType();
7136 return true;
7137 }
7138 return false;
7139 }
7140 case ISD::AssertSext: {
7141 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7142 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7143 ExtType = ISD::SEXTLOAD;
7144 return true;
7145 }
7146 return false;
7147 }
7148 case ISD::AssertZext: {
7149 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7150 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7151 ExtType = ISD::ZEXTLOAD;
7152 return true;
7153 }
7154 return false;
7155 }
7156 default:
7157 return false;
7158 }
7159
7160 return false;
7161}
7162
7163// Fold a lane-mask extraction that is only compared against zero into one of
7164// all-lane check instructions, which write the results into fcc register, so
7165// BCEQZ could use it directly.
7166//
7167// (VMSKLTZ X) != 0 -> VSETNEZ.V X
7168// (VMSKLTZ X) == 0 -> VSETEQZ.V X
7169//
7170// This is valid when X is the result of a vector compare instruction,
7171// so each lane of X has to be all-ones or all-zeros.
7173 const SDLoc &DL, SelectionDAG &DAG,
7174 const LoongArchSubtarget &Subtarget) {
7175 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7176 return SDValue();
7177 if (!isNullConstant(RHS))
7178 return SDValue();
7179
7180 unsigned MskOpc = LHS.getOpcode();
7181 if (MskOpc != LoongArchISD::VMSKLTZ && MskOpc != LoongArchISD::XVMSKLTZ)
7182 return SDValue();
7183 // Keeping the mask alive for another user would defeat the purpose.
7184 if (!LHS.hasOneUse())
7185 return SDValue();
7186
7187 SDValue Src = LHS.getOperand(0);
7188 EVT SrcVT = Src.getValueType();
7189 // Make sure every lane is all-ones or all-zeros.
7190 if (!SrcVT.isVector() ||
7191 DAG.ComputeNumSignBits(Src) != SrcVT.getScalarSizeInBits())
7192 return SDValue();
7193
7194 return DAG.getNode(CC == ISD::SETNE ? LoongArchISD::VANYNONZERO
7195 : LoongArchISD::VALLZERO,
7196 DL, Subtarget.getGRLenVT(), Src);
7197}
7198
7199// Eliminate redundant truncation and zero-extension nodes.
7200// * Case 1:
7201// +------------+ +------------+ +------------+
7202// | Input1 | | Input2 | | CC |
7203// +------------+ +------------+ +------------+
7204// | | |
7205// V V +----+
7206// +------------+ +------------+ |
7207// | TRUNCATE | | TRUNCATE | |
7208// +------------+ +------------+ |
7209// | | |
7210// V V |
7211// +------------+ +------------+ |
7212// | ZERO_EXT | | ZERO_EXT | |
7213// +------------+ +------------+ |
7214// | | |
7215// | +-------------+ |
7216// V V | |
7217// +----------------+ | |
7218// | AND | | |
7219// +----------------+ | |
7220// | | |
7221// +---------------+ | |
7222// | | |
7223// V V V
7224// +-------------+
7225// | CMP |
7226// +-------------+
7227// * Case 2:
7228// +------------+ +------------+ +-------------+ +------------+ +------------+
7229// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7230// +------------+ +------------+ +-------------+ +------------+ +------------+
7231// | | | | |
7232// V | | | |
7233// +------------+ | | | |
7234// | XOR |<---------------------+ | |
7235// +------------+ | | |
7236// | | | |
7237// V V +---------------+ |
7238// +------------+ +------------+ | |
7239// | TRUNCATE | | TRUNCATE | | +-------------------------+
7240// +------------+ +------------+ | |
7241// | | | |
7242// V V | |
7243// +------------+ +------------+ | |
7244// | ZERO_EXT | | ZERO_EXT | | |
7245// +------------+ +------------+ | |
7246// | | | |
7247// V V | |
7248// +----------------+ | |
7249// | AND | | |
7250// +----------------+ | |
7251// | | |
7252// +---------------+ | |
7253// | | |
7254// V V V
7255// +-------------+
7256// | CMP |
7257// +-------------+
7260 const LoongArchSubtarget &Subtarget) {
7261 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
7262
7263 if (N->getValueType(0) == Subtarget.getGRLenVT())
7264 if (SDValue V = foldVMskZeroTest(N->getOperand(0), N->getOperand(1), CC,
7265 SDLoc(N), DAG, Subtarget))
7266 return V;
7267
7268 SDNode *AndNode = N->getOperand(0).getNode();
7269 if (AndNode->getOpcode() != ISD::AND)
7270 return SDValue();
7271
7272 SDValue AndInputValue2 = AndNode->getOperand(1);
7273 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7274 return SDValue();
7275
7276 SDValue CmpInputValue = N->getOperand(1);
7277 SDValue AndInputValue1 = AndNode->getOperand(0);
7278 if (AndInputValue1.getOpcode() == ISD::XOR) {
7279 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7280 return SDValue();
7281 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7282 if (!CN || !CN->isAllOnes())
7283 return SDValue();
7284 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7285 if (!CN || !CN->isZero())
7286 return SDValue();
7287 AndInputValue1 = AndInputValue1.getOperand(0);
7288 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7289 return SDValue();
7290 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7291 if (AndInputValue2 != CmpInputValue)
7292 return SDValue();
7293 } else {
7294 return SDValue();
7295 }
7296
7297 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7298 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7299 return SDValue();
7300
7301 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7302 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7303 return SDValue();
7304
7305 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7306 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7307 ISD::LoadExtType ExtType1;
7308 ISD::LoadExtType ExtType2;
7309
7310 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7311 !checkValueWidth(TruncInputValue2, ExtType2))
7312 return SDValue();
7313
7314 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7315 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7316 return SDValue();
7317
7318 if ((ExtType2 != ISD::ZEXTLOAD) &&
7319 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7320 return SDValue();
7321
7322 // These truncation and zero-extension nodes are not necessary, remove them.
7323 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7324 TruncInputValue1, TruncInputValue2);
7325 SDValue NewSetCC =
7326 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7327 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7328 return SDValue(N, 0);
7329}
7330
7331// Strip a single outer ISD::SIGN_EXTEND_INREG from \p V, if present, and
7332// return the inner value together with the narrow VT it was extending
7333// from. If no such node is present, returns \p V unchanged and an invalid
7334// EVT.
7335//
7336// i32 (and other sub-GRLen) arithmetic is legalized to operate on the full
7337// GRLen-width register, with a `sign_extend_inreg` re-normalizing the
7338// result back into the narrow type's range afterwards (see e.g. the
7339// `add i32` -> `add` + `sign_extend_inreg ..., i32` legalization). Any
7340// combine that reassociates such a binop must track and reapply this
7341// extension, otherwise the transformed code can produce a value whose
7342// high bits no longer match the narrow-type semantics.
7343static std::pair<SDValue, EVT> stripSignExtendInReg(SDValue V) {
7344 if (V.getOpcode() == ISD::SIGN_EXTEND_INREG)
7345 return {V.getOperand(0), cast<VTSDNode>(V.getOperand(1))->getVT()};
7346 return {V, EVT()};
7347}
7348
7349// Try to match \p BinV (after optionally stripping an outer
7350// sign_extend_inreg) as a supported binary operation that has \p X as one
7351// of its operands, returning the matched opcode, the other operand (the
7352// "delta"), and the narrow VT of the sign_extend_inreg that was stripped
7353// (invalid EVT if none was present).
7354//
7355// For commutative ops (add/or/xor), \p X may be either operand, since
7356// `binop(X, Y) == binop(Y, X)` and the identity element (0) works on
7357// either side.
7358//
7359// For `sub`, the operation is NOT commutative: `sub(X, Y) != sub(Y, X)`.
7360// Only `sub(X, Y)` (i.e. \p X is the *minuend*, the first operand) can be
7361// rewritten using the identity `X - 0 == X`. If \p X were the *subtrahend*
7362// (second operand, i.e. the pattern is actually `sub(Y, X)`), there is no
7363// way to express `cond ? (Y - X) : X` (or the symmetric case) as
7364// `X op (select ...)` without introducing an extra negation, so that case
7365// must be rejected instead of "optimized" into worse code.
7366static std::tuple<unsigned, SDValue, EVT>
7368 auto [Inner, ExtVT] = stripSignExtendInReg(BinV);
7369
7370 unsigned Opc = Inner.getOpcode();
7371 switch (Opc) {
7372 case ISD::ADD:
7373 case ISD::OR:
7374 case ISD::XOR:
7375 if (Inner.getOperand(0) == X)
7376 return {Opc, Inner.getOperand(1), ExtVT};
7377 if (Inner.getOperand(1) == X)
7378 return {Opc, Inner.getOperand(0), ExtVT};
7379 return {0, SDValue(), EVT()};
7380 case ISD::SUB:
7381 // Only accept X as the minuend (first operand); see comment above.
7382 if (Inner.getOperand(0) == X)
7383 return {Opc, Inner.getOperand(1), ExtVT};
7384 return {0, SDValue(), EVT()};
7385 default:
7386 return {0, SDValue(), EVT()};
7387 }
7388}
7389
7390// Try to combine:
7391// select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
7392// select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
7393// for binop in {add, or, xor, sub}, where 0 is the identity element of the
7394// respective operation, additionally handling the common legalized form
7395// where the binop result is wrapped in a `sign_extend_inreg` (as happens
7396// for sub-GRLen types such as i32 on a 64-bit GRLen target). See
7397// matchBinOpWithSharedOperand() for the restrictions applied to
7398// non-commutative operations (currently only `sub`).
7401 const LoongArchSubtarget &Subtarget) {
7402 if (DCI.isBeforeLegalizeOps())
7403 return SDValue();
7404
7405 EVT VT = N->getValueType(0);
7406 // Restrict to the scalar GRLen integer type that maskeqz/masknez operate
7407 // on; this also naturally excludes float and vector selects.
7408 if (VT != Subtarget.getGRLenVT())
7409 return SDValue();
7410
7411 SDValue Cond = N->getOperand(0);
7412 SDValue TrueV = N->getOperand(1);
7413 SDValue FalseV = N->getOperand(2);
7414 SDLoc DL(N);
7415
7416 auto TryFold = [&](SDValue BinV, SDValue SharedV,
7417 bool BinIsTrueArm) -> SDValue {
7418 auto [Opc, Delta, ExtVT] = matchBinOpWithSharedOperand(BinV, SharedV);
7419 if (!Opc)
7420 return SDValue();
7421
7422 // Avoid infinite combine loops: bail out if Delta is trivially the
7423 // same node we would otherwise be selecting on (shouldn't normally
7424 // happen, but guards against degenerate/self-referential IR).
7425 if (Delta.getNode() == N)
7426 return SDValue();
7427
7428 SDValue Zero = DAG.getConstant(0, DL, VT);
7429 SDValue NewSel = BinIsTrueArm ? DAG.getSelect(DL, VT, Cond, Delta, Zero)
7430 : DAG.getSelect(DL, VT, Cond, Zero, Delta);
7431 SDValue NewBin = DAG.getNode(Opc, DL, VT, SharedV, NewSel);
7432
7433 // If the original binop result was normalized back into a narrower
7434 // type via sign_extend_inreg (e.g. i32 arithmetic on a 64-bit GRLen
7435 // target), the new binop must be re-normalized the same way: SharedV
7436 // is already known-sign-extended for that narrow type, but NewSel
7437 // (Delta or 0, selected) combined with SharedV via Opc can still
7438 // produce a 64-bit result whose high bits don't match the narrow
7439 // type's sign-extended representation.
7440 if (ExtVT != EVT())
7441 NewBin = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, NewBin,
7442 DAG.getValueType(ExtVT));
7443
7444 return NewBin;
7445 };
7446
7447 if (SDValue R = TryFold(TrueV, FalseV, /*BinIsTrueArm=*/true))
7448 return R;
7449 if (SDValue R = TryFold(FalseV, TrueV, /*BinIsTrueArm=*/false))
7450 return R;
7451
7452 return SDValue();
7453}
7454
7455// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7458 const LoongArchSubtarget &Subtarget) {
7459 if (DCI.isBeforeLegalizeOps())
7460 return SDValue();
7461
7462 SDValue Src = N->getOperand(0);
7463 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7464 return SDValue();
7465
7466 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7467 Src.getOperand(0));
7468}
7469
7470// Perform common combines for BR_CC and SELECT_CC conditions.
7471static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7472 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
7473 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7474
7475 // As far as arithmetic right shift always saves the sign,
7476 // shift can be omitted.
7477 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7478 // setge (sra X, N), 0 -> setge X, 0
7479 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7480 LHS.getOpcode() == ISD::SRA) {
7481 LHS = LHS.getOperand(0);
7482 return true;
7483 }
7484
7485 if (!ISD::isIntEqualitySetCC(CCVal))
7486 return false;
7487
7488 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7489 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7490 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7491 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7492 // If we're looking for eq 0 instead of ne 0, we need to invert the
7493 // condition.
7494 bool Invert = CCVal == ISD::SETEQ;
7495 CCVal = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
7496 if (Invert)
7497 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7498
7499 RHS = LHS.getOperand(1);
7500 LHS = LHS.getOperand(0);
7501 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7502
7503 CC = DAG.getCondCode(CCVal);
7504 return true;
7505 }
7506
7507 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7508 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7509 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7510 SDValue LHS0 = LHS.getOperand(0);
7511 if (LHS0.getOpcode() == ISD::AND &&
7512 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7513 uint64_t Mask = LHS0.getConstantOperandVal(1);
7514 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7515 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7516 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7517 CC = DAG.getCondCode(CCVal);
7518
7519 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7520 LHS = LHS0.getOperand(0);
7521 if (ShAmt != 0)
7522 LHS =
7523 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7524 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7525 return true;
7526 }
7527 }
7528 }
7529
7530 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7531 // This can occur when legalizing some floating point comparisons.
7532 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7533 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7534 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7535 CC = DAG.getCondCode(CCVal);
7536 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7537 return true;
7538 }
7539
7540 // Fold ((shl (extract_vector_elt X, I), GRLen - EleBits)), 0, eq/ne) ->
7541 // ((extract_vector_elt X, I), 0, eq/ne)
7542 if (isNullConstant(RHS) && (CCVal == ISD::SETEQ || CCVal == ISD::SETNE) &&
7543 LHS.getOpcode() == ISD::SHL && LHS.hasOneUse() &&
7544 isa<ConstantSDNode>(LHS.getOperand(1))) {
7545 SDValue Ext = LHS.getOperand(0);
7546 unsigned Sht = LHS.getConstantOperandVal(1);
7547 if (Ext.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
7548 SDValue Vec = Ext.getOperand(0);
7549 unsigned EleBits = Vec.getScalarValueSizeInBits();
7550 if ((EleBits + Sht) == Subtarget.getGRLen()) {
7551 LHS = Ext;
7552 return true;
7553 }
7554 }
7555 }
7556
7557 // Fold (C1, C2, cond) -> (0, 0, seteq/setne)
7559 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
7560 EVT VT = LHS.getValueType();
7561 EVT SetCCResVT =
7562 TLI->getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
7563 if (SDValue Folded = DAG.FoldSetCC(SetCCResVT, LHS, RHS, CCVal, DL)) {
7564 LHS = DAG.getConstant(0, DL, VT);
7565 RHS = DAG.getConstant(0, DL, VT);
7566 CC = DAG.getCondCode(!isNullConstant(Folded) ? ISD::SETEQ : ISD::SETNE);
7567 return true;
7568 }
7569 }
7570
7571 return false;
7572}
7573
7576 const LoongArchSubtarget &Subtarget) {
7577 SDValue LHS = N->getOperand(1);
7578 SDValue RHS = N->getOperand(2);
7579 SDValue CC = N->getOperand(3);
7580 SDLoc DL(N);
7581
7582 // CC was folded into V, so always return ISD::SETNE is fine.
7584 DL, DAG, Subtarget))
7585 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7586 N->getOperand(0), V,
7587 DAG.getConstant(0, DL, Subtarget.getGRLenVT()),
7588 DAG.getCondCode(ISD::SETNE), N->getOperand(4));
7589
7590 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7591 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7592 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7593
7594 return SDValue();
7595}
7596
7599 const LoongArchSubtarget &Subtarget) {
7600 // Transform
7601 SDValue LHS = N->getOperand(0);
7602 SDValue RHS = N->getOperand(1);
7603 SDValue CC = N->getOperand(2);
7604 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7605 SDValue TrueV = N->getOperand(3);
7606 SDValue FalseV = N->getOperand(4);
7607 SDLoc DL(N);
7608 EVT VT = N->getValueType(0);
7609
7610 // If the True and False values are the same, we don't need a select_cc.
7611 if (TrueV == FalseV)
7612 return TrueV;
7613
7614 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7615 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7616 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7618 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7619 if (CCVal == ISD::CondCode::SETGE)
7620 std::swap(TrueV, FalseV);
7621
7622 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7623 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7624 // Only handle simm12, if it is not in this range, it can be considered as
7625 // register.
7626 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7627 isInt<12>(TrueSImm - FalseSImm)) {
7628 SDValue SRA =
7629 DAG.getNode(ISD::SRA, DL, VT, LHS,
7630 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7631 SDValue AND =
7632 DAG.getNode(ISD::AND, DL, VT, SRA,
7633 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7634 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7635 }
7636
7637 if (CCVal == ISD::CondCode::SETGE)
7638 std::swap(TrueV, FalseV);
7639 }
7640
7641 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7642 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
7643 {LHS, RHS, CC, TrueV, FalseV});
7644
7645 return SDValue();
7646}
7647
7648template <unsigned N>
7650 SelectionDAG &DAG,
7651 const LoongArchSubtarget &Subtarget,
7652 bool IsSigned = false) {
7653 SDLoc DL(Node);
7654 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7655 // Check the ImmArg.
7656 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7657 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7658 DAG.getContext()->emitError(Node->getOperationName(0) +
7659 ": argument out of range.");
7660 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
7661 }
7662 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
7663}
7664
7665template <unsigned N>
7666static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
7667 SelectionDAG &DAG, bool IsSigned = false) {
7668 SDLoc DL(Node);
7669 EVT ResTy = Node->getValueType(0);
7670 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7671
7672 // Check the ImmArg.
7673 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7674 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7675 DAG.getContext()->emitError(Node->getOperationName(0) +
7676 ": argument out of range.");
7677 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7678 }
7679 return DAG.getConstant(
7681 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
7682 DL, ResTy);
7683}
7684
7686 SDLoc DL(Node);
7687 EVT ResTy = Node->getValueType(0);
7688 SDValue Vec = Node->getOperand(2);
7689 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
7690 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
7691}
7692
7694 SDLoc DL(Node);
7695 EVT ResTy = Node->getValueType(0);
7696 SDValue One = DAG.getConstant(1, DL, ResTy);
7697 SDValue Bit =
7698 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
7699
7700 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
7701 DAG.getNOT(DL, Bit, ResTy));
7702}
7703
7704template <unsigned N>
7706 SDLoc DL(Node);
7707 EVT ResTy = Node->getValueType(0);
7708 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7709 // Check the unsigned ImmArg.
7710 if (!isUInt<N>(CImm->getZExtValue())) {
7711 DAG.getContext()->emitError(Node->getOperationName(0) +
7712 ": argument out of range.");
7713 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7714 }
7715
7716 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7717 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
7718
7719 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
7720}
7721
7722template <unsigned N>
7724 SDLoc DL(Node);
7725 EVT ResTy = Node->getValueType(0);
7726 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7727 // Check the unsigned ImmArg.
7728 if (!isUInt<N>(CImm->getZExtValue())) {
7729 DAG.getContext()->emitError(Node->getOperationName(0) +
7730 ": argument out of range.");
7731 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7732 }
7733
7734 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7735 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7736 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
7737}
7738
7739template <unsigned N>
7741 SDLoc DL(Node);
7742 EVT ResTy = Node->getValueType(0);
7743 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7744 // Check the unsigned ImmArg.
7745 if (!isUInt<N>(CImm->getZExtValue())) {
7746 DAG.getContext()->emitError(Node->getOperationName(0) +
7747 ": argument out of range.");
7748 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7749 }
7750
7751 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7752 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7753 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
7754}
7755
7756template <unsigned W>
7758 unsigned ResOp) {
7759 unsigned Imm = N->getConstantOperandVal(2);
7760 if (!isUInt<W>(Imm)) {
7761 const StringRef ErrorMsg = "argument out of range";
7762 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
7763 return DAG.getUNDEF(N->getValueType(0));
7764 }
7765 SDLoc DL(N);
7766 SDValue Vec = N->getOperand(1);
7767 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
7769 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
7770}
7771
7772static SDValue
7775 const LoongArchSubtarget &Subtarget) {
7776 SDLoc DL(N);
7777 switch (N->getConstantOperandVal(0)) {
7778 default:
7779 break;
7780 case Intrinsic::loongarch_lsx_vadd_b:
7781 case Intrinsic::loongarch_lsx_vadd_h:
7782 case Intrinsic::loongarch_lsx_vadd_w:
7783 case Intrinsic::loongarch_lsx_vadd_d:
7784 case Intrinsic::loongarch_lasx_xvadd_b:
7785 case Intrinsic::loongarch_lasx_xvadd_h:
7786 case Intrinsic::loongarch_lasx_xvadd_w:
7787 case Intrinsic::loongarch_lasx_xvadd_d:
7788 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7789 N->getOperand(2));
7790 case Intrinsic::loongarch_lsx_vaddi_bu:
7791 case Intrinsic::loongarch_lsx_vaddi_hu:
7792 case Intrinsic::loongarch_lsx_vaddi_wu:
7793 case Intrinsic::loongarch_lsx_vaddi_du:
7794 case Intrinsic::loongarch_lasx_xvaddi_bu:
7795 case Intrinsic::loongarch_lasx_xvaddi_hu:
7796 case Intrinsic::loongarch_lasx_xvaddi_wu:
7797 case Intrinsic::loongarch_lasx_xvaddi_du:
7798 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7799 lowerVectorSplatImm<5>(N, 2, DAG));
7800 case Intrinsic::loongarch_lsx_vsub_b:
7801 case Intrinsic::loongarch_lsx_vsub_h:
7802 case Intrinsic::loongarch_lsx_vsub_w:
7803 case Intrinsic::loongarch_lsx_vsub_d:
7804 case Intrinsic::loongarch_lasx_xvsub_b:
7805 case Intrinsic::loongarch_lasx_xvsub_h:
7806 case Intrinsic::loongarch_lasx_xvsub_w:
7807 case Intrinsic::loongarch_lasx_xvsub_d:
7808 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7809 N->getOperand(2));
7810 case Intrinsic::loongarch_lsx_vsubi_bu:
7811 case Intrinsic::loongarch_lsx_vsubi_hu:
7812 case Intrinsic::loongarch_lsx_vsubi_wu:
7813 case Intrinsic::loongarch_lsx_vsubi_du:
7814 case Intrinsic::loongarch_lasx_xvsubi_bu:
7815 case Intrinsic::loongarch_lasx_xvsubi_hu:
7816 case Intrinsic::loongarch_lasx_xvsubi_wu:
7817 case Intrinsic::loongarch_lasx_xvsubi_du:
7818 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7819 lowerVectorSplatImm<5>(N, 2, DAG));
7820 case Intrinsic::loongarch_lsx_vneg_b:
7821 case Intrinsic::loongarch_lsx_vneg_h:
7822 case Intrinsic::loongarch_lsx_vneg_w:
7823 case Intrinsic::loongarch_lsx_vneg_d:
7824 case Intrinsic::loongarch_lasx_xvneg_b:
7825 case Intrinsic::loongarch_lasx_xvneg_h:
7826 case Intrinsic::loongarch_lasx_xvneg_w:
7827 case Intrinsic::loongarch_lasx_xvneg_d:
7828 return DAG.getNode(
7829 ISD::SUB, DL, N->getValueType(0),
7830 DAG.getConstant(
7831 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
7832 /*isSigned=*/true),
7833 SDLoc(N), N->getValueType(0)),
7834 N->getOperand(1));
7835 case Intrinsic::loongarch_lsx_vmax_b:
7836 case Intrinsic::loongarch_lsx_vmax_h:
7837 case Intrinsic::loongarch_lsx_vmax_w:
7838 case Intrinsic::loongarch_lsx_vmax_d:
7839 case Intrinsic::loongarch_lasx_xvmax_b:
7840 case Intrinsic::loongarch_lasx_xvmax_h:
7841 case Intrinsic::loongarch_lasx_xvmax_w:
7842 case Intrinsic::loongarch_lasx_xvmax_d:
7843 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7844 N->getOperand(2));
7845 case Intrinsic::loongarch_lsx_vmax_bu:
7846 case Intrinsic::loongarch_lsx_vmax_hu:
7847 case Intrinsic::loongarch_lsx_vmax_wu:
7848 case Intrinsic::loongarch_lsx_vmax_du:
7849 case Intrinsic::loongarch_lasx_xvmax_bu:
7850 case Intrinsic::loongarch_lasx_xvmax_hu:
7851 case Intrinsic::loongarch_lasx_xvmax_wu:
7852 case Intrinsic::loongarch_lasx_xvmax_du:
7853 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7854 N->getOperand(2));
7855 case Intrinsic::loongarch_lsx_vmaxi_b:
7856 case Intrinsic::loongarch_lsx_vmaxi_h:
7857 case Intrinsic::loongarch_lsx_vmaxi_w:
7858 case Intrinsic::loongarch_lsx_vmaxi_d:
7859 case Intrinsic::loongarch_lasx_xvmaxi_b:
7860 case Intrinsic::loongarch_lasx_xvmaxi_h:
7861 case Intrinsic::loongarch_lasx_xvmaxi_w:
7862 case Intrinsic::loongarch_lasx_xvmaxi_d:
7863 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7864 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7865 case Intrinsic::loongarch_lsx_vmaxi_bu:
7866 case Intrinsic::loongarch_lsx_vmaxi_hu:
7867 case Intrinsic::loongarch_lsx_vmaxi_wu:
7868 case Intrinsic::loongarch_lsx_vmaxi_du:
7869 case Intrinsic::loongarch_lasx_xvmaxi_bu:
7870 case Intrinsic::loongarch_lasx_xvmaxi_hu:
7871 case Intrinsic::loongarch_lasx_xvmaxi_wu:
7872 case Intrinsic::loongarch_lasx_xvmaxi_du:
7873 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7874 lowerVectorSplatImm<5>(N, 2, DAG));
7875 case Intrinsic::loongarch_lsx_vmin_b:
7876 case Intrinsic::loongarch_lsx_vmin_h:
7877 case Intrinsic::loongarch_lsx_vmin_w:
7878 case Intrinsic::loongarch_lsx_vmin_d:
7879 case Intrinsic::loongarch_lasx_xvmin_b:
7880 case Intrinsic::loongarch_lasx_xvmin_h:
7881 case Intrinsic::loongarch_lasx_xvmin_w:
7882 case Intrinsic::loongarch_lasx_xvmin_d:
7883 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7884 N->getOperand(2));
7885 case Intrinsic::loongarch_lsx_vmin_bu:
7886 case Intrinsic::loongarch_lsx_vmin_hu:
7887 case Intrinsic::loongarch_lsx_vmin_wu:
7888 case Intrinsic::loongarch_lsx_vmin_du:
7889 case Intrinsic::loongarch_lasx_xvmin_bu:
7890 case Intrinsic::loongarch_lasx_xvmin_hu:
7891 case Intrinsic::loongarch_lasx_xvmin_wu:
7892 case Intrinsic::loongarch_lasx_xvmin_du:
7893 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7894 N->getOperand(2));
7895 case Intrinsic::loongarch_lsx_vmini_b:
7896 case Intrinsic::loongarch_lsx_vmini_h:
7897 case Intrinsic::loongarch_lsx_vmini_w:
7898 case Intrinsic::loongarch_lsx_vmini_d:
7899 case Intrinsic::loongarch_lasx_xvmini_b:
7900 case Intrinsic::loongarch_lasx_xvmini_h:
7901 case Intrinsic::loongarch_lasx_xvmini_w:
7902 case Intrinsic::loongarch_lasx_xvmini_d:
7903 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7904 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7905 case Intrinsic::loongarch_lsx_vmini_bu:
7906 case Intrinsic::loongarch_lsx_vmini_hu:
7907 case Intrinsic::loongarch_lsx_vmini_wu:
7908 case Intrinsic::loongarch_lsx_vmini_du:
7909 case Intrinsic::loongarch_lasx_xvmini_bu:
7910 case Intrinsic::loongarch_lasx_xvmini_hu:
7911 case Intrinsic::loongarch_lasx_xvmini_wu:
7912 case Intrinsic::loongarch_lasx_xvmini_du:
7913 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7914 lowerVectorSplatImm<5>(N, 2, DAG));
7915 case Intrinsic::loongarch_lsx_vmul_b:
7916 case Intrinsic::loongarch_lsx_vmul_h:
7917 case Intrinsic::loongarch_lsx_vmul_w:
7918 case Intrinsic::loongarch_lsx_vmul_d:
7919 case Intrinsic::loongarch_lasx_xvmul_b:
7920 case Intrinsic::loongarch_lasx_xvmul_h:
7921 case Intrinsic::loongarch_lasx_xvmul_w:
7922 case Intrinsic::loongarch_lasx_xvmul_d:
7923 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
7924 N->getOperand(2));
7925 case Intrinsic::loongarch_lsx_vmadd_b:
7926 case Intrinsic::loongarch_lsx_vmadd_h:
7927 case Intrinsic::loongarch_lsx_vmadd_w:
7928 case Intrinsic::loongarch_lsx_vmadd_d:
7929 case Intrinsic::loongarch_lasx_xvmadd_b:
7930 case Intrinsic::loongarch_lasx_xvmadd_h:
7931 case Intrinsic::loongarch_lasx_xvmadd_w:
7932 case Intrinsic::loongarch_lasx_xvmadd_d: {
7933 EVT ResTy = N->getValueType(0);
7934 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
7935 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7936 N->getOperand(3)));
7937 }
7938 case Intrinsic::loongarch_lsx_vmsub_b:
7939 case Intrinsic::loongarch_lsx_vmsub_h:
7940 case Intrinsic::loongarch_lsx_vmsub_w:
7941 case Intrinsic::loongarch_lsx_vmsub_d:
7942 case Intrinsic::loongarch_lasx_xvmsub_b:
7943 case Intrinsic::loongarch_lasx_xvmsub_h:
7944 case Intrinsic::loongarch_lasx_xvmsub_w:
7945 case Intrinsic::loongarch_lasx_xvmsub_d: {
7946 EVT ResTy = N->getValueType(0);
7947 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
7948 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7949 N->getOperand(3)));
7950 }
7951 case Intrinsic::loongarch_lsx_vdiv_b:
7952 case Intrinsic::loongarch_lsx_vdiv_h:
7953 case Intrinsic::loongarch_lsx_vdiv_w:
7954 case Intrinsic::loongarch_lsx_vdiv_d:
7955 case Intrinsic::loongarch_lasx_xvdiv_b:
7956 case Intrinsic::loongarch_lasx_xvdiv_h:
7957 case Intrinsic::loongarch_lasx_xvdiv_w:
7958 case Intrinsic::loongarch_lasx_xvdiv_d:
7959 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
7960 N->getOperand(2));
7961 case Intrinsic::loongarch_lsx_vdiv_bu:
7962 case Intrinsic::loongarch_lsx_vdiv_hu:
7963 case Intrinsic::loongarch_lsx_vdiv_wu:
7964 case Intrinsic::loongarch_lsx_vdiv_du:
7965 case Intrinsic::loongarch_lasx_xvdiv_bu:
7966 case Intrinsic::loongarch_lasx_xvdiv_hu:
7967 case Intrinsic::loongarch_lasx_xvdiv_wu:
7968 case Intrinsic::loongarch_lasx_xvdiv_du:
7969 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
7970 N->getOperand(2));
7971 case Intrinsic::loongarch_lsx_vmod_b:
7972 case Intrinsic::loongarch_lsx_vmod_h:
7973 case Intrinsic::loongarch_lsx_vmod_w:
7974 case Intrinsic::loongarch_lsx_vmod_d:
7975 case Intrinsic::loongarch_lasx_xvmod_b:
7976 case Intrinsic::loongarch_lasx_xvmod_h:
7977 case Intrinsic::loongarch_lasx_xvmod_w:
7978 case Intrinsic::loongarch_lasx_xvmod_d:
7979 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
7980 N->getOperand(2));
7981 case Intrinsic::loongarch_lsx_vmod_bu:
7982 case Intrinsic::loongarch_lsx_vmod_hu:
7983 case Intrinsic::loongarch_lsx_vmod_wu:
7984 case Intrinsic::loongarch_lsx_vmod_du:
7985 case Intrinsic::loongarch_lasx_xvmod_bu:
7986 case Intrinsic::loongarch_lasx_xvmod_hu:
7987 case Intrinsic::loongarch_lasx_xvmod_wu:
7988 case Intrinsic::loongarch_lasx_xvmod_du:
7989 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
7990 N->getOperand(2));
7991 case Intrinsic::loongarch_lsx_vand_v:
7992 case Intrinsic::loongarch_lasx_xvand_v:
7993 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
7994 N->getOperand(2));
7995 case Intrinsic::loongarch_lsx_vor_v:
7996 case Intrinsic::loongarch_lasx_xvor_v:
7997 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7998 N->getOperand(2));
7999 case Intrinsic::loongarch_lsx_vxor_v:
8000 case Intrinsic::loongarch_lasx_xvxor_v:
8001 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8002 N->getOperand(2));
8003 case Intrinsic::loongarch_lsx_vnor_v:
8004 case Intrinsic::loongarch_lasx_xvnor_v: {
8005 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8006 N->getOperand(2));
8007 return DAG.getNOT(DL, Res, Res->getValueType(0));
8008 }
8009 case Intrinsic::loongarch_lsx_vandi_b:
8010 case Intrinsic::loongarch_lasx_xvandi_b:
8011 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8012 lowerVectorSplatImm<8>(N, 2, DAG));
8013 case Intrinsic::loongarch_lsx_vori_b:
8014 case Intrinsic::loongarch_lasx_xvori_b:
8015 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8016 lowerVectorSplatImm<8>(N, 2, DAG));
8017 case Intrinsic::loongarch_lsx_vxori_b:
8018 case Intrinsic::loongarch_lasx_xvxori_b:
8019 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8020 lowerVectorSplatImm<8>(N, 2, DAG));
8021 case Intrinsic::loongarch_lsx_vsll_b:
8022 case Intrinsic::loongarch_lsx_vsll_h:
8023 case Intrinsic::loongarch_lsx_vsll_w:
8024 case Intrinsic::loongarch_lsx_vsll_d:
8025 case Intrinsic::loongarch_lasx_xvsll_b:
8026 case Intrinsic::loongarch_lasx_xvsll_h:
8027 case Intrinsic::loongarch_lasx_xvsll_w:
8028 case Intrinsic::loongarch_lasx_xvsll_d:
8029 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8030 truncateVecElts(N, DAG));
8031 case Intrinsic::loongarch_lsx_vslli_b:
8032 case Intrinsic::loongarch_lasx_xvslli_b:
8033 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8034 lowerVectorSplatImm<3>(N, 2, DAG));
8035 case Intrinsic::loongarch_lsx_vslli_h:
8036 case Intrinsic::loongarch_lasx_xvslli_h:
8037 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8038 lowerVectorSplatImm<4>(N, 2, DAG));
8039 case Intrinsic::loongarch_lsx_vslli_w:
8040 case Intrinsic::loongarch_lasx_xvslli_w:
8041 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8042 lowerVectorSplatImm<5>(N, 2, DAG));
8043 case Intrinsic::loongarch_lsx_vslli_d:
8044 case Intrinsic::loongarch_lasx_xvslli_d:
8045 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8046 lowerVectorSplatImm<6>(N, 2, DAG));
8047 case Intrinsic::loongarch_lsx_vsrl_b:
8048 case Intrinsic::loongarch_lsx_vsrl_h:
8049 case Intrinsic::loongarch_lsx_vsrl_w:
8050 case Intrinsic::loongarch_lsx_vsrl_d:
8051 case Intrinsic::loongarch_lasx_xvsrl_b:
8052 case Intrinsic::loongarch_lasx_xvsrl_h:
8053 case Intrinsic::loongarch_lasx_xvsrl_w:
8054 case Intrinsic::loongarch_lasx_xvsrl_d:
8055 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8056 truncateVecElts(N, DAG));
8057 case Intrinsic::loongarch_lsx_vsrli_b:
8058 case Intrinsic::loongarch_lasx_xvsrli_b:
8059 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8060 lowerVectorSplatImm<3>(N, 2, DAG));
8061 case Intrinsic::loongarch_lsx_vsrli_h:
8062 case Intrinsic::loongarch_lasx_xvsrli_h:
8063 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8064 lowerVectorSplatImm<4>(N, 2, DAG));
8065 case Intrinsic::loongarch_lsx_vsrli_w:
8066 case Intrinsic::loongarch_lasx_xvsrli_w:
8067 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8068 lowerVectorSplatImm<5>(N, 2, DAG));
8069 case Intrinsic::loongarch_lsx_vsrli_d:
8070 case Intrinsic::loongarch_lasx_xvsrli_d:
8071 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8072 lowerVectorSplatImm<6>(N, 2, DAG));
8073 case Intrinsic::loongarch_lsx_vsra_b:
8074 case Intrinsic::loongarch_lsx_vsra_h:
8075 case Intrinsic::loongarch_lsx_vsra_w:
8076 case Intrinsic::loongarch_lsx_vsra_d:
8077 case Intrinsic::loongarch_lasx_xvsra_b:
8078 case Intrinsic::loongarch_lasx_xvsra_h:
8079 case Intrinsic::loongarch_lasx_xvsra_w:
8080 case Intrinsic::loongarch_lasx_xvsra_d:
8081 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8082 truncateVecElts(N, DAG));
8083 case Intrinsic::loongarch_lsx_vsrai_b:
8084 case Intrinsic::loongarch_lasx_xvsrai_b:
8085 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8086 lowerVectorSplatImm<3>(N, 2, DAG));
8087 case Intrinsic::loongarch_lsx_vsrai_h:
8088 case Intrinsic::loongarch_lasx_xvsrai_h:
8089 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8090 lowerVectorSplatImm<4>(N, 2, DAG));
8091 case Intrinsic::loongarch_lsx_vsrai_w:
8092 case Intrinsic::loongarch_lasx_xvsrai_w:
8093 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8094 lowerVectorSplatImm<5>(N, 2, DAG));
8095 case Intrinsic::loongarch_lsx_vsrai_d:
8096 case Intrinsic::loongarch_lasx_xvsrai_d:
8097 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8098 lowerVectorSplatImm<6>(N, 2, DAG));
8099 case Intrinsic::loongarch_lsx_vclz_b:
8100 case Intrinsic::loongarch_lsx_vclz_h:
8101 case Intrinsic::loongarch_lsx_vclz_w:
8102 case Intrinsic::loongarch_lsx_vclz_d:
8103 case Intrinsic::loongarch_lasx_xvclz_b:
8104 case Intrinsic::loongarch_lasx_xvclz_h:
8105 case Intrinsic::loongarch_lasx_xvclz_w:
8106 case Intrinsic::loongarch_lasx_xvclz_d:
8107 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
8108 case Intrinsic::loongarch_lsx_vpcnt_b:
8109 case Intrinsic::loongarch_lsx_vpcnt_h:
8110 case Intrinsic::loongarch_lsx_vpcnt_w:
8111 case Intrinsic::loongarch_lsx_vpcnt_d:
8112 case Intrinsic::loongarch_lasx_xvpcnt_b:
8113 case Intrinsic::loongarch_lasx_xvpcnt_h:
8114 case Intrinsic::loongarch_lasx_xvpcnt_w:
8115 case Intrinsic::loongarch_lasx_xvpcnt_d:
8116 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
8117 case Intrinsic::loongarch_lsx_vbitclr_b:
8118 case Intrinsic::loongarch_lsx_vbitclr_h:
8119 case Intrinsic::loongarch_lsx_vbitclr_w:
8120 case Intrinsic::loongarch_lsx_vbitclr_d:
8121 case Intrinsic::loongarch_lasx_xvbitclr_b:
8122 case Intrinsic::loongarch_lasx_xvbitclr_h:
8123 case Intrinsic::loongarch_lasx_xvbitclr_w:
8124 case Intrinsic::loongarch_lasx_xvbitclr_d:
8125 return lowerVectorBitClear(N, DAG);
8126 case Intrinsic::loongarch_lsx_vbitclri_b:
8127 case Intrinsic::loongarch_lasx_xvbitclri_b:
8128 return lowerVectorBitClearImm<3>(N, DAG);
8129 case Intrinsic::loongarch_lsx_vbitclri_h:
8130 case Intrinsic::loongarch_lasx_xvbitclri_h:
8131 return lowerVectorBitClearImm<4>(N, DAG);
8132 case Intrinsic::loongarch_lsx_vbitclri_w:
8133 case Intrinsic::loongarch_lasx_xvbitclri_w:
8134 return lowerVectorBitClearImm<5>(N, DAG);
8135 case Intrinsic::loongarch_lsx_vbitclri_d:
8136 case Intrinsic::loongarch_lasx_xvbitclri_d:
8137 return lowerVectorBitClearImm<6>(N, DAG);
8138 case Intrinsic::loongarch_lsx_vbitset_b:
8139 case Intrinsic::loongarch_lsx_vbitset_h:
8140 case Intrinsic::loongarch_lsx_vbitset_w:
8141 case Intrinsic::loongarch_lsx_vbitset_d:
8142 case Intrinsic::loongarch_lasx_xvbitset_b:
8143 case Intrinsic::loongarch_lasx_xvbitset_h:
8144 case Intrinsic::loongarch_lasx_xvbitset_w:
8145 case Intrinsic::loongarch_lasx_xvbitset_d: {
8146 EVT VecTy = N->getValueType(0);
8147 SDValue One = DAG.getConstant(1, DL, VecTy);
8148 return DAG.getNode(
8149 ISD::OR, DL, VecTy, N->getOperand(1),
8150 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8151 }
8152 case Intrinsic::loongarch_lsx_vbitseti_b:
8153 case Intrinsic::loongarch_lasx_xvbitseti_b:
8154 return lowerVectorBitSetImm<3>(N, DAG);
8155 case Intrinsic::loongarch_lsx_vbitseti_h:
8156 case Intrinsic::loongarch_lasx_xvbitseti_h:
8157 return lowerVectorBitSetImm<4>(N, DAG);
8158 case Intrinsic::loongarch_lsx_vbitseti_w:
8159 case Intrinsic::loongarch_lasx_xvbitseti_w:
8160 return lowerVectorBitSetImm<5>(N, DAG);
8161 case Intrinsic::loongarch_lsx_vbitseti_d:
8162 case Intrinsic::loongarch_lasx_xvbitseti_d:
8163 return lowerVectorBitSetImm<6>(N, DAG);
8164 case Intrinsic::loongarch_lsx_vbitrev_b:
8165 case Intrinsic::loongarch_lsx_vbitrev_h:
8166 case Intrinsic::loongarch_lsx_vbitrev_w:
8167 case Intrinsic::loongarch_lsx_vbitrev_d:
8168 case Intrinsic::loongarch_lasx_xvbitrev_b:
8169 case Intrinsic::loongarch_lasx_xvbitrev_h:
8170 case Intrinsic::loongarch_lasx_xvbitrev_w:
8171 case Intrinsic::loongarch_lasx_xvbitrev_d: {
8172 EVT VecTy = N->getValueType(0);
8173 SDValue One = DAG.getConstant(1, DL, VecTy);
8174 return DAG.getNode(
8175 ISD::XOR, DL, VecTy, N->getOperand(1),
8176 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8177 }
8178 case Intrinsic::loongarch_lsx_vbitrevi_b:
8179 case Intrinsic::loongarch_lasx_xvbitrevi_b:
8180 return lowerVectorBitRevImm<3>(N, DAG);
8181 case Intrinsic::loongarch_lsx_vbitrevi_h:
8182 case Intrinsic::loongarch_lasx_xvbitrevi_h:
8183 return lowerVectorBitRevImm<4>(N, DAG);
8184 case Intrinsic::loongarch_lsx_vbitrevi_w:
8185 case Intrinsic::loongarch_lasx_xvbitrevi_w:
8186 return lowerVectorBitRevImm<5>(N, DAG);
8187 case Intrinsic::loongarch_lsx_vbitrevi_d:
8188 case Intrinsic::loongarch_lasx_xvbitrevi_d:
8189 return lowerVectorBitRevImm<6>(N, DAG);
8190 case Intrinsic::loongarch_lsx_vfadd_s:
8191 case Intrinsic::loongarch_lsx_vfadd_d:
8192 case Intrinsic::loongarch_lasx_xvfadd_s:
8193 case Intrinsic::loongarch_lasx_xvfadd_d:
8194 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
8195 N->getOperand(2));
8196 case Intrinsic::loongarch_lsx_vfsub_s:
8197 case Intrinsic::loongarch_lsx_vfsub_d:
8198 case Intrinsic::loongarch_lasx_xvfsub_s:
8199 case Intrinsic::loongarch_lasx_xvfsub_d:
8200 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
8201 N->getOperand(2));
8202 case Intrinsic::loongarch_lsx_vfmul_s:
8203 case Intrinsic::loongarch_lsx_vfmul_d:
8204 case Intrinsic::loongarch_lasx_xvfmul_s:
8205 case Intrinsic::loongarch_lasx_xvfmul_d:
8206 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
8207 N->getOperand(2));
8208 case Intrinsic::loongarch_lsx_vfdiv_s:
8209 case Intrinsic::loongarch_lsx_vfdiv_d:
8210 case Intrinsic::loongarch_lasx_xvfdiv_s:
8211 case Intrinsic::loongarch_lasx_xvfdiv_d:
8212 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
8213 N->getOperand(2));
8214 case Intrinsic::loongarch_lsx_vfmadd_s:
8215 case Intrinsic::loongarch_lsx_vfmadd_d:
8216 case Intrinsic::loongarch_lasx_xvfmadd_s:
8217 case Intrinsic::loongarch_lasx_xvfmadd_d:
8218 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
8219 N->getOperand(2), N->getOperand(3));
8220 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
8221 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8222 N->getOperand(1), N->getOperand(2),
8223 legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
8224 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
8225 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
8226 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8227 N->getOperand(1), N->getOperand(2),
8228 legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
8229 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
8230 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
8231 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8232 N->getOperand(1), N->getOperand(2),
8233 legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
8234 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
8235 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8236 N->getOperand(1), N->getOperand(2),
8237 legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
8238 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
8239 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
8240 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
8241 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
8242 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
8243 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
8244 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
8245 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
8246 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
8247 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8248 N->getOperand(1)));
8249 case Intrinsic::loongarch_lsx_vreplve_b:
8250 case Intrinsic::loongarch_lsx_vreplve_h:
8251 case Intrinsic::loongarch_lsx_vreplve_w:
8252 case Intrinsic::loongarch_lsx_vreplve_d:
8253 case Intrinsic::loongarch_lasx_xvreplve_b:
8254 case Intrinsic::loongarch_lasx_xvreplve_h:
8255 case Intrinsic::loongarch_lasx_xvreplve_w:
8256 case Intrinsic::loongarch_lasx_xvreplve_d:
8257 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
8258 N->getOperand(1),
8259 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8260 N->getOperand(2)));
8261 case Intrinsic::loongarch_lsx_vpickve2gr_b:
8262 if (!Subtarget.is64Bit())
8263 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8264 break;
8265 case Intrinsic::loongarch_lsx_vpickve2gr_h:
8266 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
8267 if (!Subtarget.is64Bit())
8268 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8269 break;
8270 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8271 if (!Subtarget.is64Bit())
8272 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8273 break;
8274 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8275 if (!Subtarget.is64Bit())
8276 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8277 break;
8278 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8279 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8280 if (!Subtarget.is64Bit())
8281 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8282 break;
8283 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8284 if (!Subtarget.is64Bit())
8285 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8286 break;
8287 case Intrinsic::loongarch_lsx_bz_b:
8288 case Intrinsic::loongarch_lsx_bz_h:
8289 case Intrinsic::loongarch_lsx_bz_w:
8290 case Intrinsic::loongarch_lsx_bz_d:
8291 case Intrinsic::loongarch_lasx_xbz_b:
8292 case Intrinsic::loongarch_lasx_xbz_h:
8293 case Intrinsic::loongarch_lasx_xbz_w:
8294 case Intrinsic::loongarch_lasx_xbz_d:
8295 if (!Subtarget.is64Bit())
8296 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8297 N->getOperand(1));
8298 break;
8299 case Intrinsic::loongarch_lsx_bz_v:
8300 case Intrinsic::loongarch_lasx_xbz_v:
8301 if (!Subtarget.is64Bit())
8302 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8303 N->getOperand(1));
8304 break;
8305 case Intrinsic::loongarch_lsx_bnz_b:
8306 case Intrinsic::loongarch_lsx_bnz_h:
8307 case Intrinsic::loongarch_lsx_bnz_w:
8308 case Intrinsic::loongarch_lsx_bnz_d:
8309 case Intrinsic::loongarch_lasx_xbnz_b:
8310 case Intrinsic::loongarch_lasx_xbnz_h:
8311 case Intrinsic::loongarch_lasx_xbnz_w:
8312 case Intrinsic::loongarch_lasx_xbnz_d:
8313 if (!Subtarget.is64Bit())
8314 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8315 N->getOperand(1));
8316 break;
8317 case Intrinsic::loongarch_lsx_bnz_v:
8318 case Intrinsic::loongarch_lasx_xbnz_v:
8319 if (!Subtarget.is64Bit())
8320 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8321 N->getOperand(1));
8322 break;
8323 case Intrinsic::loongarch_lasx_concat_128_s:
8324 case Intrinsic::loongarch_lasx_concat_128_d:
8325 case Intrinsic::loongarch_lasx_concat_128:
8326 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8327 N->getOperand(1), N->getOperand(2));
8328 }
8329 return SDValue();
8330}
8331
8334 const LoongArchSubtarget &Subtarget) {
8335 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8336 // conversion is unnecessary and can be replaced with the
8337 // MOVFR2GR_S_LA64 operand.
8338 SDValue Op0 = N->getOperand(0);
8339 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8340 return Op0.getOperand(0);
8341 return SDValue();
8342}
8343
8346 const LoongArchSubtarget &Subtarget) {
8347 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8348 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8349 // operand.
8350 SDValue Op0 = N->getOperand(0);
8351 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8352 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8353 "Unexpected value type!");
8354 return Op0.getOperand(0);
8355 }
8356 return SDValue();
8357}
8358
8359static SDValue
8362 MVT VT = N->getSimpleValueType(0);
8363 unsigned NumBits = VT.getScalarSizeInBits();
8364
8365 // Simplify the inputs.
8366 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8367 APInt DemandedMask(APInt::getAllOnes(NumBits));
8368 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8369 return SDValue(N, 0);
8370
8371 return SDValue();
8372}
8373
8374static SDValue
8377 const LoongArchSubtarget &Subtarget) {
8378 SDValue Op0 = N->getOperand(0);
8379 SDLoc DL(N);
8380
8381 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8382 // redundant. Instead, use BuildPairF64's operands directly.
8383 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8384 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8385
8386 if (Op0->isUndef()) {
8387 SDValue Lo = DAG.getUNDEF(MVT::i32);
8388 SDValue Hi = DAG.getUNDEF(MVT::i32);
8389 return DCI.CombineTo(N, Lo, Hi);
8390 }
8391
8392 // It's cheaper to materialise two 32-bit integers than to load a double
8393 // from the constant pool and transfer it to integer registers through the
8394 // stack.
8396 APInt V = C->getValueAPF().bitcastToAPInt();
8397 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8398 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8399 return DCI.CombineTo(N, Lo, Hi);
8400 }
8401
8402 return SDValue();
8403}
8404
8405/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8408 const LoongArchSubtarget &Subtarget) {
8409 SDValue N0 = N->getOperand(0);
8410 SDValue N1 = N->getOperand(1);
8411 MVT VT = N->getSimpleValueType(0);
8412 SDLoc DL(N);
8413
8414 // VANDN(undef, x) -> 0
8415 // VANDN(x, undef) -> 0
8416 if (N0.isUndef() || N1.isUndef())
8417 return DAG.getConstant(0, DL, VT);
8418
8419 // VANDN(0, x) -> x
8421 return N1;
8422
8423 // VANDN(x, 0) -> 0
8425 return DAG.getConstant(0, DL, VT);
8426
8427 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8429 return DAG.getNOT(DL, N0, VT);
8430
8431 // Turn VANDN back to AND if input is inverted.
8432 if (SDValue Not = isNOT(N0, DAG))
8433 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8434
8435 // Folds for better commutativity:
8436 if (N1->hasOneUse()) {
8437 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8438 if (SDValue Not = isNOT(N1, DAG))
8439 return DAG.getNOT(
8440 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8441
8442 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8443 // -> NOT(OR(x, SplatVector(-Imm))
8444 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8445 // gain benefits.
8446 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8447 N1.getOpcode() == ISD::BUILD_VECTOR) {
8448 if (SDValue SplatValue =
8449 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8450 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8451 return SDValue();
8452
8453 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8454 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8455 SDValue Not =
8456 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8457 return DAG.getNOT(
8458 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8459 VT);
8460 }
8461 }
8462 }
8463 }
8464
8465 return SDValue();
8466}
8467
8468static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8469 SDLoc DL(N);
8470 EVT VT = N->getValueType(0);
8471 SDValue Src = N->getOperand(0);
8472 EVT SrcVT = Src.getValueType();
8473
8474 unsigned DstElts = VT.getVectorNumElements();
8475 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8476 unsigned DstEltBits = VT.getScalarSizeInBits();
8477
8478 if (SrcEltBits >= DstEltBits)
8479 return SDValue();
8480
8481 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8482 EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
8483
8484 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8485 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8486}
8487
8488// Merge two 64 to 32 convert instructions into one,
8489// e.g.
8490// vffint.s.l $vr0, $vr1, $vr2
8491// will convert 4 si64 into 4 float at once.
8492// or
8493// vftintrz.w.d $vr0, $vr1, $vr2
8494// which will convert 4 double into 4 si32 at once.
8495// also deal with their 256-bits LASX version.
8496static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8497 unsigned BlockBits) {
8498 SDLoc DL(N);
8499 MVT DstVT = N->getSimpleValueType(0);
8500 SDValue Src = N->getOperand(0);
8501 MVT SrcVT = Src.getSimpleValueType();
8502 unsigned SrcBits = SrcVT.getSizeInBits();
8503
8505 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8506 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8507 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8508 Src.getOperand(0).getValueType() == BlockVT) {
8509 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8510 Blocks.push_back(Src.getOperand(i));
8511 } else if (SrcBits > BlockBits) {
8512 // Wider than one register: extract each BlockBits-wide sub-vector.
8513 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8514 Blocks.push_back(
8515 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8516 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8517 } else {
8518 BlockBits = SrcBits;
8519 Blocks.push_back(Src);
8520 }
8521
8522 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8523 BlockBits / DstVT.getScalarSizeInBits());
8525 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8526 SDValue Lo = Blocks[i];
8527 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8528 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8529
8530 if (BlockBits == 256) {
8531 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8532 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8533 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8534 Res = DAG.getBitcast(NativeVecVT, Res);
8535 }
8536
8537 Parts.push_back(Res);
8538 }
8539
8540 if (Blocks.size() == 1)
8541 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8542 DAG.getVectorIdxConstant(0, DL));
8543 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8544}
8545
8548 const LoongArchSubtarget &Subtarget) {
8549 SDLoc DL(N);
8550 EVT VT = N->getValueType(0);
8551 SDValue Src = N->getOperand(0);
8552 EVT SrcVT = Src.getValueType();
8553
8554 if (VT.isVector()) {
8555 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8556 unsigned DstEltBits = VT.getScalarSizeInBits();
8557 unsigned NumElts = VT.getVectorNumElements();
8558 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8559
8560 // Sign-extend src to avoid scalarization.
8561 if (SrcEltBits <= DstEltBits)
8562 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8563
8564 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8565 return SDValue();
8566
8567 if (!SrcVT.isSimple() || !VT.isSimple())
8568 return SDValue();
8569
8570 // [x]vffint.s.l needs LSX and at least one full 128-bit source register.
8571 if (!Subtarget.hasExtLSX() || SrcVT.getSizeInBits() < 128)
8572 return SDValue();
8573
8574 // Combine [x]vffint.s.l for vector si64 to float conversion.
8575 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8576 }
8577
8578 if (VT != MVT::f32 && VT != MVT::f64)
8579 return SDValue();
8580 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8581 return SDValue();
8582 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8583 return SDValue();
8584
8585 // Only optimize when the source and destination types have the same width.
8586 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8587 return SDValue();
8588
8589 // If the result of an integer load is only used by an integer-to-float
8590 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8591 // (movgr2fr) instruction.
8592 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8593 // Do not change the width of a volatile load. This condition check is
8594 // inspired by AArch64.
8595 !cast<LoadSDNode>(Src)->isVolatile()) {
8596 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8597 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8598 LN0->getPointerInfo(), LN0->getAlign(),
8599 LN0->getMemOperand()->getFlags());
8600
8601 // Make sure successors of the original load stay after it by updating them
8602 // to use the new Chain.
8603 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8604 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8605 }
8606
8607 return SDValue();
8608}
8609
8612 const LoongArchSubtarget &Subtarget) {
8613 SDLoc DL(N);
8614 EVT VT = N->getValueType(0);
8615
8616 // Zero-extend src to avoid scalarization.
8617 if (VT.isVector())
8618 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8619
8620 return SDValue();
8621}
8622
8623// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
8624// For example:
8625// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
8626// Can be combined into:
8627// v4i32 = VFTINTRZ_W_D v2f64. v2f64
8630 const LoongArchSubtarget &Subtarget) {
8631 if (!Subtarget.hasExtLSX())
8632 return SDValue();
8633
8634 SDLoc DL(N);
8635 EVT DstVT = N->getValueType(0);
8636 SDValue Src = N->getOperand(0);
8637 EVT SrcVT = Src.getValueType();
8638 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
8639
8640 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
8641 return SDValue();
8642
8643 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8644 unsigned SrcBits = SrcVT.getSizeInBits();
8645 unsigned DstEltBits = DstVT.getScalarSizeInBits();
8646 unsigned NumElts = DstVT.getVectorNumElements();
8647 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8648
8649 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
8650 return SDValue();
8651
8652 if (SrcBits % BlockBits != 0 && SrcBits != 128)
8653 return SDValue();
8654
8655 if (DstEltBits < 32) {
8656 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
8657 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
8658 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
8659 }
8660
8661 if (SrcEltBits != 64 || DstEltBits != 32)
8662 return SDValue();
8663
8664 if (!IsSigned) {
8665 // LASX already has pattern for double convert to uint32.
8666 if (Subtarget.hasExtLASX())
8667 return SDValue();
8668 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
8669 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
8670 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
8671 }
8672
8673 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
8674}
8675
8676// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
8677// logical operations, like in the example below.
8678// or (and (truncate x, truncate y)),
8679// (xor (truncate z, build_vector (constants)))
8680// Given a target type \p VT, we generate
8681// or (and x, y), (xor z, zext(build_vector (constants)))
8682// given x, y and z are of type \p VT. We can do so, if operands are either
8683// truncates from VT types, the second operand is a vector of constants, can
8684// be recursively promoted or is an existing extension we can extend further.
8686 SelectionDAG &DAG,
8687 const LoongArchSubtarget &Subtarget,
8688 unsigned Depth) {
8689 // Limit recursion to avoid excessive compile times.
8691 return SDValue();
8692
8693 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
8694 return SDValue();
8695
8696 SDValue N0 = N.getOperand(0);
8697 SDValue N1 = N.getOperand(1);
8698
8699 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8700 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
8701 return SDValue();
8702
8703 if (SDValue NN0 =
8704 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
8705 N0 = NN0;
8706 else {
8707 // The left side has to be a 'trunc'.
8708 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
8709 N0.getOperand(0).getValueType() == VT;
8710 if (LHSTrunc)
8711 N0 = N0.getOperand(0);
8712 else
8713 return SDValue();
8714 }
8715
8716 if (SDValue NN1 =
8717 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
8718 N1 = NN1;
8719 else {
8720 // The right side has to be a 'trunc', a (foldable) constant or an
8721 // existing extension we can extend further.
8722 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
8723 N1.getOperand(0).getValueType() == VT;
8724 if (RHSTrunc)
8725 N1 = N1.getOperand(0);
8726 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
8727 Subtarget.hasExtLASX() && N1.hasOneUse())
8728 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
8729 // On 32-bit platform, i64 is an illegal integer scalar type, and
8730 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
8731 // future.
8732 else if (SDValue Cst =
8734 N1 = Cst;
8735 else
8736 return SDValue();
8737 }
8738
8739 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
8740}
8741
8742// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
8743// is LSX-sized register. In most cases we actually compare or select LASX-sized
8744// registers and mixing the two types creates horrible code. This method
8745// optimizes some of the transition sequences.
8747 SelectionDAG &DAG,
8748 const LoongArchSubtarget &Subtarget) {
8749 EVT VT = N.getValueType();
8750 assert(VT.isVector() && "Expected vector type");
8751 assert((N.getOpcode() == ISD::ANY_EXTEND ||
8752 N.getOpcode() == ISD::ZERO_EXTEND ||
8753 N.getOpcode() == ISD::SIGN_EXTEND) &&
8754 "Invalid Node");
8755
8756 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
8757 return SDValue();
8758
8759 SDValue Narrow = N.getOperand(0);
8760 EVT NarrowVT = Narrow.getValueType();
8761
8762 // Generate the wide operation.
8763 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
8764 if (!Op)
8765 return SDValue();
8766 switch (N.getOpcode()) {
8767 default:
8768 llvm_unreachable("Unexpected opcode");
8769 case ISD::ANY_EXTEND:
8770 return Op;
8771 case ISD::ZERO_EXTEND:
8772 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
8773 case ISD::SIGN_EXTEND:
8774 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
8775 DAG.getValueType(NarrowVT));
8776 }
8777}
8778
8781 const LoongArchSubtarget &Subtarget) {
8782 EVT VT = N->getValueType(0);
8783 SDLoc DL(N);
8784
8785 if (VT.isVector()) {
8786 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
8787 return R;
8788
8789 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
8790 N->getValueSizeInBits(0) != N->getOperand(0).getValueSizeInBits() * 2)
8791 return SDValue();
8792
8793 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
8794 if (N->getOpcode() == ISD::SIGN_EXTEND)
8795 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
8796 if (N->getOpcode() == ISD::ZERO_EXTEND)
8797 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
8798 }
8799 }
8800
8801 return SDValue();
8802}
8803
8804static SDValue
8807 const LoongArchSubtarget &Subtarget) {
8808 SDLoc DL(N);
8809 EVT VT = N->getValueType(0);
8810
8811 if (VT.isVector() && N->getNumOperands() == 2)
8812 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
8813 return R;
8814
8815 return SDValue();
8816}
8817
8820 const LoongArchSubtarget &Subtarget) {
8821 if (DCI.isBeforeLegalizeOps())
8822 return SDValue();
8823
8824 EVT VT = N->getValueType(0);
8825 if (!VT.isVector())
8826 return SDValue();
8827
8828 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
8829 return SDValue();
8830
8831 EVT EltVT = VT.getVectorElementType();
8832 if (!EltVT.isInteger())
8833 return SDValue();
8834
8835 SDValue Cond = N->getOperand(0);
8836 SDValue TrueVal = N->getOperand(1);
8837 SDValue FalseVal = N->getOperand(2);
8838
8839 // match:
8840 //
8841 // vselect (setcc shift, 0, seteq),
8842 // x,
8843 // rounded_shift
8844
8845 if (Cond.getOpcode() != ISD::SETCC)
8846 return SDValue();
8847
8848 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
8849 return SDValue();
8850
8851 auto *CC = cast<CondCodeSDNode>(Cond.getOperand(2));
8852 if (CC->get() != ISD::SETEQ)
8853 return SDValue();
8854
8855 SDValue Shift = Cond.getOperand(0);
8856
8857 // True branch must be original value:
8858 //
8859 // vselect cond, x, ...
8860
8861 SDValue X = TrueVal;
8862
8863 // Now match rounded shift pattern:
8864 //
8865 // add
8866 // (and
8867 // (srl X, shift-1)
8868 // 1)
8869 // (srl/sra X, shift)
8870
8871 if (FalseVal.getOpcode() != ISD::ADD)
8872 return SDValue();
8873
8874 SDValue Add0 = FalseVal.getOperand(0);
8875 SDValue Add1 = FalseVal.getOperand(1);
8876 SDValue And;
8877 SDValue Shr;
8878
8879 if (Add0.getOpcode() == ISD::AND) {
8880 And = Add0;
8881 Shr = Add1;
8882 } else if (Add1.getOpcode() == ISD::AND) {
8883 And = Add1;
8884 Shr = Add0;
8885 } else {
8886 return SDValue();
8887 }
8888
8889 // match:
8890 //
8891 // srl/sra X, shift
8892
8893 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
8894 return SDValue();
8895
8896 if (Shr.getOperand(0) != X)
8897 return SDValue();
8898
8899 if (Shr.getOperand(1) != Shift)
8900 return SDValue();
8901
8902 // match:
8903 //
8904 // and
8905 // (srl X, shift-1)
8906 // 1
8907
8908 SDValue Srl = And.getOperand(0);
8909 SDValue One = And.getOperand(1);
8910 APInt SplatVal;
8911
8912 if (Srl.getOpcode() != ISD::SRL)
8913 return SDValue();
8914
8915 One = peekThroughBitcasts(One);
8916 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
8917 return SDValue();
8918
8919 if (SplatVal != 1)
8920 return SDValue();
8921
8922 if (Srl.getOperand(0) != X)
8923 return SDValue();
8924
8925 // match:
8926 //
8927 // shift-1
8928
8929 SDValue ShiftMinus1 = Srl.getOperand(1);
8930
8931 if (ShiftMinus1.getOpcode() != ISD::ADD)
8932 return SDValue();
8933
8934 if (ShiftMinus1.getOperand(0) != Shift)
8935 return SDValue();
8936
8938 return SDValue();
8939
8940 // We matched a rounded right shift pattern and can lower it
8941 // to a single vector rounded shift instruction.
8942
8943 SDLoc DL(N);
8944 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
8945 : LoongArchISD::VSRAR,
8946 DL, VT, X, Shift);
8947}
8948
8950 DAGCombinerInfo &DCI) const {
8951 SelectionDAG &DAG = DCI.DAG;
8952 switch (N->getOpcode()) {
8953 default:
8954 break;
8955 case ISD::ADD:
8956 return performADDCombine(N, DAG, DCI, Subtarget);
8957 case ISD::AND:
8958 return performANDCombine(N, DAG, DCI, Subtarget);
8959 case ISD::OR:
8960 return performORCombine(N, DAG, DCI, Subtarget);
8961 case ISD::SETCC:
8962 return performSETCCCombine(N, DAG, DCI, Subtarget);
8963 case ISD::SELECT:
8964 return performSELECTCombine(N, DAG, DCI, Subtarget);
8965 case ISD::SHL:
8966 return performSHLCombine(N, DAG, DCI, Subtarget);
8967 case ISD::SRL:
8968 return performSRLCombine(N, DAG, DCI, Subtarget);
8969 case ISD::SUB:
8970 return performSUBCombine(N, DAG, DCI, Subtarget);
8971 case ISD::BITCAST:
8972 return performBITCASTCombine(N, DAG, DCI, Subtarget);
8973 case ISD::ANY_EXTEND:
8974 case ISD::ZERO_EXTEND:
8975 case ISD::SIGN_EXTEND:
8976 return performEXTENDCombine(N, DAG, DCI, Subtarget);
8977 case ISD::SINT_TO_FP:
8978 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8979 case ISD::UINT_TO_FP:
8980 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8981 case ISD::FP_TO_SINT:
8982 case ISD::FP_TO_UINT:
8983 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
8984 case LoongArchISD::BITREV_W:
8985 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
8986 case LoongArchISD::BR_CC:
8987 return performBR_CCCombine(N, DAG, DCI, Subtarget);
8988 case LoongArchISD::SELECT_CC:
8989 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
8991 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
8992 case LoongArchISD::MOVGR2FR_W_LA64:
8993 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
8994 case LoongArchISD::MOVFR2GR_S_LA64:
8995 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
8996 case LoongArchISD::CRC_W_B_W:
8997 case LoongArchISD::CRC_W_H_W:
8998 case LoongArchISD::CRCC_W_B_W:
8999 case LoongArchISD::CRCC_W_H_W:
9000 case LoongArchISD::VMSKLTZ:
9001 case LoongArchISD::XVMSKLTZ:
9002 return performDemandedBitsCombine(N, DAG, DCI);
9003 case LoongArchISD::SPLIT_PAIR_F64:
9004 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
9005 case LoongArchISD::VANDN:
9006 return performVANDNCombine(N, DAG, DCI, Subtarget);
9008 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
9009 case ISD::VSELECT:
9010 return performVSELECTCombine(N, DAG, DCI, Subtarget);
9011 case LoongArchISD::VPACKEV:
9012 case LoongArchISD::VPERMI:
9013 if (SDValue Result =
9014 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
9015 return Result;
9016 }
9017 return SDValue();
9018}
9019
9022 if (!ZeroDivCheck)
9023 return MBB;
9024
9025 // Build instructions:
9026 // MBB:
9027 // div(or mod) $dst, $dividend, $divisor
9028 // bne $divisor, $zero, SinkMBB
9029 // BreakMBB:
9030 // break 7 // BRK_DIVZERO
9031 // SinkMBB:
9032 // fallthrough
9033 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
9034 MachineFunction::iterator It = ++MBB->getIterator();
9035 MachineFunction *MF = MBB->getParent();
9036 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9037 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9038 MF->insert(It, BreakMBB);
9039 MF->insert(It, SinkMBB);
9040
9041 // Transfer the remainder of MBB and its successor edges to SinkMBB.
9042 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
9043 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
9044
9045 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
9046 DebugLoc DL = MI.getDebugLoc();
9047 MachineOperand &Divisor = MI.getOperand(2);
9048 Register DivisorReg = Divisor.getReg();
9049
9050 // MBB:
9051 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
9052 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
9053 .addReg(LoongArch::R0)
9054 .addMBB(SinkMBB);
9055 MBB->addSuccessor(BreakMBB);
9056 MBB->addSuccessor(SinkMBB);
9057
9058 // BreakMBB:
9059 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
9060 // definition of BRK_DIVZERO.
9061 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
9062 BreakMBB->addSuccessor(SinkMBB);
9063
9064 // Clear Divisor's kill flag.
9065 Divisor.setIsKill(false);
9066
9067 return SinkMBB;
9068}
9069
9070static MachineBasicBlock *
9072 const LoongArchSubtarget &Subtarget) {
9073 unsigned CondOpc;
9074 switch (MI.getOpcode()) {
9075 default:
9076 llvm_unreachable("Unexpected opcode");
9077 case LoongArch::PseudoVBZ:
9078 CondOpc = LoongArch::VSETEQZ_V;
9079 break;
9080 case LoongArch::PseudoVBZ_B:
9081 CondOpc = LoongArch::VSETANYEQZ_B;
9082 break;
9083 case LoongArch::PseudoVBZ_H:
9084 CondOpc = LoongArch::VSETANYEQZ_H;
9085 break;
9086 case LoongArch::PseudoVBZ_W:
9087 CondOpc = LoongArch::VSETANYEQZ_W;
9088 break;
9089 case LoongArch::PseudoVBZ_D:
9090 CondOpc = LoongArch::VSETANYEQZ_D;
9091 break;
9092 case LoongArch::PseudoVBNZ:
9093 CondOpc = LoongArch::VSETNEZ_V;
9094 break;
9095 case LoongArch::PseudoVBNZ_B:
9096 CondOpc = LoongArch::VSETALLNEZ_B;
9097 break;
9098 case LoongArch::PseudoVBNZ_H:
9099 CondOpc = LoongArch::VSETALLNEZ_H;
9100 break;
9101 case LoongArch::PseudoVBNZ_W:
9102 CondOpc = LoongArch::VSETALLNEZ_W;
9103 break;
9104 case LoongArch::PseudoVBNZ_D:
9105 CondOpc = LoongArch::VSETALLNEZ_D;
9106 break;
9107 case LoongArch::PseudoXVBZ:
9108 CondOpc = LoongArch::XVSETEQZ_V;
9109 break;
9110 case LoongArch::PseudoXVBZ_B:
9111 CondOpc = LoongArch::XVSETANYEQZ_B;
9112 break;
9113 case LoongArch::PseudoXVBZ_H:
9114 CondOpc = LoongArch::XVSETANYEQZ_H;
9115 break;
9116 case LoongArch::PseudoXVBZ_W:
9117 CondOpc = LoongArch::XVSETANYEQZ_W;
9118 break;
9119 case LoongArch::PseudoXVBZ_D:
9120 CondOpc = LoongArch::XVSETANYEQZ_D;
9121 break;
9122 case LoongArch::PseudoXVBNZ:
9123 CondOpc = LoongArch::XVSETNEZ_V;
9124 break;
9125 case LoongArch::PseudoXVBNZ_B:
9126 CondOpc = LoongArch::XVSETALLNEZ_B;
9127 break;
9128 case LoongArch::PseudoXVBNZ_H:
9129 CondOpc = LoongArch::XVSETALLNEZ_H;
9130 break;
9131 case LoongArch::PseudoXVBNZ_W:
9132 CondOpc = LoongArch::XVSETALLNEZ_W;
9133 break;
9134 case LoongArch::PseudoXVBNZ_D:
9135 CondOpc = LoongArch::XVSETALLNEZ_D;
9136 break;
9137 }
9138
9139 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9140 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9141 DebugLoc DL = MI.getDebugLoc();
9144
9145 MachineFunction *F = BB->getParent();
9146 MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
9147 MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
9148 MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
9149
9150 F->insert(It, FalseBB);
9151 F->insert(It, TrueBB);
9152 F->insert(It, SinkBB);
9153
9154 // Transfer the remainder of MBB and its successor edges to Sink.
9155 SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
9157
9158 // Insert the real instruction to BB.
9159 Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
9160 BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
9161
9162 // Insert branch.
9163 BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
9164 BB->addSuccessor(FalseBB);
9165 BB->addSuccessor(TrueBB);
9166
9167 // FalseBB.
9168 Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9169 BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
9170 .addReg(LoongArch::R0)
9171 .addImm(0);
9172 BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
9173 FalseBB->addSuccessor(SinkBB);
9174
9175 // TrueBB.
9176 Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9177 BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
9178 .addReg(LoongArch::R0)
9179 .addImm(1);
9180 TrueBB->addSuccessor(SinkBB);
9181
9182 // SinkBB: merge the results.
9183 BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
9184 MI.getOperand(0).getReg())
9185 .addReg(RD1)
9186 .addMBB(FalseBB)
9187 .addReg(RD2)
9188 .addMBB(TrueBB);
9189
9190 // The pseudo instruction is gone now.
9191 MI.eraseFromParent();
9192 return SinkBB;
9193}
9194
9195static MachineBasicBlock *
9197 const LoongArchSubtarget &Subtarget) {
9198 unsigned InsOp;
9199 unsigned BroadcastOp;
9200 unsigned HalfSize;
9201 switch (MI.getOpcode()) {
9202 default:
9203 llvm_unreachable("Unexpected opcode");
9204 case LoongArch::PseudoXVINSGR2VR_B:
9205 HalfSize = 16;
9206 BroadcastOp = LoongArch::XVREPLGR2VR_B;
9207 InsOp = LoongArch::XVEXTRINS_B;
9208 break;
9209 case LoongArch::PseudoXVINSGR2VR_H:
9210 HalfSize = 8;
9211 BroadcastOp = LoongArch::XVREPLGR2VR_H;
9212 InsOp = LoongArch::XVEXTRINS_H;
9213 break;
9214 }
9215 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9216 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
9217 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
9218 DebugLoc DL = MI.getDebugLoc();
9220 // XDst = vector_insert XSrc, Elt, Idx
9221 Register XDst = MI.getOperand(0).getReg();
9222 Register XSrc = MI.getOperand(1).getReg();
9223 Register Elt = MI.getOperand(2).getReg();
9224 unsigned Idx = MI.getOperand(3).getImm();
9225
9226 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
9227 Idx < HalfSize) {
9228 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
9229 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
9230
9231 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
9232 .addReg(XSrc, {}, LoongArch::sub_128);
9233 BuildMI(*BB, MI, DL,
9234 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
9235 : LoongArch::VINSGR2VR_B),
9236 ScratchSubReg2)
9237 .addReg(ScratchSubReg1)
9238 .addReg(Elt)
9239 .addImm(Idx);
9240
9241 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
9242 .addReg(ScratchSubReg2)
9243 .addImm(LoongArch::sub_128);
9244 } else {
9245 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9246 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9247
9248 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
9249
9250 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
9251 .addReg(ScratchReg1)
9252 .addReg(XSrc)
9253 .addImm(Idx >= HalfSize ? 48 : 18);
9254
9255 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
9256 .addReg(XSrc)
9257 .addReg(ScratchReg2)
9258 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
9259 }
9260
9261 MI.eraseFromParent();
9262 return BB;
9263}
9264
9267 const LoongArchSubtarget &Subtarget) {
9268 assert(Subtarget.hasExtLSX());
9269 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9270 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9271 DebugLoc DL = MI.getDebugLoc();
9273 Register Dst = MI.getOperand(0).getReg();
9274 Register Src = MI.getOperand(1).getReg();
9275
9276 unsigned BroadcastOp, CTOp, PickOp;
9277 switch (MI.getOpcode()) {
9278 default:
9279 llvm_unreachable("Unexpected opcode");
9280 case LoongArch::PseudoCTPOP_B:
9281 BroadcastOp = LoongArch::VREPLGR2VR_B;
9282 CTOp = LoongArch::VPCNT_B;
9283 PickOp = LoongArch::VPICKVE2GR_B;
9284 break;
9285 case LoongArch::PseudoCTPOP_H:
9286 case LoongArch::PseudoCTPOP_H_LA32:
9287 BroadcastOp = LoongArch::VREPLGR2VR_H;
9288 CTOp = LoongArch::VPCNT_H;
9289 PickOp = LoongArch::VPICKVE2GR_H;
9290 break;
9291 case LoongArch::PseudoCTPOP_W:
9292 case LoongArch::PseudoCTPOP_W_LA32:
9293 BroadcastOp = LoongArch::VREPLGR2VR_W;
9294 CTOp = LoongArch::VPCNT_W;
9295 PickOp = LoongArch::VPICKVE2GR_W;
9296 break;
9297 case LoongArch::PseudoCTPOP_D:
9298 BroadcastOp = LoongArch::VREPLGR2VR_D;
9299 CTOp = LoongArch::VPCNT_D;
9300 PickOp = LoongArch::VPICKVE2GR_D;
9301 break;
9302 }
9303
9304 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9305 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9306 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9307 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9308 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9309
9310 MI.eraseFromParent();
9311 return BB;
9312}
9313
9314static MachineBasicBlock *
9316 const LoongArchSubtarget &Subtarget) {
9317 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9318 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9319 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9321 Register Dst = MI.getOperand(0).getReg();
9322 Register Src = MI.getOperand(1).getReg();
9323 DebugLoc DL = MI.getDebugLoc();
9324 unsigned EleBits = 8;
9325 unsigned NotOpc = 0;
9326 unsigned MskOpc;
9327
9328 switch (MI.getOpcode()) {
9329 default:
9330 llvm_unreachable("Unexpected opcode");
9331 case LoongArch::PseudoVMSKLTZ_B:
9332 MskOpc = LoongArch::VMSKLTZ_B;
9333 break;
9334 case LoongArch::PseudoVMSKLTZ_H:
9335 MskOpc = LoongArch::VMSKLTZ_H;
9336 EleBits = 16;
9337 break;
9338 case LoongArch::PseudoVMSKLTZ_W:
9339 MskOpc = LoongArch::VMSKLTZ_W;
9340 EleBits = 32;
9341 break;
9342 case LoongArch::PseudoVMSKLTZ_D:
9343 MskOpc = LoongArch::VMSKLTZ_D;
9344 EleBits = 64;
9345 break;
9346 case LoongArch::PseudoVMSKGEZ_B:
9347 MskOpc = LoongArch::VMSKGEZ_B;
9348 break;
9349 case LoongArch::PseudoVMSKEQZ_B:
9350 MskOpc = LoongArch::VMSKNZ_B;
9351 NotOpc = LoongArch::VNOR_V;
9352 break;
9353 case LoongArch::PseudoVMSKNEZ_B:
9354 MskOpc = LoongArch::VMSKNZ_B;
9355 break;
9356 case LoongArch::PseudoXVMSKLTZ_B:
9357 MskOpc = LoongArch::XVMSKLTZ_B;
9358 RC = &LoongArch::LASX256RegClass;
9359 break;
9360 case LoongArch::PseudoXVMSKLTZ_H:
9361 MskOpc = LoongArch::XVMSKLTZ_H;
9362 RC = &LoongArch::LASX256RegClass;
9363 EleBits = 16;
9364 break;
9365 case LoongArch::PseudoXVMSKLTZ_W:
9366 MskOpc = LoongArch::XVMSKLTZ_W;
9367 RC = &LoongArch::LASX256RegClass;
9368 EleBits = 32;
9369 break;
9370 case LoongArch::PseudoXVMSKLTZ_D:
9371 MskOpc = LoongArch::XVMSKLTZ_D;
9372 RC = &LoongArch::LASX256RegClass;
9373 EleBits = 64;
9374 break;
9375 case LoongArch::PseudoXVMSKGEZ_B:
9376 MskOpc = LoongArch::XVMSKGEZ_B;
9377 RC = &LoongArch::LASX256RegClass;
9378 break;
9379 case LoongArch::PseudoXVMSKEQZ_B:
9380 MskOpc = LoongArch::XVMSKNZ_B;
9381 NotOpc = LoongArch::XVNOR_V;
9382 RC = &LoongArch::LASX256RegClass;
9383 break;
9384 case LoongArch::PseudoXVMSKNEZ_B:
9385 MskOpc = LoongArch::XVMSKNZ_B;
9386 RC = &LoongArch::LASX256RegClass;
9387 break;
9388 }
9389
9390 Register Msk = MRI.createVirtualRegister(RC);
9391 if (NotOpc) {
9392 Register Tmp = MRI.createVirtualRegister(RC);
9393 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9394 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk)
9395 .addReg(Tmp)
9396 .addReg(Tmp);
9397 } else {
9398 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9399 }
9400
9401 if (TRI->getRegSizeInBits(*RC) > 128) {
9402 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9403 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9404 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9405 .addReg(Msk)
9406 .addImm(0);
9407 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9408 .addReg(Msk)
9409 .addImm(4);
9410 BuildMI(*BB, MI, DL,
9411 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9412 : LoongArch::BSTRINS_W),
9413 Dst)
9414 .addReg(Lo)
9415 .addReg(Hi)
9416 .addImm(256 / EleBits - 1)
9417 .addImm(128 / EleBits);
9418 } else {
9419 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9420 .addReg(Msk)
9421 .addImm(0);
9422 }
9423
9424 MI.eraseFromParent();
9425 return BB;
9426}
9427
9428static MachineBasicBlock *
9430 const LoongArchSubtarget &Subtarget) {
9431 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9432 "Unexpected instruction");
9433
9434 MachineFunction &MF = *BB->getParent();
9435 DebugLoc DL = MI.getDebugLoc();
9437 Register LoReg = MI.getOperand(0).getReg();
9438 Register HiReg = MI.getOperand(1).getReg();
9439 Register SrcReg = MI.getOperand(2).getReg();
9440
9441 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9442 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9443 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9444 MI.eraseFromParent(); // The pseudo instruction is gone now.
9445 return BB;
9446}
9447
9448static MachineBasicBlock *
9450 const LoongArchSubtarget &Subtarget) {
9451 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9452 "Unexpected instruction");
9453
9454 MachineFunction &MF = *BB->getParent();
9455 DebugLoc DL = MI.getDebugLoc();
9458 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9459 Register DstReg = MI.getOperand(0).getReg();
9460 Register LoReg = MI.getOperand(1).getReg();
9461 Register HiReg = MI.getOperand(2).getReg();
9462
9463 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
9464 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
9465 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
9466 .addReg(TmpReg)
9467 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
9468 MI.eraseFromParent(); // The pseudo instruction is gone now.
9469 return BB;
9470}
9471
9473 switch (MI.getOpcode()) {
9474 default:
9475 return false;
9476 case LoongArch::Select_GPR_Using_CC_GPR:
9477 return true;
9478 }
9479}
9480
9481static MachineBasicBlock *
9483 const LoongArchSubtarget &Subtarget) {
9484 // To "insert" Select_* instructions, we actually have to insert the triangle
9485 // control-flow pattern. The incoming instructions know the destination vreg
9486 // to set, the condition code register to branch on, the true/false values to
9487 // select between, and the condcode to use to select the appropriate branch.
9488 //
9489 // We produce the following control flow:
9490 // HeadMBB
9491 // | \
9492 // | IfFalseMBB
9493 // | /
9494 // TailMBB
9495 //
9496 // When we find a sequence of selects we attempt to optimize their emission
9497 // by sharing the control flow. Currently we only handle cases where we have
9498 // multiple selects with the exact same condition (same LHS, RHS and CC).
9499 // The selects may be interleaved with other instructions if the other
9500 // instructions meet some requirements we deem safe:
9501 // - They are not pseudo instructions.
9502 // - They are debug instructions. Otherwise,
9503 // - They do not have side-effects, do not access memory and their inputs do
9504 // not depend on the results of the select pseudo-instructions.
9505 // The TrueV/FalseV operands of the selects cannot depend on the result of
9506 // previous selects in the sequence.
9507 // These conditions could be further relaxed. See the X86 target for a
9508 // related approach and more information.
9509
9510 Register LHS = MI.getOperand(1).getReg();
9511 Register RHS;
9512 if (MI.getOperand(2).isReg())
9513 RHS = MI.getOperand(2).getReg();
9514 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
9515
9516 SmallVector<MachineInstr *, 4> SelectDebugValues;
9517 SmallSet<Register, 4> SelectDests;
9518 SelectDests.insert(MI.getOperand(0).getReg());
9519
9520 MachineInstr *LastSelectPseudo = &MI;
9521 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
9522 SequenceMBBI != E; ++SequenceMBBI) {
9523 if (SequenceMBBI->isDebugInstr())
9524 continue;
9525 if (isSelectPseudo(*SequenceMBBI)) {
9526 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
9527 !SequenceMBBI->getOperand(2).isReg() ||
9528 SequenceMBBI->getOperand(2).getReg() != RHS ||
9529 SequenceMBBI->getOperand(3).getImm() != CC ||
9530 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
9531 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
9532 break;
9533 LastSelectPseudo = &*SequenceMBBI;
9534 SequenceMBBI->collectDebugValues(SelectDebugValues);
9535 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
9536 continue;
9537 }
9538 if (SequenceMBBI->hasUnmodeledSideEffects() ||
9539 SequenceMBBI->mayLoadOrStore() ||
9540 SequenceMBBI->usesCustomInsertionHook())
9541 break;
9542 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
9543 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
9544 }))
9545 break;
9546 }
9547
9548 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
9549 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9550 DebugLoc DL = MI.getDebugLoc();
9552
9553 MachineBasicBlock *HeadMBB = BB;
9554 MachineFunction *F = BB->getParent();
9555 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
9556 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
9557
9558 F->insert(I, IfFalseMBB);
9559 F->insert(I, TailMBB);
9560
9561 // Set the call frame size on entry to the new basic blocks.
9562 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
9563 IfFalseMBB->setCallFrameSize(CallFrameSize);
9564 TailMBB->setCallFrameSize(CallFrameSize);
9565
9566 // Transfer debug instructions associated with the selects to TailMBB.
9567 for (MachineInstr *DebugInstr : SelectDebugValues) {
9568 TailMBB->push_back(DebugInstr->removeFromParent());
9569 }
9570
9571 // Move all instructions after the sequence to TailMBB.
9572 TailMBB->splice(TailMBB->end(), HeadMBB,
9573 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
9574 // Update machine-CFG edges by transferring all successors of the current
9575 // block to the new block which will contain the Phi nodes for the selects.
9576 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
9577 // Set the successors for HeadMBB.
9578 HeadMBB->addSuccessor(IfFalseMBB);
9579 HeadMBB->addSuccessor(TailMBB);
9580
9581 // Insert appropriate branch.
9582 if (MI.getOperand(2).isImm())
9583 BuildMI(HeadMBB, DL, TII.get(CC))
9584 .addReg(LHS)
9585 .addImm(MI.getOperand(2).getImm())
9586 .addMBB(TailMBB);
9587 else
9588 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
9589
9590 // IfFalseMBB just falls through to TailMBB.
9591 IfFalseMBB->addSuccessor(TailMBB);
9592
9593 // Create PHIs for all of the select pseudo-instructions.
9594 auto SelectMBBI = MI.getIterator();
9595 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
9596 auto InsertionPoint = TailMBB->begin();
9597 while (SelectMBBI != SelectEnd) {
9598 auto Next = std::next(SelectMBBI);
9599 if (isSelectPseudo(*SelectMBBI)) {
9600 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
9601 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
9602 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
9603 .addReg(SelectMBBI->getOperand(4).getReg())
9604 .addMBB(HeadMBB)
9605 .addReg(SelectMBBI->getOperand(5).getReg())
9606 .addMBB(IfFalseMBB);
9607 SelectMBBI->eraseFromParent();
9608 }
9609 SelectMBBI = Next;
9610 }
9611
9612 F->getProperties().resetNoPHIs();
9613 return TailMBB;
9614}
9615
9616MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
9617 MachineInstr &MI, MachineBasicBlock *BB) const {
9618 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9619 DebugLoc DL = MI.getDebugLoc();
9620
9621 switch (MI.getOpcode()) {
9622 default:
9623 llvm_unreachable("Unexpected instr type to insert");
9624 case LoongArch::DIV_W:
9625 case LoongArch::DIV_WU:
9626 case LoongArch::MOD_W:
9627 case LoongArch::MOD_WU:
9628 case LoongArch::DIV_D:
9629 case LoongArch::DIV_DU:
9630 case LoongArch::MOD_D:
9631 case LoongArch::MOD_DU:
9632 return insertDivByZeroTrap(MI, BB);
9633 break;
9634 case LoongArch::WRFCSR: {
9635 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
9636 LoongArch::FCSR0 + MI.getOperand(0).getImm())
9637 .addReg(MI.getOperand(1).getReg());
9638 MI.eraseFromParent();
9639 return BB;
9640 }
9641 case LoongArch::RDFCSR: {
9642 MachineInstr *ReadFCSR =
9643 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
9644 MI.getOperand(0).getReg())
9645 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
9646 ReadFCSR->getOperand(1).setIsUndef();
9647 MI.eraseFromParent();
9648 return BB;
9649 }
9650 case LoongArch::Select_GPR_Using_CC_GPR:
9651 return emitSelectPseudo(MI, BB, Subtarget);
9652 case LoongArch::BuildPairF64Pseudo:
9653 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
9654 case LoongArch::SplitPairF64Pseudo:
9655 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
9656 case LoongArch::PseudoVBZ:
9657 case LoongArch::PseudoVBZ_B:
9658 case LoongArch::PseudoVBZ_H:
9659 case LoongArch::PseudoVBZ_W:
9660 case LoongArch::PseudoVBZ_D:
9661 case LoongArch::PseudoVBNZ:
9662 case LoongArch::PseudoVBNZ_B:
9663 case LoongArch::PseudoVBNZ_H:
9664 case LoongArch::PseudoVBNZ_W:
9665 case LoongArch::PseudoVBNZ_D:
9666 case LoongArch::PseudoXVBZ:
9667 case LoongArch::PseudoXVBZ_B:
9668 case LoongArch::PseudoXVBZ_H:
9669 case LoongArch::PseudoXVBZ_W:
9670 case LoongArch::PseudoXVBZ_D:
9671 case LoongArch::PseudoXVBNZ:
9672 case LoongArch::PseudoXVBNZ_B:
9673 case LoongArch::PseudoXVBNZ_H:
9674 case LoongArch::PseudoXVBNZ_W:
9675 case LoongArch::PseudoXVBNZ_D:
9676 return emitVecCondBranchPseudo(MI, BB, Subtarget);
9677 case LoongArch::PseudoXVINSGR2VR_B:
9678 case LoongArch::PseudoXVINSGR2VR_H:
9679 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
9680 case LoongArch::PseudoCTPOP_B:
9681 case LoongArch::PseudoCTPOP_H:
9682 case LoongArch::PseudoCTPOP_W:
9683 case LoongArch::PseudoCTPOP_D:
9684 case LoongArch::PseudoCTPOP_H_LA32:
9685 case LoongArch::PseudoCTPOP_W_LA32:
9686 return emitPseudoCTPOP(MI, BB, Subtarget);
9687 case LoongArch::PseudoVMSKLTZ_B:
9688 case LoongArch::PseudoVMSKLTZ_H:
9689 case LoongArch::PseudoVMSKLTZ_W:
9690 case LoongArch::PseudoVMSKLTZ_D:
9691 case LoongArch::PseudoVMSKGEZ_B:
9692 case LoongArch::PseudoVMSKEQZ_B:
9693 case LoongArch::PseudoVMSKNEZ_B:
9694 case LoongArch::PseudoXVMSKLTZ_B:
9695 case LoongArch::PseudoXVMSKLTZ_H:
9696 case LoongArch::PseudoXVMSKLTZ_W:
9697 case LoongArch::PseudoXVMSKLTZ_D:
9698 case LoongArch::PseudoXVMSKGEZ_B:
9699 case LoongArch::PseudoXVMSKEQZ_B:
9700 case LoongArch::PseudoXVMSKNEZ_B:
9701 return emitPseudoVMSKCOND(MI, BB, Subtarget);
9702 case TargetOpcode::STATEPOINT:
9703 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
9704 // while bl call instruction (where statepoint will be lowered at the
9705 // end) has implicit def. This def is early-clobber as it will be set at
9706 // the moment of the call and earlier than any use is read.
9707 // Add this implicit dead def here as a workaround.
9708 MI.addOperand(*MI.getMF(),
9710 LoongArch::R1, /*isDef*/ true,
9711 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
9712 /*isUndef*/ false, /*isEarlyClobber*/ true));
9713 if (!Subtarget.is64Bit())
9714 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
9715 return emitPatchPoint(MI, BB);
9716 case LoongArch::PROBED_STACKALLOC_DYN:
9717 return emitDynamicProbedAlloc(MI, BB);
9718 }
9719}
9720
9722 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
9723 unsigned *Fast) const {
9724 if (!Subtarget.hasUAL())
9725 return false;
9726
9727 // TODO: set reasonable speed number.
9728 if (Fast)
9729 *Fast = 1;
9730 return true;
9731}
9732
9733//===----------------------------------------------------------------------===//
9734// Calling Convention Implementation
9735//===----------------------------------------------------------------------===//
9736
9737// Eight general-purpose registers a0-a7 used for passing integer arguments,
9738// with a0-a1 reused to return values. Generally, the GPRs are used to pass
9739// fixed-point arguments, and floating-point arguments when no FPR is available
9740// or with soft float ABI.
9741const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
9742 LoongArch::R7, LoongArch::R8, LoongArch::R9,
9743 LoongArch::R10, LoongArch::R11};
9744
9745// PreserveNone calling convention:
9746// Arguments may be passed in any general-purpose registers except:
9747// - R1 : return address register
9748// - R22 : frame pointer
9749// - R31 : base pointer
9750//
9751// All general-purpose registers are treated as caller-saved,
9752// except R1 (RA) and R22 (FP).
9753//
9754// Non-volatile registers are allocated first so that a function
9755// can call normal functions without having to spill and reload
9756// argument registers.
9758 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
9759 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
9760 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
9761 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
9762 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
9763 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
9764 LoongArch::R20};
9765
9766// Eight floating-point registers fa0-fa7 used for passing floating-point
9767// arguments, and fa0-fa1 are also used to return values.
9768const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
9769 LoongArch::F3, LoongArch::F4, LoongArch::F5,
9770 LoongArch::F6, LoongArch::F7};
9771// FPR32 and FPR64 alias each other.
9773 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
9774 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
9775
9776const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
9777 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
9778 LoongArch::VR6, LoongArch::VR7};
9779
9780const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
9781 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
9782 LoongArch::XR6, LoongArch::XR7};
9783
9785 switch (State.getCallingConv()) {
9787 if (!State.isVarArg())
9788 return State.AllocateReg(PreserveNoneArgGPRs);
9789 [[fallthrough]];
9790 default:
9791 return State.AllocateReg(ArgGPRs);
9792 }
9793}
9794
9795// Pass a 2*GRLen argument that has been split into two GRLen values through
9796// registers or the stack as necessary.
9797static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
9798 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
9799 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
9800 ISD::ArgFlagsTy ArgFlags2) {
9801 unsigned GRLenInBytes = GRLen / 8;
9802 if (Register Reg = allocateArgGPR(State)) {
9803 // At least one half can be passed via register.
9804 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
9805 VA1.getLocVT(), CCValAssign::Full));
9806 } else {
9807 // Both halves must be passed on the stack, with proper alignment.
9808 Align StackAlign =
9809 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
9810 State.addLoc(
9812 State.AllocateStack(GRLenInBytes, StackAlign),
9813 VA1.getLocVT(), CCValAssign::Full));
9814 State.addLoc(CCValAssign::getMem(
9815 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9816 LocVT2, CCValAssign::Full));
9817 return false;
9818 }
9819 if (Register Reg = allocateArgGPR(State)) {
9820 // The second half can also be passed via register.
9821 State.addLoc(
9822 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
9823 } else {
9824 // The second half is passed via the stack, without additional alignment.
9825 State.addLoc(CCValAssign::getMem(
9826 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9827 LocVT2, CCValAssign::Full));
9828 }
9829 return false;
9830}
9831
9832// Implements the LoongArch calling convention. Returns true upon failure.
9834 unsigned ValNo, MVT ValVT,
9835 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
9836 CCState &State, bool IsRet, Type *OrigTy) {
9837 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
9838 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
9839 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
9840 MVT LocVT = ValVT;
9841
9842 // Any return value split into more than two values can't be returned
9843 // directly.
9844 if (IsRet && ValNo > 1)
9845 return true;
9846
9847 // If passing a variadic argument, or if no FPR is available.
9848 bool UseGPRForFloat = true;
9849
9850 switch (ABI) {
9851 default:
9852 llvm_unreachable("Unexpected ABI");
9853 break;
9858 UseGPRForFloat = ArgFlags.isVarArg();
9859 break;
9862 break;
9863 }
9864
9865 // If this is a variadic argument, the LoongArch calling convention requires
9866 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
9867 // byte alignment. An aligned register should be used regardless of whether
9868 // the original argument was split during legalisation or not. The argument
9869 // will not be passed by registers if the original type is larger than
9870 // 2*GRLen, so the register alignment rule does not apply.
9871 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
9872 if (ArgFlags.isVarArg() &&
9873 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
9874 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
9875 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
9876 // Skip 'odd' register if necessary.
9877 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
9878 State.AllocateReg(ArgGPRs);
9879 }
9880
9881 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
9882 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
9883 State.getPendingArgFlags();
9884
9885 assert(PendingLocs.size() == PendingArgFlags.size() &&
9886 "PendingLocs and PendingArgFlags out of sync");
9887
9888 // FPR32 and FPR64 alias each other.
9889 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
9890 UseGPRForFloat = true;
9891
9892 if (UseGPRForFloat && ValVT == MVT::f32) {
9893 LocVT = GRLenVT;
9894 LocInfo = CCValAssign::BCvt;
9895 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
9896 LocVT = MVT::i64;
9897 LocInfo = CCValAssign::BCvt;
9898 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
9899 // Handle passing f64 on LA32D with a soft float ABI or when floating point
9900 // registers are exhausted.
9901 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
9902 // Depending on available argument GPRS, f64 may be passed in a pair of
9903 // GPRs, split between a GPR and the stack, or passed completely on the
9904 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
9905 // cases.
9906 MCRegister Reg = allocateArgGPR(State);
9907 if (!Reg) {
9908 int64_t StackOffset = State.AllocateStack(8, Align(8));
9909 State.addLoc(
9910 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9911 return false;
9912 }
9913 LocVT = MVT::i32;
9914 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9915 MCRegister HiReg = allocateArgGPR(State);
9916 if (HiReg) {
9917 State.addLoc(
9918 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
9919 } else {
9920 int64_t StackOffset = State.AllocateStack(4, Align(4));
9921 State.addLoc(
9922 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9923 }
9924 return false;
9925 }
9926
9927 // Split arguments might be passed indirectly, so keep track of the pending
9928 // values.
9929 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
9930 LocVT = GRLenVT;
9931 LocInfo = CCValAssign::Indirect;
9932 PendingLocs.push_back(
9933 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
9934 PendingArgFlags.push_back(ArgFlags);
9935 if (!ArgFlags.isSplitEnd()) {
9936 return false;
9937 }
9938 }
9939
9940 // If the split argument only had two elements, it should be passed directly
9941 // in registers or on the stack.
9942 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
9943 PendingLocs.size() <= 2) {
9944 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
9945 // Apply the normal calling convention rules to the first half of the
9946 // split argument.
9947 CCValAssign VA = PendingLocs[0];
9948 ISD::ArgFlagsTy AF = PendingArgFlags[0];
9949 PendingLocs.clear();
9950 PendingArgFlags.clear();
9951 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
9952 ArgFlags);
9953 }
9954
9955 // Allocate to a register if possible, or else a stack slot.
9956 Register Reg;
9957 unsigned StoreSizeBytes = GRLen / 8;
9958 Align StackAlign = Align(GRLen / 8);
9959
9960 if (ValVT == MVT::f32 && !UseGPRForFloat) {
9961 Reg = State.AllocateReg(ArgFPR32s);
9962 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
9963 Reg = State.AllocateReg(ArgFPR64s);
9964 } else if (ValVT.is128BitVector()) {
9965 Reg = State.AllocateReg(ArgVRs);
9966 UseGPRForFloat = false;
9967 StoreSizeBytes = 16;
9968 StackAlign = Align(16);
9969 } else if (ValVT.is256BitVector()) {
9970 Reg = State.AllocateReg(ArgXRs);
9971 UseGPRForFloat = false;
9972 StoreSizeBytes = 32;
9973 StackAlign = Align(32);
9974 } else {
9975 Reg = allocateArgGPR(State);
9976 }
9977
9978 unsigned StackOffset =
9979 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
9980
9981 // If we reach this point and PendingLocs is non-empty, we must be at the
9982 // end of a split argument that must be passed indirectly.
9983 if (!PendingLocs.empty()) {
9984 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
9985 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
9986 for (auto &It : PendingLocs) {
9987 if (Reg)
9988 It.convertToReg(Reg);
9989 else
9990 It.convertToMem(StackOffset);
9991 State.addLoc(It);
9992 }
9993 PendingLocs.clear();
9994 PendingArgFlags.clear();
9995 return false;
9996 }
9997 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
9998 "Expected an GRLenVT at this stage");
9999
10000 if (Reg) {
10001 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10002 return false;
10003 }
10004
10005 // When a floating-point value is passed on the stack, no bit-cast is needed.
10006 if (ValVT.isFloatingPoint()) {
10007 LocVT = ValVT;
10008 LocInfo = CCValAssign::Full;
10009 }
10010
10011 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10012 return false;
10013}
10014
10015void LoongArchTargetLowering::analyzeInputArgs(
10016 MachineFunction &MF, CCState &CCInfo,
10017 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
10018 LoongArchCCAssignFn Fn) const {
10019 FunctionType *FType = MF.getFunction().getFunctionType();
10020 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
10021 MVT ArgVT = Ins[i].VT;
10022 Type *ArgTy = nullptr;
10023 if (IsRet)
10024 ArgTy = FType->getReturnType();
10025 else if (Ins[i].isOrigArg())
10026 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
10028 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10029 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
10030 CCInfo, IsRet, ArgTy)) {
10031 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
10032 << '\n');
10033 llvm_unreachable("");
10034 }
10035 }
10036}
10037
10038void LoongArchTargetLowering::analyzeOutputArgs(
10039 MachineFunction &MF, CCState &CCInfo,
10040 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
10041 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
10042 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10043 MVT ArgVT = Outs[i].VT;
10044 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
10046 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10047 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
10048 CCInfo, IsRet, OrigTy)) {
10049 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
10050 << "\n");
10051 llvm_unreachable("");
10052 }
10053 }
10054}
10055
10056// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
10057// values.
10059 const CCValAssign &VA, const SDLoc &DL) {
10060 switch (VA.getLocInfo()) {
10061 default:
10062 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10063 case CCValAssign::Full:
10065 break;
10066 case CCValAssign::BCvt:
10067 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10068 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
10069 else
10070 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10071 break;
10072 }
10073 return Val;
10074}
10075
10077 const CCValAssign &VA, const SDLoc &DL,
10078 const ISD::InputArg &In,
10079 const LoongArchTargetLowering &TLI) {
10082 EVT LocVT = VA.getLocVT();
10083 SDValue Val;
10084 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
10085 Register VReg = RegInfo.createVirtualRegister(RC);
10086 RegInfo.addLiveIn(VA.getLocReg(), VReg);
10087 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
10088
10089 // If input is sign extended from 32 bits, note it for the OptW pass.
10090 if (In.isOrigArg()) {
10091 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
10092 if (OrigArg->getType()->isIntegerTy()) {
10093 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
10094 // An input zero extended from i31 can also be considered sign extended.
10095 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
10096 (BitWidth < 32 && In.Flags.isZExt())) {
10099 LAFI->addSExt32Register(VReg);
10100 }
10101 }
10102 }
10103
10104 return convertLocVTToValVT(DAG, Val, VA, DL);
10105}
10106
10107// The caller is responsible for loading the full value if the argument is
10108// passed with CCValAssign::Indirect.
10110 const CCValAssign &VA, const SDLoc &DL) {
10112 MachineFrameInfo &MFI = MF.getFrameInfo();
10113 EVT ValVT = VA.getValVT();
10114 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
10115 /*IsImmutable=*/true);
10116 SDValue FIN = DAG.getFrameIndex(
10118
10119 ISD::LoadExtType ExtType;
10120 switch (VA.getLocInfo()) {
10121 default:
10122 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10123 case CCValAssign::Full:
10125 case CCValAssign::BCvt:
10126 ExtType = ISD::NON_EXTLOAD;
10127 break;
10128 }
10129 return DAG.getExtLoad(
10130 ExtType, DL, VA.getLocVT(), Chain, FIN,
10132}
10133
10135 const CCValAssign &VA,
10136 const CCValAssign &HiVA,
10137 const SDLoc &DL) {
10138 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
10139 "Unexpected VA");
10141 MachineFrameInfo &MFI = MF.getFrameInfo();
10143
10144 assert(VA.isRegLoc() && "Expected register VA assignment");
10145
10146 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10147 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
10148 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
10149 SDValue Hi;
10150 if (HiVA.isMemLoc()) {
10151 // Second half of f64 is passed on the stack.
10152 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
10153 /*IsImmutable=*/true);
10154 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
10155 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
10157 } else {
10158 // Second half of f64 is passed in another GPR.
10159 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10160 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
10161 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
10162 }
10163 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
10164}
10165
10167 const CCValAssign &VA, const SDLoc &DL) {
10168 EVT LocVT = VA.getLocVT();
10169
10170 switch (VA.getLocInfo()) {
10171 default:
10172 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10173 case CCValAssign::Full:
10174 break;
10175 case CCValAssign::BCvt:
10176 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10177 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
10178 else
10179 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10180 break;
10181 }
10182 return Val;
10183}
10184
10185static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
10186 CCValAssign::LocInfo LocInfo,
10187 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
10188 CCState &State) {
10189 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
10190 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
10191 // s0 s1 s2 s3 s4 s5 s6 s7 s8
10192 static const MCPhysReg GPRList[] = {
10193 LoongArch::R23, LoongArch::R24, LoongArch::R25,
10194 LoongArch::R26, LoongArch::R27, LoongArch::R28,
10195 LoongArch::R29, LoongArch::R30, LoongArch::R31};
10196 if (MCRegister Reg = State.AllocateReg(GPRList)) {
10197 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10198 return false;
10199 }
10200 }
10201
10202 if (LocVT == MVT::f32) {
10203 // Pass in STG registers: F1, F2, F3, F4
10204 // fs0,fs1,fs2,fs3
10205 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
10206 LoongArch::F26, LoongArch::F27};
10207 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
10208 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10209 return false;
10210 }
10211 }
10212
10213 if (LocVT == MVT::f64) {
10214 // Pass in STG registers: D1, D2, D3, D4
10215 // fs4,fs5,fs6,fs7
10216 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
10217 LoongArch::F30_64, LoongArch::F31_64};
10218 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
10219 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10220 return false;
10221 }
10222 }
10223
10224 report_fatal_error("No registers left in GHC calling convention");
10225 return true;
10226}
10227
10228// Transform physical registers into virtual registers.
10230 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10231 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
10232 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
10233
10235
10236 switch (CallConv) {
10237 default:
10238 llvm_unreachable("Unsupported calling convention");
10239 case CallingConv::C:
10240 case CallingConv::Fast:
10243 break;
10244 case CallingConv::GHC:
10245 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
10246 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
10248 "GHC calling convention requires the F and D extensions");
10249 }
10250
10251 const Function &Func = MF.getFunction();
10252 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10253 MVT GRLenVT = Subtarget.getGRLenVT();
10254 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
10255
10256 // Check if this function has any musttail calls. If so, incoming indirect
10257 // arg pointers must be saved in virtual registers so they survive across
10258 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
10259 // when needed to avoid adding register pressure to non-musttail functions.
10260 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
10261 return llvm::any_of(BB, [](const Instruction &I) {
10262 if (const auto *CI = dyn_cast<CallInst>(&I))
10263 return CI->isMustTailCall();
10264 return false;
10265 });
10266 });
10267 // Used with varargs to acumulate store chains.
10268 std::vector<SDValue> OutChains;
10269
10270 // Assign locations to all of the incoming arguments.
10272 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10273
10274 if (CallConv == CallingConv::GHC)
10276 else
10277 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
10278
10279 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10280 CCValAssign &VA = ArgLocs[i];
10281 SDValue ArgValue;
10282 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10283 // case.
10284 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10285 assert(VA.needsCustom());
10286 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10287 } else if (VA.isRegLoc())
10288 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10289 else
10290 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10291 if (VA.getLocInfo() == CCValAssign::Indirect) {
10292 // If the original argument was split and passed by reference, we need to
10293 // load all parts of it here (using the same address).
10294 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10296 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10297 if (HasMusttail) {
10300 Register VReg =
10301 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10302 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10303 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10304 }
10305 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10306 assert(ArgPartOffset == 0);
10307 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10308 CCValAssign &PartVA = ArgLocs[i + 1];
10309 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10310 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10311 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10312 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10314 ++i;
10315 ++InsIdx;
10316 }
10317 continue;
10318 }
10319 InVals.push_back(ArgValue);
10320 }
10321
10322 if (IsVarArg) {
10324 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10325 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10326 MachineFrameInfo &MFI = MF.getFrameInfo();
10327 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10328 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10329
10330 // Offset of the first variable argument from stack pointer, and size of
10331 // the vararg save area. For now, the varargs save area is either zero or
10332 // large enough to hold a0-a7.
10333 int VaArgOffset, VarArgsSaveSize;
10334
10335 // If all registers are allocated, then all varargs must be passed on the
10336 // stack and we don't need to save any argregs.
10337 if (ArgRegs.size() == Idx) {
10338 VaArgOffset = CCInfo.getStackSize();
10339 VarArgsSaveSize = 0;
10340 } else {
10341 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10342 VaArgOffset = -VarArgsSaveSize;
10343 }
10344
10345 // Record the frame index of the first variable argument
10346 // which is a value necessary to VASTART.
10347 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10348 LoongArchFI->setVarArgsFrameIndex(FI);
10349
10350 // If saving an odd number of registers then create an extra stack slot to
10351 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10352 // offsets to even-numbered registered remain 2*GRLen-aligned.
10353 if (Idx % 2) {
10354 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10355 true);
10356 VarArgsSaveSize += GRLenInBytes;
10357 }
10358
10359 // Copy the integer registers that may have been used for passing varargs
10360 // to the vararg save area.
10361 for (unsigned I = Idx; I < ArgRegs.size();
10362 ++I, VaArgOffset += GRLenInBytes) {
10363 const Register Reg = RegInfo.createVirtualRegister(RC);
10364 RegInfo.addLiveIn(ArgRegs[I], Reg);
10365 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10366 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10367 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10368 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10370 cast<StoreSDNode>(Store.getNode())
10371 ->getMemOperand()
10372 ->setValue((Value *)nullptr);
10373 OutChains.push_back(Store);
10374 }
10375 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10376 }
10377
10378 // All stores are grouped in one node to allow the matching between
10379 // the size of Ins and InVals. This only happens for vararg functions.
10380 if (!OutChains.empty()) {
10381 OutChains.push_back(Chain);
10382 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10383 }
10384
10385 return Chain;
10386}
10387
10389 return CI->isTailCall();
10390}
10391
10392// Check if the return value is used as only a return value, as otherwise
10393// we can't perform a tail-call.
10395 SDValue &Chain) const {
10396 if (N->getNumValues() != 1)
10397 return false;
10398 if (!N->hasNUsesOfValue(1, 0))
10399 return false;
10400
10401 SDNode *Copy = *N->user_begin();
10402 if (Copy->getOpcode() != ISD::CopyToReg)
10403 return false;
10404
10405 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10406 // isn't safe to perform a tail call.
10407 if (Copy->getGluedNode())
10408 return false;
10409
10410 // The copy must be used by a LoongArchISD::RET, and nothing else.
10411 bool HasRet = false;
10412 for (SDNode *Node : Copy->users()) {
10413 if (Node->getOpcode() != LoongArchISD::RET)
10414 return false;
10415 HasRet = true;
10416 }
10417
10418 if (!HasRet)
10419 return false;
10420
10421 Chain = Copy->getOperand(0);
10422 return true;
10423}
10424
10425// Check whether the call is eligible for tail call optimization.
10426bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10427 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10428 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10429
10430 auto CalleeCC = CLI.CallConv;
10431 auto &Outs = CLI.Outs;
10432 auto &Caller = MF.getFunction();
10433 auto CallerCC = Caller.getCallingConv();
10434
10435 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10436
10437 // Byval parameters hand the function a pointer directly into the stack area
10438 // we want to reuse during a tail call. Working around this *is* possible
10439 // but less efficient and uglier in LowerCall. For musttail, there is no
10440 // workaround today: a byval arg requires a local copy that becomes invalid
10441 // after the tail call deallocates the caller's frame, so rejecting here
10442 // (and triggering reportFatalInternalError in LowerCall) is safer than
10443 // miscompiling.
10444 for (auto &Arg : Outs)
10445 if (Arg.Flags.isByVal())
10446 return false;
10447
10448 // musttail bypasses the remaining checks: the checks either reject cases
10449 // we handle specially (indirect args are forwarded via incoming pointers,
10450 // stack-passed args reuse the matching incoming layout, sret is forwarded
10451 // like any other pointer arg) or are optimizations not applicable to
10452 // mandatory tail calls.
10453 if (IsMustTail)
10454 return true;
10455
10456 // Do not tail call opt if the stack is used to pass parameters.
10457 if (CCInfo.getStackSize() != 0)
10458 return false;
10459
10460 // Do not tail call opt if any parameters need to be passed indirectly.
10461 for (auto &VA : ArgLocs)
10462 if (VA.getLocInfo() == CCValAssign::Indirect)
10463 return false;
10464
10465 // Do not tail call opt if either caller or callee uses struct return
10466 // semantics.
10467 auto IsCallerStructRet = Caller.hasStructRetAttr();
10468 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10469 if (IsCallerStructRet || IsCalleeStructRet)
10470 return false;
10471
10472 // The callee has to preserve all registers the caller needs to preserve.
10473 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10474 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10475 if (CalleeCC != CallerCC) {
10476 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10477 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10478 return false;
10479 }
10480 return true;
10481}
10482
10484 return DAG.getDataLayout().getPrefTypeAlign(
10485 VT.getTypeForEVT(*DAG.getContext()));
10486}
10487
10488// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
10489// and output parameter nodes.
10490SDValue
10492 SmallVectorImpl<SDValue> &InVals) const {
10493 SelectionDAG &DAG = CLI.DAG;
10494 SDLoc &DL = CLI.DL;
10496 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10498 SDValue Chain = CLI.Chain;
10499 SDValue Callee = CLI.Callee;
10500 CallingConv::ID CallConv = CLI.CallConv;
10501 bool IsVarArg = CLI.IsVarArg;
10502 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10503 MVT GRLenVT = Subtarget.getGRLenVT();
10504 bool &IsTailCall = CLI.IsTailCall;
10505
10507
10508 // Analyze the operands of the call, assigning locations to each operand.
10510 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10511
10512 if (CallConv == CallingConv::GHC)
10513 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
10514 else
10515 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
10516
10517 // Check if it's really possible to do a tail call.
10518 if (IsTailCall)
10519 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
10520
10521 if (IsTailCall)
10522 ++NumTailCalls;
10523 else if (CLI.CB && CLI.CB->isMustTailCall())
10524 report_fatal_error("failed to perform tail call elimination on a call "
10525 "site marked musttail");
10526
10527 // Get a count of how many bytes are to be pushed on the stack.
10528 unsigned NumBytes = ArgCCInfo.getStackSize();
10529
10530 // Create local copies for byval args.
10531 SmallVector<SDValue> ByValArgs;
10532 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10533 ISD::ArgFlagsTy Flags = Outs[i].Flags;
10534 if (!Flags.isByVal())
10535 continue;
10536
10537 SDValue Arg = OutVals[i];
10538 unsigned Size = Flags.getByValSize();
10539 Align Alignment = Flags.getNonZeroByValAlign();
10540
10541 int FI =
10542 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
10543 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10544 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
10545
10546 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
10547 /*IsVolatile=*/false,
10548 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
10550 ByValArgs.push_back(FIPtr);
10551 }
10552
10553 if (!IsTailCall)
10554 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
10555
10556 // Copy argument values to their designated locations.
10558 SmallVector<SDValue> MemOpChains;
10559 SDValue StackPtr;
10560 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
10561 ++i, ++OutIdx) {
10562 CCValAssign &VA = ArgLocs[i];
10563 SDValue ArgValue = OutVals[OutIdx];
10564 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
10565
10566 // Handle passing f64 on LA32D with a soft float ABI as a special case.
10567 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10568 assert(VA.isRegLoc() && "Expected register VA assignment");
10569 assert(VA.needsCustom());
10570 SDValue SplitF64 =
10571 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10572 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
10573 SDValue Lo = SplitF64.getValue(0);
10574 SDValue Hi = SplitF64.getValue(1);
10575
10576 Register RegLo = VA.getLocReg();
10577 RegsToPass.push_back(std::make_pair(RegLo, Lo));
10578
10579 // Get the CCValAssign for the Hi part.
10580 CCValAssign &HiVA = ArgLocs[++i];
10581
10582 if (HiVA.isMemLoc()) {
10583 // Second half of f64 is passed on the stack.
10584 if (!StackPtr.getNode())
10585 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10587 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10588 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
10589 // Emit the store.
10590 MemOpChains.push_back(DAG.getStore(
10591 Chain, DL, Hi, Address,
10593 } else {
10594 // Second half of f64 is passed in another GPR.
10595 Register RegHigh = HiVA.getLocReg();
10596 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
10597 }
10598 continue;
10599 }
10600
10601 // Promote the value if needed.
10602 // For now, only handle fully promoted and indirect arguments.
10603 if (VA.getLocInfo() == CCValAssign::Indirect) {
10604 // For musttail calls, reuse incoming indirect pointers instead of
10605 // creating new stack temporaries. The incoming pointers point to the
10606 // caller's caller's frame, which remains valid after a tail call.
10607 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
10610 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
10611
10612 // Resolve which formal parameter is being passed at this call
10613 // position.
10614 //
10615 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
10616 // but Outs[].OrigArgIndex is an index into a filtered arg list
10617 // (empty types removed, via CallLoweringInfo in the target-
10618 // independent layer). IncomingIndirectArgs is keyed by the
10619 // caller's unfiltered Argument::getArgNo(), so we have to walk
10620 // the caller's formals (same filter) to translate the index.
10621 // This target-independent asymmetry should be normalized so
10622 // backends do not need to re-derive the mapping.
10623 //
10624 // Steps:
10625 // 1. Find the call operand at filtered position CallArgIdx.
10626 // 2. If it is an Argument, use getArgNo() directly (same filter
10627 // for caller formals and call operands).
10628 // 3. Otherwise (computed value), walk the caller's formals and
10629 // skip empty types to map the filtered index to getArgNo().
10630 const Argument *FormalArg = nullptr;
10631 unsigned FilteredIdx = 0;
10632 for (const auto &CallArg : CLI.CB->args()) {
10633 if (CallArg->getType()->isEmptyTy())
10634 continue;
10635 if (FilteredIdx == CallArgIdx) {
10636 FormalArg = dyn_cast<Argument>(CallArg);
10637 break;
10638 }
10639 ++FilteredIdx;
10640 }
10641
10642 // For forwarded args, getArgNo() gives the unfiltered index directly.
10643 // For computed args, walk the caller's formals to resolve it.
10644 unsigned FormalArgIdx = CallArgIdx;
10645 if (FormalArg) {
10646 FormalArgIdx = FormalArg->getArgNo();
10647 } else {
10648 FilteredIdx = 0;
10649 for (const auto &Arg : MF.getFunction().args()) {
10650 if (Arg.getType()->isEmptyTy())
10651 continue;
10652 if (FilteredIdx == CallArgIdx) {
10653 FormalArgIdx = Arg.getArgNo();
10654 break;
10655 }
10656 ++FilteredIdx;
10657 }
10658 }
10659
10660 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
10661 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
10662 // Thread the CopyFromReg output chain through MemOpChains so the
10663 // TokenFactor below sequences the copy with any stores we emit
10664 // for this argument.
10665 MemOpChains.push_back(CopyOp.getValue(1));
10666 SDValue IncomingPtr = CopyOp;
10667
10668 if (!FormalArg) {
10669 // Computed value: store into the incoming indirect pointer for the
10670 // same-position formal parameter (musttail guarantees matching
10671 // prototypes, so types match). The pointer survives the tail call
10672 // since it points to the caller's caller's frame.
10673 //
10674 // The data-flow edge through IncomingPtr already prevents the
10675 // store from being scheduled before the CopyFromReg. Threading
10676 // CopyOp.getValue(1) (the copy's output chain) into the store
10677 // makes that ordering explicit on the chain edge as well, which
10678 // is the convention for memory ops chaining off their producers.
10679 MemOpChains.push_back(
10680 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
10682 // Store any split parts at their respective offsets.
10683 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10684 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10685 SDValue PartValue = OutVals[OutIdx + 1];
10686 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10687 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10688 SDValue Addr =
10689 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
10690 MemOpChains.push_back(
10691 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
10693 ++i;
10694 ++OutIdx;
10695 }
10696 }
10697 ArgValue = IncomingPtr;
10698
10699 // Skip any remaining split parts (for forwarded args, they are
10700 // covered by the forwarded pointer).
10701 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10702 ++i;
10703 ++OutIdx;
10704 }
10705 } else {
10706 // Store the argument in a stack slot and pass its address.
10707 Align StackAlign =
10708 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
10709 getPrefTypeAlign(ArgValue.getValueType(), DAG));
10710 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
10711 // If the original argument was split and passed by reference, we need
10712 // to store the required parts of it here (and pass just one address).
10713 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
10714 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10715 assert(ArgPartOffset == 0);
10716 // Calculate the total size to store. We don't have access to what we're
10717 // actually storing other than performing the loop and collecting the
10718 // info.
10720 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
10721 SDValue PartValue = OutVals[OutIdx + 1];
10722 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10723 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10724 EVT PartVT = PartValue.getValueType();
10725 StoredSize += PartVT.getStoreSize();
10726 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
10727 Parts.push_back(std::make_pair(PartValue, Offset));
10728 ++i;
10729 ++OutIdx;
10730 }
10731 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
10732 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
10733 MemOpChains.push_back(
10734 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
10736 for (const auto &Part : Parts) {
10737 SDValue PartValue = Part.first;
10738 SDValue PartOffset = Part.second;
10740 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
10741 MemOpChains.push_back(
10742 DAG.getStore(Chain, DL, PartValue, Address,
10744 }
10745 ArgValue = SpillSlot;
10746 }
10747 } else {
10748 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
10749 }
10750
10751 // Use local copy if it is a byval arg.
10752 if (Flags.isByVal())
10753 ArgValue = ByValArgs[j++];
10754
10755 if (VA.isRegLoc()) {
10756 // Queue up the argument copies and emit them at the end.
10757 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
10758 } else {
10759 assert(VA.isMemLoc() && "Argument not register or memory");
10760 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
10761 "Tail call not allowed if stack is used for passing parameters");
10762
10763 // Work out the address of the stack slot.
10764 if (!StackPtr.getNode())
10765 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10767 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10769
10770 // Emit the store.
10771 MemOpChains.push_back(
10772 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
10773 }
10774 }
10775
10776 // Join the stores, which are independent of one another.
10777 if (!MemOpChains.empty())
10778 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
10779
10780 SDValue Glue;
10781
10782 // Build a sequence of copy-to-reg nodes, chained and glued together.
10783 for (auto &Reg : RegsToPass) {
10784 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
10785 Glue = Chain.getValue(1);
10786 }
10787
10788 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
10789 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
10790 // split it and then direct call can be matched by PseudoCALL_SMALL.
10792 const GlobalValue *GV = S->getGlobal();
10793 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
10796 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
10797 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
10798 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
10801 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
10802 }
10803
10804 // The first call operand is the chain and the second is the target address.
10806 Ops.push_back(Chain);
10807 Ops.push_back(Callee);
10808
10809 // Add argument registers to the end of the list so that they are
10810 // known live into the call.
10811 for (auto &Reg : RegsToPass)
10812 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
10813
10814 if (!IsTailCall) {
10815 // Add a register mask operand representing the call-preserved registers.
10816 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
10817 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
10818 assert(Mask && "Missing call preserved mask for calling convention");
10819 Ops.push_back(DAG.getRegisterMask(Mask));
10820 }
10821
10822 // Glue the call to the argument copies, if any.
10823 if (Glue.getNode())
10824 Ops.push_back(Glue);
10825
10826 // Emit the call.
10827 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
10828 unsigned Op;
10829 switch (DAG.getTarget().getCodeModel()) {
10830 default:
10831 report_fatal_error("Unsupported code model");
10832 case CodeModel::Small:
10833 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
10834 break;
10835 case CodeModel::Medium:
10836 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
10837 break;
10838 case CodeModel::Large:
10839 assert(Subtarget.is64Bit() && "Large code model requires LA64");
10840 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
10841 break;
10842 }
10843
10844 if (IsTailCall) {
10846 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
10847 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
10848 return Ret;
10849 }
10850
10851 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
10852 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
10853 Glue = Chain.getValue(1);
10854
10855 // Mark the end of the call, which is glued to the call itself.
10856 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
10857 Glue = Chain.getValue(1);
10858
10859 // Assign locations to each value returned by this call.
10861 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
10862 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
10863
10864 // Copy all of the result registers out of their specified physreg.
10865 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
10866 auto &VA = RVLocs[i];
10867 // Copy the value out.
10868 SDValue RetValue =
10869 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
10870 // Glue the RetValue to the end of the call sequence.
10871 Chain = RetValue.getValue(1);
10872 Glue = RetValue.getValue(2);
10873
10874 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10875 assert(VA.needsCustom());
10876 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
10877 MVT::i32, Glue);
10878 Chain = RetValue2.getValue(1);
10879 Glue = RetValue2.getValue(2);
10880 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
10881 RetValue, RetValue2);
10882 } else
10883 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
10884
10885 InVals.push_back(RetValue);
10886 }
10887
10888 return Chain;
10889}
10890
10892 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
10893 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
10894 const Type *RetTy) const {
10896 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
10897
10898 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10899 LoongArchABI::ABI ABI =
10900 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10901 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
10902 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
10903 return false;
10904 }
10905 return true;
10906}
10907
10909 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10911 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
10912 SelectionDAG &DAG) const {
10913 // Stores the assignment of the return value to a location.
10915
10916 // Info about the registers and stack slot.
10917 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
10918 *DAG.getContext());
10919
10920 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
10921 nullptr, CC_LoongArch);
10922 if (CallConv == CallingConv::GHC && !RVLocs.empty())
10923 report_fatal_error("GHC functions return void only");
10924 SDValue Glue;
10925 SmallVector<SDValue, 4> RetOps(1, Chain);
10926
10927 // Copy the result values into the output registers.
10928 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
10929 SDValue Val = OutVals[OutIdx];
10930 CCValAssign &VA = RVLocs[i];
10931 assert(VA.isRegLoc() && "Can only return in registers!");
10932
10933 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10934 // Handle returning f64 on LA32D with a soft float ABI.
10935 assert(VA.isRegLoc() && "Expected return via registers");
10936 assert(VA.needsCustom());
10937 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10938 DAG.getVTList(MVT::i32, MVT::i32), Val);
10939 SDValue Lo = SplitF64.getValue(0);
10940 SDValue Hi = SplitF64.getValue(1);
10941 Register RegLo = VA.getLocReg();
10942 Register RegHi = RVLocs[++i].getLocReg();
10943
10944 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
10945 Glue = Chain.getValue(1);
10946 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
10947 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
10948 Glue = Chain.getValue(1);
10949 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
10950 } else {
10951 // Handle a 'normal' return.
10952 Val = convertValVTToLocVT(DAG, Val, VA, DL);
10953 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
10954
10955 // Guarantee that all emitted copies are stuck together.
10956 Glue = Chain.getValue(1);
10957 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
10958 }
10959 }
10960
10961 RetOps[0] = Chain; // Update chain.
10962
10963 // Add the glue node if we have it.
10964 if (Glue.getNode())
10965 RetOps.push_back(Glue);
10966
10967 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
10968}
10969
10970// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
10971// Note: The following prefixes are excluded:
10972// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
10973// as they can be represented using [x]vrepli.[whb]
10975 const APInt &SplatValue, const unsigned SplatBitSize) const {
10976 uint64_t RequiredImm = 0;
10977 uint64_t V = SplatValue.getZExtValue();
10978 if (SplatBitSize == 16 && !(V & 0x00FF)) {
10979 // 4'b0101
10980 RequiredImm = (0b10101 << 8) | (V >> 8);
10981 return {true, RequiredImm};
10982 } else if (SplatBitSize == 32) {
10983 // 4'b0001
10984 if (!(V & 0xFFFF00FF)) {
10985 RequiredImm = (0b10001 << 8) | (V >> 8);
10986 return {true, RequiredImm};
10987 }
10988 // 4'b0010
10989 if (!(V & 0xFF00FFFF)) {
10990 RequiredImm = (0b10010 << 8) | (V >> 16);
10991 return {true, RequiredImm};
10992 }
10993 // 4'b0011
10994 if (!(V & 0x00FFFFFF)) {
10995 RequiredImm = (0b10011 << 8) | (V >> 24);
10996 return {true, RequiredImm};
10997 }
10998 // 4'b0110
10999 if ((V & 0xFFFF00FF) == 0xFF) {
11000 RequiredImm = (0b10110 << 8) | (V >> 8);
11001 return {true, RequiredImm};
11002 }
11003 // 4'b0111
11004 if ((V & 0xFF00FFFF) == 0xFFFF) {
11005 RequiredImm = (0b10111 << 8) | (V >> 16);
11006 return {true, RequiredImm};
11007 }
11008 // 4'b1010
11009 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
11010 RequiredImm =
11011 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11012 return {true, RequiredImm};
11013 }
11014 } else if (SplatBitSize == 64) {
11015 // 4'b1011
11016 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
11017 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
11018 RequiredImm =
11019 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11020 return {true, RequiredImm};
11021 }
11022 // 4'b1100
11023 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
11024 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
11025 RequiredImm =
11026 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
11027 return {true, RequiredImm};
11028 }
11029 // 4'b1001
11030 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
11031 uint8_t res = 0;
11032 for (int i = 0; i < 8; ++i) {
11033 uint8_t byte = x & 0xFF;
11034 if (byte == 0 || byte == 0xFF)
11035 res |= ((byte & 1) << i);
11036 else
11037 return {false, 0};
11038 x >>= 8;
11039 }
11040 return {true, res};
11041 };
11042 auto [IsSame, Suffix] = sameBitsPreByte(V);
11043 if (IsSame) {
11044 RequiredImm = (0b11001 << 8) | Suffix;
11045 return {true, RequiredImm};
11046 }
11047 }
11048 return {false, RequiredImm};
11049}
11050
11052 EVT VT) const {
11053 if (!Subtarget.hasExtLSX())
11054 return false;
11055
11056 if (VT == MVT::f32) {
11057 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
11058 return (masked == 0x3e000000 || masked == 0x40000000);
11059 }
11060
11061 if (VT == MVT::f64) {
11062 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
11063 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
11064 }
11065
11066 return false;
11067}
11068
11069// Only form FP_TO_SINT_SAT from clamp/NaN-guard idioms when it will be lowered
11070// to a single [X]VFTINTRZ/FTINTRZ, otherwise the generic expansion is worse
11071// than the original sequence.
11072bool LoongArchTargetLowering::shouldConvertFpToSat(unsigned Op, EVT FPVT,
11073 EVT VT) const {
11074 if (!isOperationLegalOrCustom(Op, VT))
11075 return false;
11076 if (VT.isVector())
11077 return FPVT.getScalarSizeInBits() == VT.getScalarSizeInBits();
11078 if (FPVT == MVT::f32)
11079 return VT.getSizeInBits() == 32 || Subtarget.hasBasicD();
11080 return FPVT == MVT::f64 && Subtarget.hasBasicD();
11081}
11082
11084LoongArchTargetLowering::getFPImmAction(const APFloat &Imm, EVT VT,
11085 bool ForCodeSize) const {
11086 // TODO: Maybe need more checks here after vector extension is supported.
11087 if (VT == MVT::f32 && !Subtarget.hasBasicF())
11089 if (VT == MVT::f64 && !Subtarget.hasBasicD())
11091 return (Imm.isZero() || Imm.isOne() || isFPImmVLDILegal(Imm, VT))
11094}
11095
11097 return true;
11098}
11099
11101 return true;
11102}
11103
11104bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
11105 const Instruction *I) const {
11106 if (!Subtarget.is64Bit())
11107 return isa<LoadInst>(I) || isa<StoreInst>(I);
11108
11109 if (isa<LoadInst>(I))
11110 return true;
11111
11112 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
11113 // require fences beacuse we can use amswap_db.[w/d].
11114 Type *Ty = I->getOperand(0)->getType();
11115 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
11116 unsigned Size = Ty->getIntegerBitWidth();
11117 return (Size == 8 || Size == 16);
11118 }
11119
11120 return false;
11121}
11122
11124 LLVMContext &Context,
11125 EVT VT) const {
11126 if (!VT.isVector())
11127 return getPointerTy(DL);
11129}
11130
11132 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
11133 // Do not merge to float value size (128 or 256 bits) if no implicit
11134 // float attribute is set.
11135 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
11136 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
11137 if (NoFloat)
11138 return MemVT.getSizeInBits() <= MaxIntSize;
11139
11140 // Make sure we don't merge greater than our maximum supported vector width.
11141 if (Subtarget.hasExtLASX())
11142 MaxIntSize = 256;
11143 else if (Subtarget.hasExtLSX())
11144 MaxIntSize = 128;
11145
11146 return MemVT.getSizeInBits() <= MaxIntSize;
11147}
11148
11150 EVT VT = Y.getValueType();
11151
11152 if (VT.isVector())
11153 return Subtarget.hasExtLSX() && VT.isInteger();
11154
11155 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
11156}
11157
11160 MachineFunction &MF, unsigned Intrinsic) const {
11161 switch (Intrinsic) {
11162 default:
11163 return;
11164 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
11165 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
11166 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
11167 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
11168 IntrinsicInfo Info;
11170 Info.memVT = MVT::i32;
11171 Info.ptrVal = I.getArgOperand(0);
11172 Info.offset = 0;
11173 Info.align = Align(4);
11176 Infos.push_back(Info);
11177 return;
11178 // TODO: Add more Intrinsics later.
11179 }
11180 }
11181}
11182
11183// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
11184// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
11185// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
11186// regression, we need to implement it manually.
11189
11191 Op == AtomicRMWInst::And) &&
11192 "Unable to expand");
11193 unsigned MinWordSize = 4;
11194
11195 IRBuilder<> Builder(AI);
11196 LLVMContext &Ctx = Builder.getContext();
11197 const DataLayout &DL = AI->getDataLayout();
11198 Type *ValueType = AI->getType();
11199 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
11200
11201 Value *Addr = AI->getPointerOperand();
11202 PointerType *PtrTy = cast<PointerType>(Addr->getType());
11203 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
11204
11205 Value *AlignedAddr = Builder.CreateIntrinsic(
11206 Intrinsic::ptrmask, {PtrTy, IntTy},
11207 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
11208 "AlignedAddr");
11209
11210 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
11211 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
11212 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
11213 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
11214 Value *Mask = Builder.CreateShl(
11215 ConstantInt::get(WordType,
11216 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
11217 ShiftAmt, "Mask");
11218 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
11219 Value *ValOperand_Shifted =
11220 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
11221 ShiftAmt, "ValOperand_Shifted");
11222 Value *NewOperand;
11223 if (Op == AtomicRMWInst::And)
11224 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
11225 else
11226 NewOperand = ValOperand_Shifted;
11227
11228 AtomicRMWInst *NewAI =
11229 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
11230 AI->getOrdering(), AI->getSyncScopeID());
11231
11232 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
11233 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
11234 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
11235 AI->replaceAllUsesWith(FinalOldResult);
11236 AI->eraseFromParent();
11237}
11238
11241 const AtomicRMWInst *AI) const {
11242 // TODO: Add more AtomicRMWInst that needs to be extended.
11243
11244 // Since floating-point operation requires a non-trivial set of data
11245 // operations, use CmpXChg to expand.
11246 if (AI->isFloatingPointOperation() ||
11252
11253 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
11256 AI->getOperation() == AtomicRMWInst::Sub)) {
11258 }
11259
11260 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
11261 if (Subtarget.hasLAMCAS()) {
11262 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
11266 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
11268 }
11269
11270 if (Size == 8 || Size == 16)
11273}
11274
11275static Intrinsic::ID
11277 AtomicRMWInst::BinOp BinOp) {
11278 if (GRLen == 64) {
11279 switch (BinOp) {
11280 default:
11281 llvm_unreachable("Unexpected AtomicRMW BinOp");
11283 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
11284 case AtomicRMWInst::Add:
11285 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
11286 case AtomicRMWInst::Sub:
11287 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
11289 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
11291 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
11293 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
11294 case AtomicRMWInst::Max:
11295 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
11296 case AtomicRMWInst::Min:
11297 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11298 // TODO: support other AtomicRMWInst.
11299 }
11300 }
11301
11302 if (GRLen == 32) {
11303 switch (BinOp) {
11304 default:
11305 llvm_unreachable("Unexpected AtomicRMW BinOp");
11307 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11308 case AtomicRMWInst::Add:
11309 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11310 case AtomicRMWInst::Sub:
11311 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11313 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11315 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11317 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11318 case AtomicRMWInst::Max:
11319 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11320 case AtomicRMWInst::Min:
11321 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11322 // TODO: support other AtomicRMWInst.
11323 }
11324 }
11325
11326 llvm_unreachable("Unexpected GRLen\n");
11327}
11328
11331 const AtomicCmpXchgInst *CI) const {
11332
11333 if (Subtarget.hasLAMCAS())
11335
11337 if (Size == 8 || Size == 16)
11340}
11341
11343 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11344 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11345 unsigned GRLen = Subtarget.getGRLen();
11346 AtomicOrdering FailOrd = CI->getFailureOrdering();
11347 Value *FailureOrdering =
11348 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11349 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11350 if (GRLen == 64) {
11351 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11352 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11353 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11354 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11355 }
11356 Type *Tys[] = {AlignedAddr->getType()};
11357 Value *Result = Builder.CreateIntrinsic(
11358 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11359 if (GRLen == 64)
11360 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11361 return Result;
11362}
11363
11365 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11366 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11367 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11368 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11369 // mask, as this produces better code than the LL/SC loop emitted by
11370 // int_loongarch_masked_atomicrmw_xchg.
11371 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11374 if (CVal->isZero())
11375 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11376 Builder.CreateNot(Mask, "Inv_Mask"),
11377 AI->getAlign(), Ord);
11378 if (CVal->isMinusOne())
11379 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11380 AI->getAlign(), Ord);
11381 }
11382
11383 unsigned GRLen = Subtarget.getGRLen();
11384 Value *Ordering =
11385 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11386 Type *Tys[] = {AlignedAddr->getType()};
11388 AI->getModule(),
11390
11391 if (GRLen == 64) {
11392 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11393 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11394 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11395 }
11396
11397 Value *Result;
11398
11399 // Must pass the shift amount needed to sign extend the loaded value prior
11400 // to performing a signed comparison for min/max. ShiftAmt is the number of
11401 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11402 // is the number of bits to left+right shift the value in order to
11403 // sign-extend.
11404 if (AI->getOperation() == AtomicRMWInst::Min ||
11406 const DataLayout &DL = AI->getDataLayout();
11407 unsigned ValWidth =
11408 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11409 Value *SextShamt =
11410 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11411 Result = Builder.CreateCall(LlwOpScwLoop,
11412 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11413 } else {
11414 Result =
11415 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11416 }
11417
11418 if (GRLen == 64)
11419 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11420 return Result;
11421}
11422
11424 const MachineFunction &MF, EVT VT) const {
11425 VT = VT.getScalarType();
11426
11427 if (!VT.isSimple())
11428 return false;
11429
11430 switch (VT.getSimpleVT().SimpleTy) {
11431 case MVT::f32:
11432 case MVT::f64:
11433 return true;
11434 default:
11435 break;
11436 }
11437
11438 return false;
11439}
11440
11442 ExceptionHandling EH, const Constant *PersonalityFn) const {
11443 return LoongArch::R4;
11444}
11445
11447 ExceptionHandling EH, const Constant *PersonalityFn) const {
11448 return LoongArch::R5;
11449}
11450
11451//===----------------------------------------------------------------------===//
11452// Target Optimization Hooks
11453//===----------------------------------------------------------------------===//
11454
11456 const LoongArchSubtarget &Subtarget) {
11457 // Feature FRECIPE instrucions relative accuracy is 2^-14.
11458 // IEEE float has 23 digits and double has 52 digits.
11459 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11460 return RefinementSteps;
11461}
11462
11463static bool
11465 assert(Subtarget.hasFrecipe() &&
11466 "Reciprocal estimate queried on unsupported target");
11467
11468 if (!VT.isSimple())
11469 return false;
11470
11471 switch (VT.getSimpleVT().SimpleTy) {
11472 case MVT::f32:
11473 // f32 is the base type for reciprocal estimate instructions.
11474 return true;
11475
11476 case MVT::f64:
11477 return Subtarget.hasBasicD();
11478
11479 case MVT::v4f32:
11480 case MVT::v2f64:
11481 return Subtarget.hasExtLSX();
11482
11483 case MVT::v8f32:
11484 case MVT::v4f64:
11485 return Subtarget.hasExtLASX();
11486
11487 default:
11488 return false;
11489 }
11490}
11491
11493 SelectionDAG &DAG, int Enabled,
11494 int &RefinementSteps,
11495 bool &UseOneConstNR,
11496 bool Reciprocal) const {
11498 "Enabled should never be Disabled here");
11499
11500 if (!Subtarget.hasFrecipe())
11501 return SDValue();
11502
11503 SDLoc DL(Operand);
11504 EVT VT = Operand.getValueType();
11505
11506 // Check supported types.
11507 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11508 return SDValue();
11509
11510 // Handle refinement steps.
11511 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11512 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11513
11514 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
11515 UseOneConstNR = false;
11516 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
11517
11518 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
11519 // are needed (which rely on the reciprocal form), return the raw reciprocal
11520 // estimate.
11521 if (Reciprocal || RefinementSteps > 0)
11522 return Rsqrt;
11523
11524 // Otherwise, return sqrt(x) by multiplying with the operand.
11525 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
11526}
11527
11529 SelectionDAG &DAG,
11530 int Enabled,
11531 int &RefinementSteps) const {
11533 "Enabled should never be Disabled here");
11534
11535 if (!Subtarget.hasFrecipe())
11536 return SDValue();
11537
11538 SDLoc DL(Operand);
11539 EVT VT = Operand.getValueType();
11540
11541 // Check supported types.
11542 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11543 return SDValue();
11544
11545 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11546 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11547
11548 // FRECIPE computes 1.0 / x.
11549 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
11550}
11551
11552//===----------------------------------------------------------------------===//
11553// LoongArch Inline Assembly Support
11554//===----------------------------------------------------------------------===//
11555
11557LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
11558 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
11559 //
11560 // 'f': A floating-point register (if available).
11561 // 'k': A memory operand whose address is formed by a base register and
11562 // (optionally scaled) index register.
11563 // 'l': A signed 16-bit constant.
11564 // 'm': A memory operand whose address is formed by a base register and
11565 // offset that is suitable for use in instructions with the same
11566 // addressing mode as st.w and ld.w.
11567 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
11568 // instruction)
11569 // 'I': A signed 12-bit constant (for arithmetic instructions).
11570 // 'J': Integer zero.
11571 // 'K': An unsigned 12-bit constant (for logic instructions).
11572 // "ZB": An address that is held in a general-purpose register. The offset is
11573 // zero.
11574 // "ZC": A memory operand whose address is formed by a base register and
11575 // offset that is suitable for use in instructions with the same
11576 // addressing mode as ll.w and sc.w.
11577 if (Constraint.size() == 1) {
11578 switch (Constraint[0]) {
11579 default:
11580 break;
11581 case 'f':
11582 case 'q':
11583 return C_RegisterClass;
11584 case 'l':
11585 case 'I':
11586 case 'J':
11587 case 'K':
11588 return C_Immediate;
11589 case 'k':
11590 return C_Memory;
11591 }
11592 }
11593
11594 if (Constraint == "ZC" || Constraint == "ZB")
11595 return C_Memory;
11596
11597 // 'm' is handled here.
11598 return TargetLowering::getConstraintType(Constraint);
11599}
11600
11601InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
11602 StringRef ConstraintCode) const {
11603 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
11607 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
11608}
11609
11610std::pair<unsigned, const TargetRegisterClass *>
11611LoongArchTargetLowering::getRegForInlineAsmConstraint(
11612 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
11613 // First, see if this is a constraint that directly corresponds to a LoongArch
11614 // register class.
11615 if (Constraint.size() == 1) {
11616 switch (Constraint[0]) {
11617 case 'r':
11618 // TODO: Support fixed vectors up to GRLen?
11619 if (VT.isVector())
11620 break;
11621 return std::make_pair(0U, &LoongArch::GPRRegClass);
11622 case 'q':
11623 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
11624 case 'f':
11625 if (Subtarget.hasBasicF() && VT == MVT::f32)
11626 return std::make_pair(0U, &LoongArch::FPR32RegClass);
11627 if (Subtarget.hasBasicD() && VT == MVT::f64)
11628 return std::make_pair(0U, &LoongArch::FPR64RegClass);
11629 if (Subtarget.hasExtLSX() &&
11630 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
11631 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11632 if (Subtarget.hasExtLSX() && VT == MVT::i128)
11633 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11634 if (Subtarget.hasExtLASX() &&
11635 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
11636 return std::make_pair(0U, &LoongArch::LASX256RegClass);
11637 break;
11638 default:
11639 break;
11640 }
11641 }
11642
11643 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
11644 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
11645 // constraints while the official register name is prefixed with a '$'. So we
11646 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
11647 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
11648 // case insensitive, so no need to convert the constraint to upper case here.
11649 //
11650 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
11651 // decode the usage of register name aliases into their official names. And
11652 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
11653 // official register names.
11654 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
11655 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
11656 bool IsFP = Constraint[2] == 'f';
11657 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
11658 std::pair<unsigned, const TargetRegisterClass *> R;
11660 TRI, join_items("", Temp.first, Temp.second), VT);
11661 // Match those names to the widest floating point register type available.
11662 if (IsFP) {
11663 unsigned RegNo = R.first;
11664 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
11665 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
11666 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
11667 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
11668 }
11669 }
11670 }
11671 return R;
11672 }
11673
11674 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
11675}
11676
11677void LoongArchTargetLowering::LowerAsmOperandForConstraint(
11678 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
11679 SelectionDAG &DAG) const {
11680 // Currently only support length 1 constraints.
11681 if (Constraint.size() == 1) {
11682 switch (Constraint[0]) {
11683 case 'l':
11684 // Validate & create a 16-bit signed immediate operand.
11685 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11686 uint64_t CVal = C->getSExtValue();
11687 if (isInt<16>(CVal))
11688 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11689 Subtarget.getGRLenVT()));
11690 }
11691 return;
11692 case 'I':
11693 // Validate & create a 12-bit signed immediate operand.
11694 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11695 uint64_t CVal = C->getSExtValue();
11696 if (isInt<12>(CVal))
11697 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11698 Subtarget.getGRLenVT()));
11699 }
11700 return;
11701 case 'J':
11702 // Validate & create an integer zero operand.
11703 if (auto *C = dyn_cast<ConstantSDNode>(Op))
11704 if (C->getZExtValue() == 0)
11705 Ops.push_back(
11706 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
11707 return;
11708 case 'K':
11709 // Validate & create a 12-bit unsigned immediate operand.
11710 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11711 uint64_t CVal = C->getZExtValue();
11712 if (isUInt<12>(CVal))
11713 Ops.push_back(
11714 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
11715 }
11716 return;
11717 default:
11718 break;
11719 }
11720 }
11722}
11723
11724#define GET_REGISTER_MATCHER
11725#include "LoongArchGenAsmMatcher.inc"
11726
11729 const MachineFunction &MF) const {
11730 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
11731 std::string NewRegName = Name.second.str();
11732 Register Reg = MatchRegisterAltName(NewRegName);
11733 if (!Reg)
11734 Reg = MatchRegisterName(NewRegName);
11735 if (!Reg)
11736 return Reg;
11737 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
11738 if (!ReservedRegs.test(Reg))
11739 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
11740 StringRef(RegName) + "\"."));
11741 return Reg;
11742}
11743
11745 EVT VT, SDValue C) const {
11746 // TODO: Support vectors.
11747 if (!VT.isScalarInteger())
11748 return false;
11749
11750 // Omit the optimization if the data size exceeds GRLen.
11751 if (VT.getSizeInBits() > Subtarget.getGRLen())
11752 return false;
11753
11754 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
11755 const APInt &Imm = ConstNode->getAPIntValue();
11756 // Break MUL into (SLLI + ADD/SUB) or ALSL.
11757 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
11758 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
11759 return true;
11760 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
11761 if (ConstNode->hasOneUse() &&
11762 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
11763 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
11764 return true;
11765 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
11766 // in which the immediate has two set bits. Or Break (MUL x, imm)
11767 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
11768 // equals to (1 << s0) - (1 << s1).
11769 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
11770 unsigned Shifts = Imm.countr_zero();
11771 // Reject immediates which can be composed via a single LUI.
11772 if (Shifts >= 12)
11773 return false;
11774 // Reject multiplications can be optimized to
11775 // (SLLI (ALSL x, x, 1/2/3/4), s).
11776 APInt ImmPop = Imm.ashr(Shifts);
11777 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
11778 return false;
11779 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
11780 // since it needs one more instruction than other 3 cases.
11781 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
11782 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
11783 (ImmSmall - Imm).isPowerOf2())
11784 return true;
11785 }
11786 }
11787
11788 return false;
11789}
11790
11792 const AddrMode &AM,
11793 Type *Ty, unsigned AS,
11794 Instruction *I) const {
11795 // LoongArch has four basic addressing modes:
11796 // 1. reg
11797 // 2. reg + 12-bit signed offset
11798 // 3. reg + 14-bit signed offset left-shifted by 2
11799 // 4. reg1 + reg2
11800 // TODO: Add more checks after support vector extension.
11801
11802 // No global is ever allowed as a base.
11803 if (AM.BaseGV)
11804 return false;
11805
11806 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
11807 // with `UAL` feature.
11808 if (!isInt<12>(AM.BaseOffs) &&
11809 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
11810 return false;
11811
11812 switch (AM.Scale) {
11813 case 0:
11814 // "r+i" or just "i", depending on HasBaseReg.
11815 break;
11816 case 1:
11817 // "r+r+i" is not allowed.
11818 if (AM.HasBaseReg && AM.BaseOffs)
11819 return false;
11820 // Otherwise we have "r+r" or "r+i".
11821 break;
11822 case 2:
11823 // "2*r+r" or "2*r+i" is not allowed.
11824 if (AM.HasBaseReg || AM.BaseOffs)
11825 return false;
11826 // Allow "2*r" as "r+r".
11827 break;
11828 default:
11829 return false;
11830 }
11831
11832 return true;
11833}
11834
11836 return isInt<12>(Imm);
11837}
11838
11840 return isInt<12>(Imm);
11841}
11842
11844 // Zexts are free if they can be combined with a load.
11845 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
11846 // poorly with type legalization of compares preferring sext.
11847 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
11848 EVT MemVT = LD->getMemoryVT();
11849 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
11850 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
11851 LD->getExtensionType() == ISD::ZEXTLOAD))
11852 return true;
11853 }
11854
11855 return TargetLowering::isZExtFree(Val, VT2);
11856}
11857
11859 EVT DstVT) const {
11860 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
11861}
11862
11864 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
11865}
11866
11868 // TODO: Support vectors.
11869 if (Y.getValueType().isVector())
11870 return false;
11871
11872 return !isa<ConstantSDNode>(Y);
11873}
11874
11876 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
11877 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
11878}
11879
11881 Type *Ty, bool IsSigned) const {
11882 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
11883 return true;
11884
11885 return IsSigned;
11886}
11887
11889 // Return false to suppress the unnecessary extensions if the LibCall
11890 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
11891 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
11892 Type.getSizeInBits() < Subtarget.getGRLen()))
11893 return false;
11894 return true;
11895}
11896
11897// memcpy, and other memory intrinsics, typically tries to use wider load/store
11898// if the source/dest is aligned and the copy size is large enough. We therefore
11899// want to align such objects passed to memory intrinsics.
11901 unsigned &MinSize,
11902 Align &PrefAlign) const {
11903 if (!isa<MemIntrinsic>(CI))
11904 return false;
11905
11906 if (Subtarget.is64Bit()) {
11907 MinSize = 8;
11908 PrefAlign = Align(8);
11909 } else {
11910 MinSize = 4;
11911 PrefAlign = Align(4);
11912 }
11913
11914 return true;
11915}
11916
11919 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
11920 VT.getVectorElementType() != MVT::i1)
11921 return TypeWidenVector;
11922
11924}
11925
11926bool LoongArchTargetLowering::splitValueIntoRegisterParts(
11927 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
11928 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
11929 bool IsABIRegCopy = CC.has_value();
11930 EVT ValueVT = Val.getValueType();
11931
11932 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11933 PartVT == MVT::f32) {
11934 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
11935 // nan, and cast to f32.
11936 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
11937 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
11938 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
11939 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
11940 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
11941 Parts[0] = Val;
11942 return true;
11943 }
11944
11945 return false;
11946}
11947
11948SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
11949 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
11950 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
11951 bool IsABIRegCopy = CC.has_value();
11952
11953 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11954 PartVT == MVT::f32) {
11955 SDValue Val = Parts[0];
11956
11957 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
11958 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
11959 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
11960 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
11961 return Val;
11962 }
11963
11964 return SDValue();
11965}
11966
11967MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
11968 CallingConv::ID CC,
11969 EVT VT) const {
11970 // Use f32 to pass f16.
11971 if (VT == MVT::f16 && Subtarget.hasBasicF())
11972 return MVT::f32;
11973
11975}
11976
11977unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
11978 LLVMContext &Context, CallingConv::ID CC, EVT VT) const {
11979 // Use f32 to pass f16.
11980 if (VT == MVT::f16 && Subtarget.hasBasicF())
11981 return 1;
11982
11984}
11985
11987 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
11988 const SelectionDAG &DAG, unsigned Depth) const {
11989 unsigned Opc = Op.getOpcode();
11990 Known.resetAll();
11991 switch (Opc) {
11992 default:
11993 break;
11994 case LoongArchISD::VANYNONZERO:
11995 case LoongArchISD::VALLZERO: {
11996 // MOVCF2GR zero-extend the i1 cond to GPR.
11997 Known.Zero.setBitsFrom(1);
11998 break;
11999 }
12000 case LoongArchISD::VALL_ZERO:
12001 case LoongArchISD::VANY_ZERO:
12002 case LoongArchISD::VALL_NONZERO:
12003 case LoongArchISD::VANY_NONZERO: {
12004 // Materialized as literal 0/1 by the Pseudo{,X}VB{Z,NZ}_[BHWD]'s custom
12005 // inserter, emitVecCondBranchPseudo().
12006 Known.Zero.setBitsFrom(1);
12007 break;
12008 }
12009 case LoongArchISD::VPICK_ZEXT_ELT: {
12010 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
12011 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
12012 unsigned VTBits = VT.getScalarSizeInBits();
12013 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
12014 Known.Zero.setBitsFrom(VTBits);
12015 break;
12016 }
12017 }
12018}
12019
12021 SDValue Op, const APInt &OriginalDemandedBits,
12022 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
12023 unsigned Depth) const {
12024 EVT VT = Op.getValueType();
12025 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
12026 unsigned Opc = Op.getOpcode();
12027 switch (Opc) {
12028 default:
12029 break;
12030 case LoongArchISD::CRC_W_B_W:
12031 case LoongArchISD::CRC_W_H_W:
12032 case LoongArchISD::CRCC_W_B_W:
12033 case LoongArchISD::CRCC_W_H_W: {
12034 KnownBits KnownSrc;
12035 APInt DemandedSrcBits =
12036 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
12037 Opc == LoongArchISD::CRCC_W_B_W)
12038 ? 8
12039 : 16);
12040 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
12041 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
12042 }
12043 case LoongArchISD::VMSKLTZ:
12044 case LoongArchISD::XVMSKLTZ: {
12045 SDValue Src = Op.getOperand(0);
12046 MVT SrcVT = Src.getSimpleValueType();
12047 unsigned SrcBits = SrcVT.getScalarSizeInBits();
12048 unsigned NumElts = SrcVT.getVectorNumElements();
12049
12050 // If we don't need the sign bits at all just return zero.
12051 if (OriginalDemandedBits.countr_zero() >= NumElts)
12052 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
12053
12054 // Only demand the vector elements of the sign bits we need.
12055 APInt KnownUndef, KnownZero;
12056 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
12057 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
12058 TLO, Depth + 1))
12059 return true;
12060
12061 Known.Zero = KnownZero.zext(BitWidth);
12062 Known.Zero.setHighBits(BitWidth - NumElts);
12063
12064 // [X]VMSKLTZ only uses the MSB from each vector element.
12065 KnownBits KnownSrc;
12066 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
12067 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
12068 Depth + 1))
12069 return true;
12070
12071 if (KnownSrc.One[SrcBits - 1])
12072 Known.One.setLowBits(NumElts);
12073 else if (KnownSrc.Zero[SrcBits - 1])
12074 Known.Zero.setLowBits(NumElts);
12075
12076 // Attempt to avoid multi-use ops if we don't need anything from it.
12078 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
12079 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
12080 return false;
12081 }
12082 }
12083
12085 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
12086}
12087
12089 unsigned Opc = VecOp.getOpcode();
12090
12091 // Assume target opcodes can't be scalarized.
12092 // TODO - do we have any exceptions?
12093 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
12094 return false;
12095
12096 // If the vector op is not supported, try to convert to scalar.
12097 EVT VecVT = VecOp.getValueType();
12099 return true;
12100
12101 // If the vector op is supported, but the scalar op is not, the transform may
12102 // not be worthwhile.
12103 EVT ScalarVT = VecVT.getScalarType();
12104 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
12105}
12106
12109 unsigned Index) const {
12112
12113 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
12114 if (Index == 0)
12117}
12118
12120 unsigned Index) const {
12121 EVT EltVT = VT.getScalarType();
12122
12123 // Extract a scalar FP value from index 0 of a vector is free.
12124 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
12125}
12126
12128 const MachineFunction &MF) const {
12129
12130 // If the function specifically requests inline stack probes, emit them.
12131 if (MF.getFunction().hasFnAttribute("probe-stack"))
12132 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
12133 "inline-asm";
12134
12135 return false;
12136}
12137
12139 Align StackAlign) const {
12140 // The default stack probe size is 4096 if the function has no
12141 // stack-probe-size attribute.
12142 const Function &Fn = MF.getFunction();
12143 unsigned StackProbeSize =
12144 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
12145 // Round down to the stack alignment.
12146 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
12147 return StackProbeSize ? StackProbeSize : StackAlign.value();
12148}
12149
12150SDValue
12151LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
12152 SelectionDAG &DAG) const {
12154 if (!hasInlineStackProbe(MF))
12155 return SDValue();
12156
12157 const MVT GRLenVT = Subtarget.getGRLenVT();
12158 // Get the inputs.
12159 SDValue Chain = Op.getOperand(0);
12160 SDValue Size = Op.getOperand(1);
12161
12162 const MaybeAlign Align =
12163 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
12164 const SDLoc dl(Op);
12165 const EVT VT = Op.getValueType();
12166
12167 // Construct the new SP value in a GPR.
12168 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
12169 Chain = SP.getValue(1);
12170 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
12171 if (Align)
12172 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
12173 DAG.getSignedConstant(-Align->value(), dl, VT));
12174
12175 // Set the real SP to the new value with a probing loop.
12176 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
12177 return DAG.getMergeValues({SP, Chain}, dl);
12178}
12179
12182 MachineBasicBlock *MBB) const {
12183 MachineFunction &MF = *MBB->getParent();
12184 MachineBasicBlock::iterator MBBI = MI.getIterator();
12185 DebugLoc DL = MBB->findDebugLoc(MBBI);
12186 const Register TargetReg = MI.getOperand(0).getReg();
12187
12188 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
12189 const bool IsLA64 = Subtarget.is64Bit();
12190 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
12191 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
12192 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
12193
12194 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
12195 MachineBasicBlock *const LoopTestMBB =
12196 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12197 MF.insert(MBBInsertPoint, LoopTestMBB);
12198 MachineBasicBlock *const ExitMBB =
12199 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12200 MF.insert(MBBInsertPoint, ExitMBB);
12201 const Register SPReg = LoongArch::R3;
12202 const Register ScratchReg =
12203 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
12204
12205 // ScratchReg = ProbeSize
12206 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
12207
12208 // LoopTest:
12209 // sub.{w/d} $sp, $sp, ScratchReg
12210 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12211 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
12212 .addReg(SPReg)
12213 .addReg(ScratchReg);
12214
12215 // st.{w/d} $zero, $sp, 0
12216 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12217 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
12218 .addReg(LoongArch::R0)
12219 .addReg(SPReg)
12220 .addImm(0);
12221
12222 // bltu TargetReg, $sp, LoopTest
12223 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
12224 .addReg(TargetReg)
12225 .addReg(SPReg)
12226 .addMBB(LoopTestMBB);
12227
12228 // move $sp, TargetReg
12229 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
12230 .addReg(TargetReg)
12231 .addReg(LoongArch::R0);
12232
12233 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
12235
12236 LoopTestMBB->addSuccessor(ExitMBB);
12237 LoopTestMBB->addSuccessor(LoopTestMBB);
12238 MBB->addSuccessor(LoopTestMBB);
12239
12240 MI.eraseFromParent();
12241 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
12242 return ExitMBB->begin()->getParent();
12243}
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)
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)
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)
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
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 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 MachineBasicBlock * emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
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
const SmallVectorImpl< MachineOperand > & Cond
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
LLVM_READONLY bool isOne() const
Definition APFloat.h:1661
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
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
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:2909
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
const LoongArchRegisterInfo * getRegisterInfo() const override
const LoongArchTargetLowering * getTargetLowering() const override
const LoongArchInstrInfo * getInstrInfo() const override
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.
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.
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 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.
bool isImplicitDef() const
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 LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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
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)
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)
bool isOperationLegalOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal using promotion.
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.
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:549
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:541
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:267
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:418
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
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:307
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:323
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:155
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:230
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:404
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:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:235
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:351
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:484
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:160
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
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...