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 // The legalizer builds immediates the size of a GPR from their bits. Fall
956 // back to a load from the constant pool for expensive immediates.
957 if (VT.getSizeInBits() == Subtarget.getGRLen() ||
958 !isFPImmCheapInGPR(FPVal, VT))
959 return SDValue();
960
961 // Construct as integer, and move to float register.
962 APInt INTVal = FPVal.bitcastToAPInt();
963 if (VT == MVT::f32) {
964 assert(Subtarget.is64Bit());
965 SDValue NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
966 DAG.getConstant(INTVal, DL, MVT::i32));
967 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, VT, NewVal);
968 }
969
970 assert(VT == MVT::f64 && !Subtarget.is64Bit());
971 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
972 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
973 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
974}
975
976// Ensure SETCC result and operand have the same bit width; isel does not
977// support mismatched widths.
978SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
979 SelectionDAG &DAG) const {
980 SDLoc DL(Op);
981 EVT ResultVT = Op.getValueType();
982 EVT OperandVT = Op.getOperand(0).getValueType();
983
984 EVT SetCCResultVT =
985 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
986
987 if (ResultVT == SetCCResultVT)
988 return Op;
989
990 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
991 "SETCC operands must have the same type!");
992
993 SDValue SetCCNode =
994 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
995 Op.getOperand(1), Op.getOperand(2));
996
997 if (ResultVT.bitsGT(SetCCResultVT))
998 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
999 else if (ResultVT.bitsLT(SetCCResultVT))
1000 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
1001
1002 return SetCCNode;
1003}
1004
1005// Lower sext_invec using vslti instructions.
1006// For example:
1007// %b = sext <4 x i16> %a to <4 x i32>
1008// can be lowered to:
1009// VSLTI_H vr2, vr1, 0
1010// VILVL.H vr1, vr2, vr1
1011SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1012 SDValue Op, SelectionDAG &DAG) const {
1013 SDLoc DL(Op);
1014 SDValue Src = Op.getOperand(0);
1015 MVT SrcVT = Src.getSimpleValueType();
1016 MVT DstVT = Op.getSimpleValueType();
1017
1018 if (!SrcVT.is128BitVector())
1019 return SDValue();
1020
1021 // lower to VSLTI + VILVL if extend could be done in single step.
1022 if (DstVT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits() == 2) {
1023 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
1024 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Src, Zero,
1025 DAG.getCondCode(ISD::SETLT));
1026 SDValue LoInterleaved =
1027 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Src);
1028
1029 return DAG.getBitcast(DstVT, LoInterleaved);
1030 }
1031
1032 return SDValue();
1033}
1034
1035// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1036SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1037 SelectionDAG &DAG) const {
1038 assert(Subtarget.hasExtLASX());
1039 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1040 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1041 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1042 Op.getOperand(0));
1043}
1044
1045// Lower vecreduce_add using vhaddw instructions.
1046// For Example:
1047// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1048// can be lowered to:
1049// VHADDW_D_W vr0, vr0, vr0
1050// VHADDW_Q_D vr0, vr0, vr0
1051// VPICKVE2GR_D a0, vr0, 0
1052// ADDI_W a0, a0, 0
1053SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1054 SelectionDAG &DAG) const {
1055
1056 SDLoc DL(Op);
1057 MVT OpVT = Op.getSimpleValueType();
1058 SDValue Val = Op.getOperand(0);
1059
1060 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1061 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1062 unsigned ResBits = OpVT.getScalarSizeInBits();
1063
1064 unsigned LegalVecSize = 128;
1065 bool isLASX256Vector =
1066 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1067
1068 // Ensure operand type legal or enable it legal.
1069 while (!isTypeLegal(Val.getSimpleValueType())) {
1070 Val = DAG.WidenVector(Val, DL);
1071 }
1072
1073 // NumEles is designed for iterations count, v4i32 for LSX
1074 // and v8i32 for LASX should have the same count.
1075 if (isLASX256Vector) {
1076 NumEles /= 2;
1077 LegalVecSize = 256;
1078 }
1079
1080 EleBits *= 2;
1081 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1082 EleBits = std::min(EleBits, 64u);
1083 MVT IntTy = MVT::getIntegerVT(EleBits);
1084 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1085 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1086 }
1087
1088 if (isLASX256Vector) {
1089 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1090 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1091 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1092 }
1093
1094 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1095 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1096 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1097}
1098
1099// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1100// For Example:
1101// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1102// can be lowered to:
1103// VBSRL_V vr1, vr0, 8
1104// VMAX_W vr0, vr1, vr0
1105// VBSRL_V vr1, vr0, 4
1106// VMAX_W vr0, vr1, vr0
1107// VPICKVE2GR_W a0, vr0, 0
1108// For 256 bit vector, it is illegal and will be spilt into
1109// two 128 bit vector by default then processed by this.
1110SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1111 SelectionDAG &DAG) const {
1112 SDLoc DL(Op);
1113
1114 MVT OpVT = Op.getSimpleValueType();
1115 SDValue Val = Op.getOperand(0);
1116
1117 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1118 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1119
1120 // Ensure operand type legal or enable it legal.
1121 while (!isTypeLegal(Val.getSimpleValueType())) {
1122 Val = DAG.WidenVector(Val, DL);
1123 }
1124
1125 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1126 MVT VecTy = Val.getSimpleValueType();
1127 MVT GRLenVT = Subtarget.getGRLenVT();
1128
1129 for (int i = NumEles; i > 1; i /= 2) {
1130 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1131 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1132 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1133 }
1134
1135 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1136 DAG.getConstant(0, DL, GRLenVT));
1137}
1138
1139SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1140 SelectionDAG &DAG) const {
1141 unsigned IsData = Op.getConstantOperandVal(4);
1142
1143 // We don't support non-data prefetch.
1144 // Just preserve the chain.
1145 if (!IsData)
1146 return Op.getOperand(0);
1147
1148 return Op;
1149}
1150
1151SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1152 SelectionDAG &DAG) const {
1153 MVT VT = Op.getSimpleValueType();
1154 assert(VT.isVector() && "Unexpected type");
1155
1156 SDLoc DL(Op);
1157 SDValue R = Op.getOperand(0);
1158 SDValue Amt = Op.getOperand(1);
1159 unsigned Opcode = Op.getOpcode();
1160 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1161
1162 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1163 if (V.getOpcode() != ISD::BUILD_VECTOR)
1164 return false;
1165 if (SDValue SplatValue =
1166 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1167 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1168 CstSplatValue = C->getAPIntValue();
1169 return true;
1170 }
1171 }
1172 return false;
1173 };
1174
1175 // Check for constant splat rotation amount.
1176 APInt CstSplatValue;
1177 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1178 bool isROTL = Opcode == ISD::ROTL;
1179
1180 // Check for splat rotate by zero.
1181 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1182 return R;
1183
1184 // LoongArch targets always prefer ISD::ROTR.
1185 if (isROTL) {
1186 SDValue Zero = DAG.getConstant(0, DL, VT);
1187 return DAG.getNode(ISD::ROTR, DL, VT, R,
1188 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1189 }
1190
1191 // Rotate by a immediate.
1192 if (IsCstSplat) {
1193 // ISD::ROTR: Attemp to rotate by a positive immediate.
1194 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1195 if (SDValue Urem =
1196 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1197 return DAG.getNode(Opcode, DL, VT, R, Urem);
1198 }
1199
1200 return Op;
1201}
1202
1203// Return true if Val is equal to (setcc LHS, RHS, CC).
1204// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1205// Otherwise, return std::nullopt.
1206static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1207 ISD::CondCode CC, SDValue Val) {
1208 assert(Val->getOpcode() == ISD::SETCC);
1209 SDValue LHS2 = Val.getOperand(0);
1210 SDValue RHS2 = Val.getOperand(1);
1211 ISD::CondCode CC2 = cast<CondCodeSDNode>(Val.getOperand(2))->get();
1212
1213 if (LHS == LHS2 && RHS == RHS2) {
1214 if (CC == CC2)
1215 return true;
1216 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1217 return false;
1218 } else if (LHS == RHS2 && RHS == LHS2) {
1220 if (CC == CC2)
1221 return true;
1222 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1223 return false;
1224 }
1225
1226 return std::nullopt;
1227}
1228
1230 const LoongArchSubtarget &Subtarget) {
1231 SDValue CondV = N->getOperand(0);
1232 SDValue TrueV = N->getOperand(1);
1233 SDValue FalseV = N->getOperand(2);
1234 MVT VT = N->getSimpleValueType(0);
1235 SDLoc DL(N);
1236
1237 // (select c, -1, y) -> -c | y
1238 if (isAllOnesConstant(TrueV)) {
1239 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1240 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1241 }
1242 // (select c, y, -1) -> (c-1) | y
1243 if (isAllOnesConstant(FalseV)) {
1244 SDValue Neg =
1245 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1246 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1247 }
1248
1249 // (select c, 0, y) -> (c-1) & y
1250 if (isNullConstant(TrueV)) {
1251 SDValue Neg =
1252 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1253 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1254 }
1255 // (select c, y, 0) -> -c & y
1256 if (isNullConstant(FalseV)) {
1257 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1258 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1259 }
1260
1261 // select c, ~x, x --> xor -c, x
1262 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1263 const APInt &TrueVal = TrueV->getAsAPIntVal();
1264 const APInt &FalseVal = FalseV->getAsAPIntVal();
1265 if (~TrueVal == FalseVal) {
1266 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1267 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1268 }
1269 }
1270
1271 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1272 // when both truev and falsev are also setcc.
1273 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1274 FalseV.getOpcode() == ISD::SETCC) {
1275 SDValue LHS = CondV.getOperand(0);
1276 SDValue RHS = CondV.getOperand(1);
1278
1279 // (select x, x, y) -> x | y
1280 // (select !x, x, y) -> x & y
1281 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1282 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1283 DAG.getFreeze(FalseV));
1284 }
1285 // (select x, y, x) -> x & y
1286 // (select !x, y, x) -> x | y
1287 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1288 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1289 DAG.getFreeze(TrueV), FalseV);
1290 }
1291 }
1292
1293 return SDValue();
1294}
1295
1296// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1297// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1298// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1299// being `0` or `-1`. In such cases we can replace `select` with `and`.
1300// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1301// than `c0`?
1302static SDValue
1304 const LoongArchSubtarget &Subtarget) {
1305 unsigned SelOpNo = 0;
1306 SDValue Sel = BO->getOperand(0);
1307 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1308 SelOpNo = 1;
1309 Sel = BO->getOperand(1);
1310 }
1311
1312 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1313 return SDValue();
1314
1315 unsigned ConstSelOpNo = 1;
1316 unsigned OtherSelOpNo = 2;
1317 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1318 ConstSelOpNo = 2;
1319 OtherSelOpNo = 1;
1320 }
1321 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1322 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1323 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1324 return SDValue();
1325
1326 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1327 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1328 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1329 return SDValue();
1330
1331 SDLoc DL(Sel);
1332 EVT VT = BO->getValueType(0);
1333
1334 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1335 if (SelOpNo == 1)
1336 std::swap(NewConstOps[0], NewConstOps[1]);
1337
1338 SDValue NewConstOp =
1339 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1340 if (!NewConstOp)
1341 return SDValue();
1342
1343 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1344 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1345 return SDValue();
1346
1347 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1348 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1349 if (SelOpNo == 1)
1350 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1351 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1352
1353 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1354 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1355 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1356}
1357
1358// Changes the condition code and swaps operands if necessary, so the SetCC
1359// operation matches one of the comparisons supported directly by branches
1360// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1361// compare with 1/-1.
1363 ISD::CondCode &CC, SelectionDAG &DAG) {
1364 // If this is a single bit test that can't be handled by ANDI, shift the
1365 // bit to be tested to the MSB and perform a signed compare with 0.
1366 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1367 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1368 isa<ConstantSDNode>(LHS.getOperand(1))) {
1369 uint64_t Mask = LHS.getConstantOperandVal(1);
1370 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1371 unsigned ShAmt = 0;
1372 if (isPowerOf2_64(Mask)) {
1374 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1375 } else {
1376 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1377 }
1378
1379 LHS = LHS.getOperand(0);
1380 if (ShAmt != 0)
1381 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1382 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1383 return;
1384 }
1385 }
1386
1387 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1388 int64_t C = RHSC->getSExtValue();
1389 switch (CC) {
1390 default:
1391 break;
1392 case ISD::SETGT:
1393 // Convert X > -1 to X >= 0.
1394 if (C == -1) {
1395 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1396 CC = ISD::SETGE;
1397 return;
1398 }
1399 break;
1400 case ISD::SETLT:
1401 // Convert X < 1 to 0 >= X.
1402 if (C == 1) {
1403 RHS = LHS;
1404 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1405 CC = ISD::SETGE;
1406 return;
1407 }
1408 break;
1409 }
1410 }
1411
1412 switch (CC) {
1413 default:
1414 break;
1415 case ISD::SETGT:
1416 case ISD::SETLE:
1417 case ISD::SETUGT:
1418 case ISD::SETULE:
1420 std::swap(LHS, RHS);
1421 break;
1422 }
1423}
1424
1425SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1426 SelectionDAG &DAG) const {
1427 SDValue CondV = Op.getOperand(0);
1428 SDValue TrueV = Op.getOperand(1);
1429 SDValue FalseV = Op.getOperand(2);
1430 SDLoc DL(Op);
1431 MVT VT = Op.getSimpleValueType();
1432 MVT GRLenVT = Subtarget.getGRLenVT();
1433
1434 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1435 return V;
1436
1437 if (Op.hasOneUse()) {
1438 unsigned UseOpc = Op->user_begin()->getOpcode();
1439 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1440 SDNode *BinOp = *Op->user_begin();
1441 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1442 DAG, Subtarget)) {
1443 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1444 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1445 // may return a constant node and cause crash in lowerSELECT.
1446 if (NewSel.getOpcode() == ISD::SELECT)
1447 return lowerSELECT(NewSel, DAG);
1448 return NewSel;
1449 }
1450 }
1451 }
1452
1453 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1454 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1455 // (select condv, truev, falsev)
1456 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1457 if (CondV.getOpcode() != ISD::SETCC ||
1458 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1459 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1460 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1461
1462 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1463
1464 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1465 }
1466
1467 // If the CondV is the output of a SETCC node which operates on GRLenVT
1468 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1469 // to take advantage of the integer compare+branch instructions. i.e.: (select
1470 // (setcc lhs, rhs, cc), truev, falsev)
1471 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1472 SDValue LHS = CondV.getOperand(0);
1473 SDValue RHS = CondV.getOperand(1);
1474 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1475
1476 // Special case for a select of 2 constants that have a difference of 1.
1477 // Normally this is done by DAGCombine, but if the select is introduced by
1478 // type legalization or op legalization, we miss it. Restricting to SETLT
1479 // case for now because that is what signed saturating add/sub need.
1480 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1481 // but we would probably want to swap the true/false values if the condition
1482 // is SETGE/SETLE to avoid an XORI.
1483 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1484 CCVal == ISD::SETLT) {
1485 const APInt &TrueVal = TrueV->getAsAPIntVal();
1486 const APInt &FalseVal = FalseV->getAsAPIntVal();
1487 if (TrueVal - 1 == FalseVal)
1488 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1489 if (TrueVal + 1 == FalseVal)
1490 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1491 }
1492
1493 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1494 // 1 < x ? x : 1 -> 0 < x ? x : 1
1495 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1496 RHS == TrueV && LHS == FalseV) {
1497 LHS = DAG.getConstant(0, DL, VT);
1498 // 0 <u x is the same as x != 0.
1499 if (CCVal == ISD::SETULT) {
1500 std::swap(LHS, RHS);
1501 CCVal = ISD::SETNE;
1502 }
1503 }
1504
1505 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1506 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1507 RHS == FalseV) {
1508 RHS = DAG.getConstant(0, DL, VT);
1509 }
1510
1511 SDValue TargetCC = DAG.getCondCode(CCVal);
1512
1513 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1514 // (select (setcc lhs, rhs, CC), constant, falsev)
1515 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1516 std::swap(TrueV, FalseV);
1517 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1518 }
1519
1520 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1521 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1522}
1523
1524SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1525 SelectionDAG &DAG) const {
1526 SDValue CondV = Op.getOperand(1);
1527 SDLoc DL(Op);
1528 MVT GRLenVT = Subtarget.getGRLenVT();
1529
1530 if (CondV.getOpcode() == ISD::SETCC) {
1531 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1532 SDValue LHS = CondV.getOperand(0);
1533 SDValue RHS = CondV.getOperand(1);
1534 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1535
1536 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1537
1538 SDValue TargetCC = DAG.getCondCode(CCVal);
1539 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1540 Op.getOperand(0), LHS, RHS, TargetCC,
1541 Op.getOperand(2));
1542 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1543 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1544 Op.getOperand(0), CondV, Op.getOperand(2));
1545 }
1546 }
1547
1548 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1549 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1550 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1551}
1552
1553SDValue
1554LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1555 SelectionDAG &DAG) const {
1556 SDLoc DL(Op);
1557 MVT OpVT = Op.getSimpleValueType();
1558
1559 SDValue Vector = DAG.getUNDEF(OpVT);
1560 SDValue Val = Op.getOperand(0);
1561 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1562
1563 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1564}
1565
1566SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1567 SelectionDAG &DAG) const {
1568 EVT ResTy = Op->getValueType(0);
1569 SDValue Src = Op->getOperand(0);
1570 SDLoc DL(Op);
1571
1572 // LoongArchISD::BITREV_8B is not supported on LA32.
1573 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1574 return SDValue();
1575
1576 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1577 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1578 unsigned int NewEltNum = NewVT.getVectorNumElements();
1579
1580 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1581
1583 for (unsigned int i = 0; i < NewEltNum; i++) {
1584 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1585 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1586 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1587 ? (unsigned)LoongArchISD::BITREV_8B
1588 : (unsigned)ISD::BITREVERSE;
1589 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1590 }
1591 SDValue Res =
1592 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1593
1594 switch (ResTy.getSimpleVT().SimpleTy) {
1595 default:
1596 return SDValue();
1597 case MVT::v16i8:
1598 case MVT::v32i8:
1599 return Res;
1600 case MVT::v8i16:
1601 case MVT::v16i16:
1602 case MVT::v4i32:
1603 case MVT::v8i32: {
1605 for (unsigned int i = 0; i < NewEltNum; i++)
1606 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1607 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1608 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1609 }
1610 }
1611}
1612
1613// Widen element type to get a new mask value (if possible).
1614// For example:
1615// shufflevector <4 x i32> %a, <4 x i32> %b,
1616// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1617// is equivalent to:
1618// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1619// can be lowered to:
1620// VPACKOD_D vr0, vr0, vr1
1622 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1623 unsigned EltBits = VT.getScalarSizeInBits();
1624
1625 if (EltBits > 32 || EltBits == 1)
1626 return SDValue();
1627
1628 SmallVector<int, 8> NewMask;
1629 if (widenShuffleMaskElts(Mask, NewMask)) {
1630 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1631 : MVT::getIntegerVT(EltBits * 2);
1632 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1633 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1634 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1635 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1636 return DAG.getBitcast(
1637 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1638 }
1639 }
1640
1641 return SDValue();
1642}
1643
1644/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1645/// instruction.
1646// The funciton matches elements from one of the input vector shuffled to the
1647// left or right with zeroable elements 'shifted in'. It handles both the
1648// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1649// lane.
1650// Mostly copied from X86.
1651static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1652 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1653 int MaskOffset, const APInt &Zeroable) {
1654 int Size = Mask.size();
1655 unsigned SizeInBits = Size * ScalarSizeInBits;
1656
1657 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1658 for (int i = 0; i < Size; i += Scale)
1659 for (int j = 0; j < Shift; ++j)
1660 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1661 return false;
1662
1663 return true;
1664 };
1665
1666 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1667 int Step = 1) {
1668 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1669 if (!(Mask[i] == -1 || Mask[i] == Low))
1670 return false;
1671 return true;
1672 };
1673
1674 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1675 for (int i = 0; i != Size; i += Scale) {
1676 unsigned Pos = Left ? i + Shift : i;
1677 unsigned Low = Left ? i : i + Shift;
1678 unsigned Len = Scale - Shift;
1679 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1680 return -1;
1681 }
1682
1683 int ShiftEltBits = ScalarSizeInBits * Scale;
1684 bool ByteShift = ShiftEltBits > 64;
1685 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1686 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1687 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1688
1689 // Normalize the scale for byte shifts to still produce an i64 element
1690 // type.
1691 Scale = ByteShift ? Scale / 2 : Scale;
1692
1693 // We need to round trip through the appropriate type for the shift.
1694 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1695 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1696 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1697 return (int)ShiftAmt;
1698 };
1699
1700 unsigned MaxWidth = 128;
1701 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1702 for (int Shift = 1; Shift != Scale; ++Shift)
1703 for (bool Left : {true, false})
1704 if (CheckZeros(Shift, Scale, Left)) {
1705 int ShiftAmt = MatchShift(Shift, Scale, Left);
1706 if (0 < ShiftAmt)
1707 return ShiftAmt;
1708 }
1709
1710 // no match
1711 return -1;
1712}
1713
1714/// Lower VECTOR_SHUFFLE as shift (if possible).
1715///
1716/// For example:
1717/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1718/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1719/// is lowered to:
1720/// (VBSLL_V $v0, $v0, 4)
1721///
1722/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1723/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1724/// is lowered to:
1725/// (VSLLI_D $v0, $v0, 32)
1727 MVT VT, SDValue V1, SDValue V2,
1728 SelectionDAG &DAG,
1729 const LoongArchSubtarget &Subtarget,
1730 const APInt &Zeroable) {
1731 int Size = Mask.size();
1732 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1733
1734 MVT ShiftVT;
1735 SDValue V = V1;
1736 unsigned Opcode;
1737
1738 // Try to match shuffle against V1 shift.
1739 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1740 Mask, 0, Zeroable);
1741
1742 // If V1 failed, try to match shuffle against V2 shift.
1743 if (ShiftAmt < 0) {
1744 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1745 Mask, Size, Zeroable);
1746 V = V2;
1747 }
1748
1749 if (ShiftAmt < 0)
1750 return SDValue();
1751
1752 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1753 "Illegal integer vector type");
1754 V = DAG.getBitcast(ShiftVT, V);
1755 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1756 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1757 return DAG.getBitcast(VT, V);
1758}
1759
1760/// Determine whether a range fits a regular pattern of values.
1761/// This function accounts for the possibility of jumping over the End iterator.
1762template <typename ValType>
1763static bool
1765 unsigned CheckStride,
1767 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1768 auto &I = Begin;
1769
1770 while (I != End) {
1771 if (*I != -1 && *I != ExpectedIndex)
1772 return false;
1773 ExpectedIndex += ExpectedIndexStride;
1774
1775 // Incrementing past End is undefined behaviour so we must increment one
1776 // step at a time and check for End at each step.
1777 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1778 ; // Empty loop body.
1779 }
1780 return true;
1781}
1782
1783/// Compute whether each element of a shuffle is zeroable.
1784///
1785/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1787 SDValue V2, APInt &KnownUndef,
1788 APInt &KnownZero) {
1789 int Size = Mask.size();
1790 KnownUndef = KnownZero = APInt::getZero(Size);
1791
1793 V2 = peekThroughBitcasts(V2);
1794
1795 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1796 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1797
1798 int VectorSizeInBits = V1.getValueSizeInBits();
1799 int ScalarSizeInBits = VectorSizeInBits / Size;
1800 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1801 (void)ScalarSizeInBits;
1802
1803 for (int i = 0; i < Size; ++i) {
1804 int M = Mask[i];
1805 if (M < 0) {
1806 KnownUndef.setBit(i);
1807 continue;
1808 }
1809 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1810 KnownZero.setBit(i);
1811 continue;
1812 }
1813 }
1814}
1815
1816/// Test whether a shuffle mask is equivalent within each sub-lane.
1817///
1818/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1819/// non-trivial to compute in the face of undef lanes. The representation is
1820/// suitable for use with existing 128-bit shuffles as entries from the second
1821/// vector have been remapped to [LaneSize, 2*LaneSize).
1822static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1823 ArrayRef<int> Mask,
1824 SmallVectorImpl<int> &RepeatedMask) {
1825 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1826 RepeatedMask.assign(LaneSize, -1);
1827 int Size = Mask.size();
1828 for (int i = 0; i < Size; ++i) {
1829 assert(Mask[i] == -1 || Mask[i] >= 0);
1830 if (Mask[i] < 0)
1831 continue;
1832 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1833 // This entry crosses lanes, so there is no way to model this shuffle.
1834 return false;
1835
1836 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1837 // Adjust second vector indices to start at LaneSize instead of Size.
1838 int LocalM =
1839 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1840 if (RepeatedMask[i % LaneSize] < 0)
1841 // This is the first non-undef entry in this slot of a 128-bit lane.
1842 RepeatedMask[i % LaneSize] = LocalM;
1843 else if (RepeatedMask[i % LaneSize] != LocalM)
1844 // Found a mismatch with the repeated mask.
1845 return false;
1846 }
1847 return true;
1848}
1849
1850/// Attempts to match vector shuffle as byte rotation.
1852 ArrayRef<int> Mask) {
1853
1854 SDValue Lo, Hi;
1855 SmallVector<int, 16> RepeatedMask;
1856
1857 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1858 return -1;
1859
1860 int NumElts = RepeatedMask.size();
1861 int Rotation = 0;
1862 int Scale = 16 / NumElts;
1863
1864 for (int i = 0; i < NumElts; ++i) {
1865 int M = RepeatedMask[i];
1866 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1867 "Unexpected mask index.");
1868 if (M < 0)
1869 continue;
1870
1871 // Determine where a rotated vector would have started.
1872 int StartIdx = i - (M % NumElts);
1873 if (StartIdx == 0)
1874 return -1;
1875
1876 // If we found the tail of a vector the rotation must be the missing
1877 // front. If we found the head of a vector, it must be how much of the
1878 // head.
1879 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1880
1881 if (Rotation == 0)
1882 Rotation = CandidateRotation;
1883 else if (Rotation != CandidateRotation)
1884 return -1;
1885
1886 // Compute which value this mask is pointing at.
1887 SDValue MaskV = M < NumElts ? V1 : V2;
1888
1889 // Compute which of the two target values this index should be assigned
1890 // to. This reflects whether the high elements are remaining or the low
1891 // elements are remaining.
1892 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1893
1894 // Either set up this value if we've not encountered it before, or check
1895 // that it remains consistent.
1896 if (!TargetV)
1897 TargetV = MaskV;
1898 else if (TargetV != MaskV)
1899 return -1;
1900 }
1901
1902 // Check that we successfully analyzed the mask, and normalize the results.
1903 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1904 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1905 if (!Lo)
1906 Lo = Hi;
1907 else if (!Hi)
1908 Hi = Lo;
1909
1910 V1 = Lo;
1911 V2 = Hi;
1912
1913 return Rotation * Scale;
1914}
1915
1916/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
1917///
1918/// For example:
1919/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
1920/// <2 x i32> <i32 3, i32 0>
1921/// is lowered to:
1922/// (VBSRL_V $v1, $v1, 8)
1923/// (VBSLL_V $v0, $v0, 8)
1924/// (VOR_V $v0, $V0, $v1)
1925static SDValue
1927 SDValue V1, SDValue V2, SelectionDAG &DAG,
1928 const LoongArchSubtarget &Subtarget) {
1929
1930 SDValue Lo = V1, Hi = V2;
1931 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
1932 if (ByteRotation <= 0)
1933 return SDValue();
1934
1935 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
1936 Lo = DAG.getBitcast(ByteVT, Lo);
1937 Hi = DAG.getBitcast(ByteVT, Hi);
1938
1939 int LoByteShift = 16 - ByteRotation;
1940 int HiByteShift = ByteRotation;
1941 MVT GRLenVT = Subtarget.getGRLenVT();
1942
1943 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
1944 DAG.getConstant(LoByteShift, DL, GRLenVT));
1945 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
1946 DAG.getConstant(HiByteShift, DL, GRLenVT));
1947 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
1948}
1949
1950/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
1951///
1952/// For example:
1953/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1954/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
1955/// %3 = bitcast <4 x i32> %2 to <2 x i64>
1956/// is lowered to:
1957/// (VREPLI $v1, 0)
1958/// (VILVL $v0, $v1, $v0)
1960 ArrayRef<int> Mask, MVT VT,
1961 SDValue V1, SDValue V2,
1962 SelectionDAG &DAG,
1963 const APInt &Zeroable) {
1964 int Bits = VT.getSizeInBits();
1965 int EltBits = VT.getScalarSizeInBits();
1966 int NumElements = VT.getVectorNumElements();
1967
1968 if (Zeroable.isAllOnes())
1969 return DAG.getConstant(0, DL, VT);
1970
1971 // Define a helper function to check a particular ext-scale and lower to it if
1972 // valid.
1973 auto Lower = [&](int Scale) -> SDValue {
1974 SDValue InputV;
1975 bool AnyExt = true;
1976 int Offset = 0;
1977 for (int i = 0; i < NumElements; i++) {
1978 int M = Mask[i];
1979 if (M < 0)
1980 continue;
1981 if (i % Scale != 0) {
1982 // Each of the extended elements need to be zeroable.
1983 if (!Zeroable[i])
1984 return SDValue();
1985
1986 AnyExt = false;
1987 continue;
1988 }
1989
1990 // Each of the base elements needs to be consecutive indices into the
1991 // same input vector.
1992 SDValue V = M < NumElements ? V1 : V2;
1993 M = M % NumElements;
1994 if (!InputV) {
1995 InputV = V;
1996 Offset = M - (i / Scale);
1997
1998 // These offset can't be handled
1999 if (Offset % (NumElements / Scale))
2000 return SDValue();
2001 } else if (InputV != V)
2002 return SDValue();
2003
2004 if (M != (Offset + (i / Scale)))
2005 return SDValue(); // Non-consecutive strided elements.
2006 }
2007
2008 // If we fail to find an input, we have a zero-shuffle which should always
2009 // have already been handled.
2010 if (!InputV)
2011 return SDValue();
2012
2013 do {
2014 unsigned VilVLoHi = LoongArchISD::VILVL;
2015 if (Offset >= (NumElements / 2)) {
2016 VilVLoHi = LoongArchISD::VILVH;
2017 Offset -= (NumElements / 2);
2018 }
2019
2020 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2021 SDValue Ext =
2022 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2023 InputV = DAG.getBitcast(InputVT, InputV);
2024 Ext = DAG.getBitcast(InputVT, Ext);
2025 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2026 Scale /= 2;
2027 EltBits *= 2;
2028 NumElements /= 2;
2029 } while (Scale > 1);
2030 return DAG.getBitcast(VT, InputV);
2031 };
2032
2033 // Each iteration, try extending the elements half as much, but into twice as
2034 // many elements.
2035 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2036 NumExtElements *= 2) {
2037 if (SDValue V = Lower(NumElements / NumExtElements))
2038 return V;
2039 }
2040 return SDValue();
2041}
2042
2043/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2044///
2045/// VREPLVEI performs vector broadcast based on an element specified by an
2046/// integer immediate, with its mask being similar to:
2047/// <x, x, x, ...>
2048/// where x is any valid index.
2049///
2050/// When undef's appear in the mask they are treated as if they were whatever
2051/// value is necessary in order to fit the above form.
2052static SDValue
2054 SDValue V1, SelectionDAG &DAG,
2055 const LoongArchSubtarget &Subtarget) {
2056 int SplatIndex = -1;
2057 for (const auto &M : Mask) {
2058 if (M != -1) {
2059 SplatIndex = M;
2060 break;
2061 }
2062 }
2063
2064 if (SplatIndex == -1)
2065 return DAG.getUNDEF(VT);
2066
2067 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2068 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2069 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2070 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2071 }
2072
2073 return SDValue();
2074}
2075
2076/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2077///
2078/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2079/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2080///
2081/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2082/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2083/// When undef's appear they are treated as if they were whatever value is
2084/// necessary in order to fit the above forms.
2085///
2086/// For example:
2087/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2088/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2089/// i32 7, i32 6, i32 5, i32 4>
2090/// is lowered to:
2091/// (VSHUF4I_H $v0, $v1, 27)
2092/// where the 27 comes from:
2093/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2094static SDValue
2096 SDValue V1, SDValue V2, SelectionDAG &DAG,
2097 const LoongArchSubtarget &Subtarget) {
2098
2099 unsigned SubVecSize = 4;
2100 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2101 SubVecSize = 2;
2102
2103 int SubMask[4] = {-1, -1, -1, -1};
2104 for (unsigned i = 0; i < SubVecSize; ++i) {
2105 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2106 int M = Mask[j];
2107
2108 // Convert from vector index to 4-element subvector index
2109 // If an index refers to an element outside of the subvector then give up
2110 if (M != -1) {
2111 M -= 4 * (j / SubVecSize);
2112 if (M < 0 || M >= 4)
2113 return SDValue();
2114 }
2115
2116 // If the mask has an undef, replace it with the current index.
2117 // Note that it might still be undef if the current index is also undef
2118 if (SubMask[i] == -1)
2119 SubMask[i] = M;
2120 // Check that non-undef values are the same as in the mask. If they
2121 // aren't then give up
2122 else if (M != -1 && M != SubMask[i])
2123 return SDValue();
2124 }
2125 }
2126
2127 // Calculate the immediate. Replace any remaining undefs with zero
2128 int Imm = 0;
2129 for (int i = SubVecSize - 1; i >= 0; --i) {
2130 int M = SubMask[i];
2131
2132 if (M == -1)
2133 M = 0;
2134
2135 Imm <<= 2;
2136 Imm |= M & 0x3;
2137 }
2138
2139 MVT GRLenVT = Subtarget.getGRLenVT();
2140
2141 // Return vshuf4i.d
2142 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2143 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2144 DAG.getConstant(Imm, DL, GRLenVT));
2145
2146 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2147 DAG.getConstant(Imm, DL, GRLenVT));
2148}
2149
2150/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2151///
2152/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2153/// reverse whose mask likes:
2154/// <7, 6, 5, 4, 3, 2, 1, 0>
2155///
2156/// When undef's appear in the mask they are treated as if they were whatever
2157/// value is necessary in order to fit the above forms.
2158static SDValue
2160 SDValue V1, SelectionDAG &DAG,
2161 const LoongArchSubtarget &Subtarget) {
2162 // Only vectors with i8/i16 elements which cannot match other patterns
2163 // directly needs to do this.
2164 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2165 VT != MVT::v16i16)
2166 return SDValue();
2167
2168 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2169 return SDValue();
2170
2171 int WidenNumElts = VT.getVectorNumElements() / 4;
2172 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2173 for (int i = 0; i < WidenNumElts; ++i)
2174 WidenMask[i] = WidenNumElts - 1 - i;
2175
2176 MVT WidenVT = MVT::getVectorVT(
2177 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2178 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2179 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2180 DAG.getUNDEF(WidenVT), WidenMask);
2181
2182 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2183 DAG.getBitcast(VT, WidenRev),
2184 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2185}
2186
2187/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2188///
2189/// VPACKEV interleaves the even elements from each vector.
2190///
2191/// It is possible to lower into VPACKEV when the mask consists of two of the
2192/// following forms interleaved:
2193/// <0, 2, 4, ...>
2194/// <n, n+2, n+4, ...>
2195/// where n is the number of elements in the vector.
2196/// For example:
2197/// <0, 0, 2, 2, 4, 4, ...>
2198/// <0, n, 2, n+2, 4, n+4, ...>
2199///
2200/// When undef's appear in the mask they are treated as if they were whatever
2201/// value is necessary in order to fit the above forms.
2203 MVT VT, SDValue V1, SDValue V2,
2204 SelectionDAG &DAG) {
2205
2206 const auto &Begin = Mask.begin();
2207 const auto &End = Mask.end();
2208 SDValue OriV1 = V1, OriV2 = V2;
2209
2210 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2211 V1 = OriV1;
2212 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2213 V1 = OriV2;
2214 else
2215 return SDValue();
2216
2217 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2218 V2 = OriV1;
2219 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2220 V2 = OriV2;
2221 else
2222 return SDValue();
2223
2224 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2225}
2226
2227/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2228///
2229/// VPACKOD interleaves the odd elements from each vector.
2230///
2231/// It is possible to lower into VPACKOD when the mask consists of two of the
2232/// following forms interleaved:
2233/// <1, 3, 5, ...>
2234/// <n+1, n+3, n+5, ...>
2235/// where n is the number of elements in the vector.
2236/// For example:
2237/// <1, 1, 3, 3, 5, 5, ...>
2238/// <1, n+1, 3, n+3, 5, n+5, ...>
2239///
2240/// When undef's appear in the mask they are treated as if they were whatever
2241/// value is necessary in order to fit the above forms.
2243 MVT VT, SDValue V1, SDValue V2,
2244 SelectionDAG &DAG) {
2245
2246 const auto &Begin = Mask.begin();
2247 const auto &End = Mask.end();
2248 SDValue OriV1 = V1, OriV2 = V2;
2249
2250 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2251 V1 = OriV1;
2252 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2253 V1 = OriV2;
2254 else
2255 return SDValue();
2256
2257 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2258 V2 = OriV1;
2259 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2260 V2 = OriV2;
2261 else
2262 return SDValue();
2263
2264 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2265}
2266
2267/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2268///
2269/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2270/// of each vector.
2271///
2272/// It is possible to lower into VILVH when the mask consists of two of the
2273/// following forms interleaved:
2274/// <x, x+1, x+2, ...>
2275/// <n+x, n+x+1, n+x+2, ...>
2276/// where n is the number of elements in the vector and x is half n.
2277/// For example:
2278/// <x, x, x+1, x+1, x+2, x+2, ...>
2279/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2280///
2281/// When undef's appear in the mask they are treated as if they were whatever
2282/// value is necessary in order to fit the above forms.
2284 MVT VT, SDValue V1, SDValue V2,
2285 SelectionDAG &DAG) {
2286
2287 const auto &Begin = Mask.begin();
2288 const auto &End = Mask.end();
2289 unsigned HalfSize = Mask.size() / 2;
2290 SDValue OriV1 = V1, OriV2 = V2;
2291
2292 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2293 V1 = OriV1;
2294 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2295 V1 = OriV2;
2296 else
2297 return SDValue();
2298
2299 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2300 V2 = OriV1;
2301 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2302 1))
2303 V2 = OriV2;
2304 else
2305 return SDValue();
2306
2307 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2308}
2309
2310/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2311///
2312/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2313/// of each vector.
2314///
2315/// It is possible to lower into VILVL when the mask consists of two of the
2316/// following forms interleaved:
2317/// <0, 1, 2, ...>
2318/// <n, n+1, n+2, ...>
2319/// where n is the number of elements in the vector.
2320/// For example:
2321/// <0, 0, 1, 1, 2, 2, ...>
2322/// <0, n, 1, n+1, 2, n+2, ...>
2323///
2324/// When undef's appear in the mask they are treated as if they were whatever
2325/// value is necessary in order to fit the above forms.
2327 MVT VT, SDValue V1, SDValue V2,
2328 SelectionDAG &DAG) {
2329
2330 const auto &Begin = Mask.begin();
2331 const auto &End = Mask.end();
2332 SDValue OriV1 = V1, OriV2 = V2;
2333
2334 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2335 V1 = OriV1;
2336 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2337 V1 = OriV2;
2338 else
2339 return SDValue();
2340
2341 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2342 V2 = OriV1;
2343 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2344 V2 = OriV2;
2345 else
2346 return SDValue();
2347
2348 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2349}
2350
2351/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2352///
2353/// VPICKEV copies the even elements of each vector into the result vector.
2354///
2355/// It is possible to lower into VPICKEV when the mask consists of two of the
2356/// following forms concatenated:
2357/// <0, 2, 4, ...>
2358/// <n, n+2, n+4, ...>
2359/// where n is the number of elements in the vector.
2360/// For example:
2361/// <0, 2, 4, ..., 0, 2, 4, ...>
2362/// <0, 2, 4, ..., n, n+2, n+4, ...>
2363///
2364/// When undef's appear in the mask they are treated as if they were whatever
2365/// value is necessary in order to fit the above forms.
2367 MVT VT, SDValue V1, SDValue V2,
2368 SelectionDAG &DAG) {
2369
2370 const auto &Begin = Mask.begin();
2371 const auto &Mid = Mask.begin() + Mask.size() / 2;
2372 const auto &End = Mask.end();
2373 SDValue OriV1 = V1, OriV2 = V2;
2374
2375 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2376 V1 = OriV1;
2377 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2378 V1 = OriV2;
2379 else
2380 return SDValue();
2381
2382 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2383 V2 = OriV1;
2384 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2385 V2 = OriV2;
2386
2387 else
2388 return SDValue();
2389
2390 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2391}
2392
2393/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2394///
2395/// VPICKOD copies the odd elements of each vector into the result vector.
2396///
2397/// It is possible to lower into VPICKOD when the mask consists of two of the
2398/// following forms concatenated:
2399/// <1, 3, 5, ...>
2400/// <n+1, n+3, n+5, ...>
2401/// where n is the number of elements in the vector.
2402/// For example:
2403/// <1, 3, 5, ..., 1, 3, 5, ...>
2404/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2405///
2406/// When undef's appear in the mask they are treated as if they were whatever
2407/// value is necessary in order to fit the above forms.
2409 MVT VT, SDValue V1, SDValue V2,
2410 SelectionDAG &DAG) {
2411
2412 const auto &Begin = Mask.begin();
2413 const auto &Mid = Mask.begin() + Mask.size() / 2;
2414 const auto &End = Mask.end();
2415 SDValue OriV1 = V1, OriV2 = V2;
2416
2417 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2418 V1 = OriV1;
2419 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2420 V1 = OriV2;
2421 else
2422 return SDValue();
2423
2424 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2425 V2 = OriV1;
2426 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2427 V2 = OriV2;
2428 else
2429 return SDValue();
2430
2431 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2432}
2433
2434/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2435///
2436/// VEXTRINS copies one element of a vector into any place of the result
2437/// vector and makes no change to the rest elements of the result vector.
2438///
2439/// It is possible to lower into VEXTRINS when the mask takes the form:
2440/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2441/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2442/// where n is the number of elements in the vector and i is in [0, n).
2443/// For example:
2444/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2445/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2446///
2447/// When undef's appear in the mask they are treated as if they were whatever
2448/// value is necessary in order to fit the above forms.
2449static SDValue
2451 SDValue V1, SDValue V2, SelectionDAG &DAG,
2452 const LoongArchSubtarget &Subtarget) {
2453 unsigned NumElts = VT.getVectorNumElements();
2454 MVT EltVT = VT.getVectorElementType();
2455 MVT GRLenVT = Subtarget.getGRLenVT();
2456
2457 if (Mask.size() != NumElts)
2458 return SDValue();
2459
2460 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2461 int DiffCount = 0;
2462 int DiffPos = -1;
2463 for (unsigned i = 0; i < NumElts; ++i) {
2464 if (Mask[i] == -1)
2465 continue;
2466 if (Mask[i] != int(Base + i)) {
2467 ++DiffCount;
2468 DiffPos = int(i);
2469 if (DiffCount > 1)
2470 return SDValue();
2471 }
2472 }
2473
2474 // Need exactly one differing element to lower into VEXTRINS.
2475 if (DiffCount != 1)
2476 return SDValue();
2477
2478 // DiffMask must be in [0, 2N).
2479 int DiffMask = Mask[DiffPos];
2480 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2481 return SDValue();
2482
2483 // Determine source vector and source index.
2484 SDValue SrcVec;
2485 unsigned SrcIdx;
2486 if (unsigned(DiffMask) < NumElts) {
2487 SrcVec = V1;
2488 SrcIdx = unsigned(DiffMask);
2489 } else {
2490 SrcVec = V2;
2491 SrcIdx = unsigned(DiffMask) - NumElts;
2492 }
2493
2494 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2495 // patterns of VEXTRINS in tablegen.
2496 SDValue Extracted = DAG.getNode(
2497 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2498 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2499 SDValue Result =
2500 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2501 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2502
2503 return Result;
2504 };
2505
2506 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2507 if (SDValue Result = tryLowerToExtrAndIns(0))
2508 return Result;
2509 return tryLowerToExtrAndIns(NumElts);
2510}
2511
2512// Check the Mask and then build SrcVec and MaskImm infos which will
2513// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2514// On success, return true. Otherwise, return false.
2517 unsigned &MaskImm) {
2518 unsigned MaskSize = Mask.size();
2519
2520 auto isValid = [&](int M, int Off) {
2521 return (M == -1) || (M >= Off && M < Off + 4);
2522 };
2523
2524 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2525 auto immPart = [&](int M, unsigned Off) {
2526 return (M == -1 ? 0 : (M - Off)) & 0x3;
2527 };
2528 MaskImm |= immPart(MLo, Off) << (I * 2);
2529 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2530 };
2531
2532 for (unsigned i = 0; i < 4; i += 2) {
2533 int MLo = Mask[i];
2534 int MHi = Mask[i + 1];
2535
2536 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2537 auto isValid2 = [&](int &M, int M2) {
2538 // If high half index is undef, it's always valid.
2539 if (M2 == -1)
2540 return true;
2541 if (M == -1) {
2542 // If low half index is undef, use index from high half,
2543 // remapped to low half.
2544 if ((M2 % MaskSize) < 4)
2545 return false;
2546 M = M2 - 4;
2547 return true;
2548 }
2549 // Index in low half must be same as index in high half.
2550 return M2 == M + 4;
2551 };
2552 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2553 return false;
2554 }
2555
2556 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2557 SrcVec.push_back(V1);
2558 buildImm(MLo, MHi, 0, i);
2559 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2560 SrcVec.push_back(V2);
2561 buildImm(MLo, MHi, MaskSize, i);
2562 } else {
2563 return false;
2564 }
2565 }
2566
2567 return true;
2568}
2569
2570/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2571///
2572/// VPERMI selects two elements from each of the two vectors based on the
2573/// mask and places them in the corresponding positions of the result vector
2574/// in order. Only v4i32 and v4f32 types are allowed.
2575///
2576/// It is possible to lower into VPERMI when the mask consists of two of the
2577/// following forms concatenated:
2578/// <i, j, u, v>
2579/// <u, v, i, j>
2580/// where i,j are in [0,4) and u,v are in [4, 8).
2581/// For example:
2582/// <2, 3, 4, 5>
2583/// <5, 7, 0, 2>
2584///
2585/// When undef's appear in the mask they are treated as if they were whatever
2586/// value is necessary in order to fit the above forms.
2588 MVT VT, SDValue V1, SDValue V2,
2589 SelectionDAG &DAG,
2590 const LoongArchSubtarget &Subtarget) {
2591 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2592 Mask.size() != VT.getVectorNumElements())
2593 return SDValue();
2594
2596 unsigned MaskImm = 0;
2597 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2598 return SDValue();
2599
2600 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2601 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2602}
2603
2604/// Lower VECTOR_SHUFFLE into VSHUF.
2605///
2606/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2607/// adding it as an operand to the resulting VSHUF.
2609 MVT VT, SDValue V1, SDValue V2,
2610 SelectionDAG &DAG,
2611 const LoongArchSubtarget &Subtarget) {
2612
2614 for (auto M : Mask)
2615 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2616
2617 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2618 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2619
2620 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2621 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2622 // VSHF concatenates the vectors in a bitwise fashion:
2623 // <0b00, 0b01> + <0b10, 0b11> ->
2624 // 0b0100 + 0b1110 -> 0b01001110
2625 // <0b10, 0b11, 0b00, 0b01>
2626 // We must therefore swap the operands to get the correct result.
2627 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2628}
2629
2630/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2631///
2632/// This routine breaks down the specific type of 128-bit shuffle and
2633/// dispatches to the lowering routines accordingly.
2635 SDValue V1, SDValue V2, SelectionDAG &DAG,
2636 const LoongArchSubtarget &Subtarget) {
2637 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2638 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2639 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2640 "Vector type is unsupported for lsx!");
2641 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2642 "Two operands have different types!");
2643 assert(VT.getVectorNumElements() == Mask.size() &&
2644 "Unexpected mask size for shuffle!");
2645 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2646
2647 APInt KnownUndef, KnownZero;
2648 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2649 APInt Zeroable = KnownUndef | KnownZero;
2650
2651 SDValue Result;
2652 // TODO: Add more comparison patterns.
2653 if (V2.isUndef()) {
2654 if ((Result =
2655 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2656 return Result;
2657 if ((Result =
2658 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2659 return Result;
2660 if ((Result =
2661 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2662 return Result;
2663
2664 // TODO: This comment may be enabled in the future to better match the
2665 // pattern for instruction selection.
2666 /* V2 = V1; */
2667 }
2668
2669 // It is recommended not to change the pattern comparison order for better
2670 // performance.
2671 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2672 return Result;
2673 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2674 return Result;
2675 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2676 return Result;
2677 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2678 return Result;
2679 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2680 return Result;
2681 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2682 return Result;
2683 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2684 (Result =
2685 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2686 return Result;
2687 if ((Result =
2688 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2689 return Result;
2690 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2691 Zeroable)))
2692 return Result;
2693 if ((Result =
2694 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2695 return Result;
2696 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2697 Zeroable)))
2698 return Result;
2699 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2700 Subtarget)))
2701 return Result;
2702 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2703 return NewShuffle;
2704 if ((Result =
2705 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2706 return Result;
2707 return SDValue();
2708}
2709
2710/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2711///
2712/// It is a XVREPLVEI when the mask is:
2713/// <x, x, x, ..., x+n, x+n, x+n, ...>
2714/// where the number of x is equal to n and n is half the length of vector.
2715///
2716/// When undef's appear in the mask they are treated as if they were whatever
2717/// value is necessary in order to fit the above form.
2718static SDValue
2720 SDValue V1, SelectionDAG &DAG,
2721 const LoongArchSubtarget &Subtarget) {
2722 int SplatIndex = -1;
2723 for (const auto &M : Mask) {
2724 if (M != -1) {
2725 SplatIndex = M;
2726 break;
2727 }
2728 }
2729
2730 if (SplatIndex == -1)
2731 return DAG.getUNDEF(VT);
2732
2733 const auto &Begin = Mask.begin();
2734 const auto &End = Mask.end();
2735 int HalfSize = Mask.size() / 2;
2736
2737 if (SplatIndex >= HalfSize)
2738 return SDValue();
2739
2740 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2741 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2742 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2743 0)) {
2744 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2745 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2746 }
2747
2748 return SDValue();
2749}
2750
2751/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2752static SDValue
2754 SDValue V1, SDValue V2, SelectionDAG &DAG,
2755 const LoongArchSubtarget &Subtarget) {
2756 // XVSHUF4I_D must be handled separately because it is different from other
2757 // types of [X]VSHUF4I instructions.
2758 if (Mask.size() == 4) {
2759 unsigned MaskImm = 0;
2760 for (int i = 1; i >= 0; --i) {
2761 int MLo = Mask[i];
2762 int MHi = Mask[i + 2];
2763 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2764 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2765 return SDValue();
2766 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2767 return SDValue();
2768
2769 MaskImm <<= 2;
2770 if (MLo != -1)
2771 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2772 else if (MHi != -1)
2773 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2774 }
2775
2776 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2777 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2778 }
2779
2780 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2781}
2782
2783/// Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
2784///
2785/// It is a XVREPLVE0 when the VECTOR_SHUFFLE is a broadcast of element 0,
2786/// i.e. the mask is:
2787/// <0, 0, 0, ...>
2788///
2789/// When undef's appear in the mask they are treated as if they were whatever
2790/// value is necessary in order to fit the above form.
2792 ArrayRef<int> Mask, MVT VT,
2793 SDValue V1, SelectionDAG &DAG) {
2794 if (!ShuffleVectorInst::isZeroEltSplatMask(Mask, Mask.size()))
2795 return SDValue();
2796
2797 return DAG.getNode(LoongArchISD::XVREPLVE0, DL, VT, V1);
2798}
2799
2800/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2801static SDValue
2803 SDValue V1, SDValue V2, SelectionDAG &DAG,
2804 const LoongArchSubtarget &Subtarget) {
2805 MVT GRLenVT = Subtarget.getGRLenVT();
2806 unsigned MaskSize = Mask.size();
2807 if (MaskSize != VT.getVectorNumElements())
2808 return SDValue();
2809
2810 // Consider XVPERMI_W.
2811 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2813 unsigned MaskImm = 0;
2814 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2815 return SDValue();
2816
2817 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2818 DAG.getConstant(MaskImm, DL, GRLenVT));
2819 }
2820
2821 // Consider XVPERMI_D.
2822 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2823 unsigned MaskImm = 0;
2824 for (unsigned i = 0; i < MaskSize; ++i) {
2825 if (Mask[i] == -1)
2826 continue;
2827 if (Mask[i] >= (int)MaskSize)
2828 return SDValue();
2829 MaskImm |= Mask[i] << (i * 2);
2830 }
2831
2832 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2833 DAG.getConstant(MaskImm, DL, GRLenVT));
2834 }
2835
2836 return SDValue();
2837}
2838
2839/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2841 MVT VT, SDValue V1, SelectionDAG &DAG,
2842 const LoongArchSubtarget &Subtarget) {
2843 // LoongArch LASX only have XVPERM_W.
2844 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2845 return SDValue();
2846
2847 unsigned NumElts = VT.getVectorNumElements();
2848 unsigned HalfSize = NumElts / 2;
2849 bool FrontLo = true, FrontHi = true;
2850 bool BackLo = true, BackHi = true;
2851
2852 auto inRange = [](int val, int low, int high) {
2853 return (val == -1) || (val >= low && val < high);
2854 };
2855
2856 for (unsigned i = 0; i < HalfSize; ++i) {
2857 int Fronti = Mask[i];
2858 int Backi = Mask[i + HalfSize];
2859
2860 FrontLo &= inRange(Fronti, 0, HalfSize);
2861 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2862 BackLo &= inRange(Backi, 0, HalfSize);
2863 BackHi &= inRange(Backi, HalfSize, NumElts);
2864 }
2865
2866 // If both the lower and upper 128-bit parts access only one half of the
2867 // vector (either lower or upper), avoid using xvperm.w. The latency of
2868 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2869 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2870 return SDValue();
2871
2873 MVT GRLenVT = Subtarget.getGRLenVT();
2874 for (unsigned i = 0; i < NumElts; ++i)
2875 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2876 : DAG.getConstant(Mask[i], DL, GRLenVT));
2877 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2878
2879 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2880}
2881
2882/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2884 MVT VT, SDValue V1, SDValue V2,
2885 SelectionDAG &DAG) {
2886 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2887}
2888
2889/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2891 MVT VT, SDValue V1, SDValue V2,
2892 SelectionDAG &DAG) {
2893 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2894}
2895
2896/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2898 MVT VT, SDValue V1, SDValue V2,
2899 SelectionDAG &DAG) {
2900
2901 const auto &Begin = Mask.begin();
2902 const auto &End = Mask.end();
2903 unsigned HalfSize = Mask.size() / 2;
2904 unsigned LeftSize = HalfSize / 2;
2905 SDValue OriV1 = V1, OriV2 = V2;
2906
2907 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2908 1) &&
2909 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2910 V1 = OriV1;
2911 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2912 Mask.size() + HalfSize - LeftSize, 1) &&
2913 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2914 Mask.size() + HalfSize + LeftSize, 1))
2915 V1 = OriV2;
2916 else
2917 return SDValue();
2918
2919 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
2920 1) &&
2921 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
2922 1))
2923 V2 = OriV1;
2924 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
2925 Mask.size() + HalfSize - LeftSize, 1) &&
2926 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2927 Mask.size() + HalfSize + LeftSize, 1))
2928 V2 = OriV2;
2929 else
2930 return SDValue();
2931
2932 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2933}
2934
2935/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
2937 MVT VT, SDValue V1, SDValue V2,
2938 SelectionDAG &DAG) {
2939
2940 const auto &Begin = Mask.begin();
2941 const auto &End = Mask.end();
2942 unsigned HalfSize = Mask.size() / 2;
2943 SDValue OriV1 = V1, OriV2 = V2;
2944
2945 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
2946 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
2947 V1 = OriV1;
2948 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
2949 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2950 Mask.size() + HalfSize, 1))
2951 V1 = OriV2;
2952 else
2953 return SDValue();
2954
2955 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
2956 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
2957 V2 = OriV1;
2958 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
2959 1) &&
2960 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2961 Mask.size() + HalfSize, 1))
2962 V2 = OriV2;
2963 else
2964 return SDValue();
2965
2966 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2967}
2968
2969/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
2971 MVT VT, SDValue V1, SDValue V2,
2972 SelectionDAG &DAG) {
2973
2974 const auto &Begin = Mask.begin();
2975 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
2976 const auto &Mid = Mask.begin() + Mask.size() / 2;
2977 const auto &RightMid = Mask.end() - Mask.size() / 4;
2978 const auto &End = Mask.end();
2979 unsigned HalfSize = Mask.size() / 2;
2980 SDValue OriV1 = V1, OriV2 = V2;
2981
2982 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
2983 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
2984 V1 = OriV1;
2985 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
2986 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
2987 V1 = OriV2;
2988 else
2989 return SDValue();
2990
2991 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
2992 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
2993 V2 = OriV1;
2994 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
2995 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
2996 V2 = OriV2;
2997
2998 else
2999 return SDValue();
3000
3001 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
3002}
3003
3004/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
3006 MVT VT, SDValue V1, SDValue V2,
3007 SelectionDAG &DAG) {
3008
3009 const auto &Begin = Mask.begin();
3010 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3011 const auto &Mid = Mask.begin() + Mask.size() / 2;
3012 const auto &RightMid = Mask.end() - Mask.size() / 4;
3013 const auto &End = Mask.end();
3014 unsigned HalfSize = Mask.size() / 2;
3015 SDValue OriV1 = V1, OriV2 = V2;
3016
3017 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
3018 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
3019 V1 = OriV1;
3020 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3021 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3022 2))
3023 V1 = OriV2;
3024 else
3025 return SDValue();
3026
3027 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3028 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3029 V2 = OriV1;
3030 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3031 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3032 2))
3033 V2 = OriV2;
3034 else
3035 return SDValue();
3036
3037 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3038}
3039
3040/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3041static SDValue
3043 SDValue V1, SDValue V2, SelectionDAG &DAG,
3044 const LoongArchSubtarget &Subtarget) {
3045 int NumElts = VT.getVectorNumElements();
3046 int HalfSize = NumElts / 2;
3047 MVT EltVT = VT.getVectorElementType();
3048 MVT GRLenVT = Subtarget.getGRLenVT();
3049
3050 if ((int)Mask.size() != NumElts)
3051 return SDValue();
3052
3053 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3054 SmallVector<int> DiffPos;
3055 for (int i = 0; i < NumElts; ++i) {
3056 if (Mask[i] == -1)
3057 continue;
3058 if (Mask[i] != Base + i) {
3059 DiffPos.push_back(i);
3060 if (DiffPos.size() > 2)
3061 return SDValue();
3062 }
3063 }
3064
3065 // Need exactly two differing element to lower into XVEXTRINS.
3066 // If only one differing element, the element at a distance of
3067 // HalfSize from it must be undef.
3068 if (DiffPos.size() == 1) {
3069 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3070 DiffPos.push_back(DiffPos[0] + HalfSize);
3071 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3072 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3073 else
3074 return SDValue();
3075 }
3076 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3077 return SDValue();
3078
3079 // DiffMask must be in its low or high part.
3080 int DiffMaskLo = Mask[DiffPos[0]];
3081 int DiffMaskHi = Mask[DiffPos[1]];
3082 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3083 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3084 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3085 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3086 return SDValue();
3087 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3088 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3089 return SDValue();
3090 if (DiffMaskHi != DiffMaskLo + HalfSize)
3091 return SDValue();
3092
3093 // Determine source vector and source index.
3094 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3095 int SrcIdxLo =
3096 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3097 bool IsEltFP = EltVT.isFloatingPoint();
3098
3099 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3100 // the patterns of XVEXTRINS in tablegen.
3101 SDValue BaseVec = (Base == 0) ? V1 : V2;
3102 SDValue EltLo =
3103 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3104 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3105 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3106 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3107 SDValue EltHi =
3108 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3109 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3110 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3111 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3112
3113 return Result;
3114 };
3115
3116 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3117 if (SDValue Result = tryLowerToExtrAndIns(0))
3118 return Result;
3119 return tryLowerToExtrAndIns(NumElts);
3120}
3121
3122/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3123static SDValue
3125 SDValue V1, SDValue V2, SelectionDAG &DAG,
3126 const LoongArchSubtarget &Subtarget) {
3127 // LoongArch LASX only supports xvinsve0.{w/d}.
3128 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3129 VT != MVT::v4f64)
3130 return SDValue();
3131
3132 MVT GRLenVT = Subtarget.getGRLenVT();
3133 int MaskSize = Mask.size();
3134 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3135
3136 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3137 // all other elements are either 'Base + i' or undef (-1). On success, return
3138 // the index of the replaced element. Otherwise, just return -1.
3139 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3140 int Idx = -1;
3141 for (int i = 0; i < MaskSize; ++i) {
3142 if (Mask[i] == Base + i || Mask[i] == -1)
3143 continue;
3144 if (Mask[i] != Replaced)
3145 return -1;
3146 if (Idx == -1)
3147 Idx = i;
3148 else
3149 return -1;
3150 }
3151 return Idx;
3152 };
3153
3154 // Case 1: the lowest element of V2 replaces one element in V1.
3155 int Idx = checkReplaceOne(0, MaskSize);
3156 if (Idx != -1)
3157 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3158 DAG.getConstant(Idx, DL, GRLenVT));
3159
3160 // Case 2: the lowest element of V1 replaces one element in V2.
3161 Idx = checkReplaceOne(MaskSize, 0);
3162 if (Idx != -1)
3163 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3164 DAG.getConstant(Idx, DL, GRLenVT));
3165
3166 return SDValue();
3167}
3168
3169/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3171 MVT VT, SDValue V1, SDValue V2,
3172 SelectionDAG &DAG) {
3173
3174 int MaskSize = Mask.size();
3175 int HalfSize = Mask.size() / 2;
3176 const auto &Begin = Mask.begin();
3177 const auto &Mid = Mask.begin() + HalfSize;
3178 const auto &End = Mask.end();
3179
3180 // VECTOR_SHUFFLE concatenates the vectors:
3181 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3182 // shuffling ->
3183 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3184 //
3185 // XVSHUF concatenates the vectors:
3186 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3187 // shuffling ->
3188 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3189 SmallVector<SDValue, 8> MaskAlloc;
3190 for (auto it = Begin; it < Mid; it++) {
3191 if (*it < 0) // UNDEF
3192 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3193 else if ((*it >= 0 && *it < HalfSize) ||
3194 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3195 int M = *it < HalfSize ? *it : *it - HalfSize;
3196 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3197 } else
3198 return SDValue();
3199 }
3200 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3201
3202 for (auto it = Mid; it < End; it++) {
3203 if (*it < 0) // UNDEF
3204 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3205 else if ((*it >= HalfSize && *it < MaskSize) ||
3206 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3207 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3208 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3209 } else
3210 return SDValue();
3211 }
3212 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3213
3214 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3215 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3216 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3217}
3218
3219/// Shuffle vectors by lane to generate more optimized instructions.
3220/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3221///
3222/// Therefore, except for the following four cases, other cases are regarded
3223/// as cross-lane shuffles, where optimization is relatively limited.
3224///
3225/// - Shuffle high, low lanes of two inputs vector
3226/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3227/// - Shuffle low, high lanes of two inputs vector
3228/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3229/// - Shuffle low, low lanes of two inputs vector
3230/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3231/// - Shuffle high, high lanes of two inputs vector
3232/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3233///
3234/// The first case is the closest to LoongArch instructions and the other
3235/// cases need to be converted to it for processing.
3236///
3237/// This function will return true for the last three cases above and will
3238/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3239/// cross-lane shuffle cases.
3241 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3242 SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
3243
3244 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3245
3246 int MaskSize = Mask.size();
3247 int HalfSize = Mask.size() / 2;
3248 MVT GRLenVT = Subtarget.getGRLenVT();
3249
3250 HalfMaskType preMask = None, postMask = None;
3251
3252 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3253 return M < 0 || (M >= 0 && M < HalfSize) ||
3254 (M >= MaskSize && M < MaskSize + HalfSize);
3255 }))
3256 preMask = HighLaneTy;
3257 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3258 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3259 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3260 }))
3261 preMask = LowLaneTy;
3262
3263 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3264 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3265 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3266 }))
3267 postMask = LowLaneTy;
3268 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3269 return M < 0 || (M >= 0 && M < HalfSize) ||
3270 (M >= MaskSize && M < MaskSize + HalfSize);
3271 }))
3272 postMask = HighLaneTy;
3273
3274 // The pre-half of mask is high lane type, and the post-half of mask
3275 // is low lane type, which is closest to the LoongArch instructions.
3276 //
3277 // Note: In the LoongArch architecture, the high lane of mask corresponds
3278 // to the lower 128-bit of vector register, and the low lane of mask
3279 // corresponds the higher 128-bit of vector register.
3280 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3281 return false;
3282 }
3283 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3284 V1 = DAG.getBitcast(MVT::v4i64, V1);
3285 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3286 DAG.getConstant(0b01001110, DL, GRLenVT));
3287 V1 = DAG.getBitcast(VT, V1);
3288
3289 if (!V2.isUndef()) {
3290 V2 = DAG.getBitcast(MVT::v4i64, V2);
3291 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3292 DAG.getConstant(0b01001110, DL, GRLenVT));
3293 V2 = DAG.getBitcast(VT, V2);
3294 }
3295
3296 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3297 *it = *it < 0 ? *it : *it - HalfSize;
3298 }
3299 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3300 *it = *it < 0 ? *it : *it + HalfSize;
3301 }
3302 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3303 V1 = DAG.getBitcast(MVT::v4i64, V1);
3304 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3305 DAG.getConstant(0b11101110, DL, GRLenVT));
3306 V1 = DAG.getBitcast(VT, V1);
3307
3308 if (!V2.isUndef()) {
3309 V2 = DAG.getBitcast(MVT::v4i64, V2);
3310 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3311 DAG.getConstant(0b11101110, DL, GRLenVT));
3312 V2 = DAG.getBitcast(VT, V2);
3313 }
3314
3315 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3316 *it = *it < 0 ? *it : *it - HalfSize;
3317 }
3318 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3319 V1 = DAG.getBitcast(MVT::v4i64, V1);
3320 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3321 DAG.getConstant(0b01000100, 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(0b01000100, DL, GRLenVT));
3328 V2 = DAG.getBitcast(VT, V2);
3329 }
3330
3331 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3332 *it = *it < 0 ? *it : *it + HalfSize;
3333 }
3334 } else { // cross-lane
3335 return false;
3336 }
3337
3338 return true;
3339}
3340
3341/// Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
3342///
3343/// For example:
3344/// %2 = shufflevector <4 x i64> %0, <4 x i64> %1,
3345/// <4 x i32> <i32 2, i32 3, i32 4, i32 5>
3346/// is lowered to:
3347/// (XVPERMI_Q $xr1, $xr0, 33)
3348static SDValue
3350 SDValue V1, SDValue V2, SelectionDAG &DAG,
3351 const LoongArchSubtarget &Subtarget) {
3352 // Each 128-bit lane of the result must be a whole lane of V1 or V2.
3353 SmallVector<int, 2> LaneMask;
3354 if (!widenShuffleMaskElts(Mask.size() / 2, Mask, LaneMask))
3355 return SDValue();
3356
3357 // Lanes 0-3 are V1.lo, V1.hi, V2.lo and V2.hi, the same as the XVPERMI_Q
3358 // selector with xj = V1 and xd = V2.
3359 int Lo = LaneMask[0] < 0 ? 0 : LaneMask[0];
3360 int Hi = LaneMask[1] < 0 ? 1 : LaneMask[1];
3361 return DAG.getNode(
3362 LoongArchISD::XVPERMIQ, DL, VT, V2, V1,
3363 DAG.getConstant(Lo | (Hi << 4), DL, Subtarget.getGRLenVT()));
3364}
3365
3366/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3367/// Only for 256-bit vector.
3368///
3369/// Each 128-bit lane of the result may use at most two lanes of the inputs.
3370/// These lanes are first moved into place, then shuffled within the lane.
3371///
3372/// For example:
3373/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3374/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3375/// is lowerded to:
3376/// (XVPERMI $xr2, $xr0, 78)
3377/// (XVSHUF $xr1, $xr2, $xr0)
3378/// (XVORI $xr0, $xr1, 0)
3379///
3380/// and the splice:
3381/// %2 = shufflevector <8 x i32> %0, <8 x i32> %1,
3382/// <8 x i32> <i32 7, i32 8, i32 9, i32 10,
3383/// i32 11, i32 12, i32 13, i32 14>
3384/// is lowered to:
3385/// (XVBSLL_V $xr2, $xr1, 4)
3386/// (XVPERMI_Q $xr1, $xr0, 33)
3387/// (XVBSRL_V $xr0, $xr1, 12)
3388/// (XVOR_V $xr0, $xr2, $xr0)
3390 ArrayRef<int> Mask,
3391 MVT VT, SDValue V1,
3392 SDValue V2,
3393 SelectionDAG &DAG) {
3394 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3395 int Size = Mask.size();
3396 int LaneSize = Size / 2;
3397
3398 // For each result lane, the input lanes (0/1: V1, 2/3: V2) used by the two
3399 // operands of the in-lane shuffle.
3400 int LaneSrcs[2][2] = {{-1, -1}, {-1, -1}};
3401 SmallVector<int, 32> InLaneMask(Size, -1);
3402 bool LaneCrossing = false;
3403 for (int i = 0; i < Size; ++i) {
3404 int M = Mask[i];
3405 if (M < 0)
3406 continue;
3407 int Lane = i / LaneSize;
3408 int SrcLane = M / LaneSize;
3409
3410 // Put lanes that stay in place in the first operand and the others in the
3411 // second one, so a single input becomes V1 and V1 with lanes swapped.
3412 int Op = (SrcLane % 2) != Lane;
3413 LaneCrossing |= Op;
3414 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3415 Op ^= 1;
3416 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3417 return SDValue();
3418 LaneSrcs[Lane][Op] = SrcLane;
3419 InLaneMask[i] = Op * Size + Lane * LaneSize + M % LaneSize;
3420 }
3421
3422 if (!LaneCrossing)
3423 return SDValue();
3424
3425 // Swap the operands of the high lane if that makes both lanes use the same
3426 // in-lane mask, which more patterns (e.g. XVPICKEV) can match.
3427 SmallVector<int, 16> RepeatedMask;
3428 if (!isRepeatedShuffleMask(128, VT, InLaneMask, RepeatedMask)) {
3429 SmallVector<int, 32> SwappedMask(InLaneMask);
3430 for (int i = LaneSize; i < Size; ++i)
3431 if (SwappedMask[i] >= 0)
3432 SwappedMask[i] = (SwappedMask[i] + Size) % (2 * Size);
3433 if (isRepeatedShuffleMask(128, VT, SwappedMask, RepeatedMask)) {
3434 std::swap(LaneSrcs[1][0], LaneSrcs[1][1]);
3435 InLaneMask = SwappedMask;
3436 }
3437 }
3438
3439 // Move the input lanes of each operand into place.
3440 SDValue Ops[2];
3441 for (int Op = 0; Op < 2; ++Op) {
3442 SmallVector<int, 32> LaneMask(Size, -1);
3443 for (int Lane = 0; Lane < 2; ++Lane)
3444 if (LaneSrcs[Lane][Op] >= 0)
3445 for (int i = 0; i < LaneSize; ++i)
3446 LaneMask[Lane * LaneSize + i] = LaneSrcs[Lane][Op] * LaneSize + i;
3447 Ops[Op] = DAG.getVectorShuffle(VT, DL, V1, V2, LaneMask);
3448
3449 // Exit if we got back the shuffle we started with, to avoid infinite
3450 // recursion.
3451 if (auto *SVN = dyn_cast<ShuffleVectorSDNode>(Ops[Op]))
3452 if (SVN->getMask() == Mask)
3453 return SDValue();
3454 }
3455 return DAG.getVectorShuffle(VT, DL, Ops[0], Ops[1], InLaneMask);
3456}
3457
3458/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3459///
3460/// This routine breaks down the specific type of 256-bit shuffle and
3461/// dispatches to the lowering routines accordingly.
3463 SDValue V1, SDValue V2, SelectionDAG &DAG,
3464 const LoongArchSubtarget &Subtarget) {
3465 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3466 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3467 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3468 "Vector type is unsupported for lasx!");
3469 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3470 "Two operands have different types!");
3471 assert(VT.getVectorNumElements() == Mask.size() &&
3472 "Unexpected mask size for shuffle!");
3473 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3474 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3475
3476 APInt KnownUndef, KnownZero;
3477 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3478 APInt Zeroable = KnownUndef | KnownZero;
3479
3480 SDValue Result;
3481 // TODO: Add more comparison patterns.
3482 if (V2.isUndef()) {
3483 if ((Result =
3484 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3485 return Result;
3486 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3487 Subtarget)))
3488 return Result;
3489 if ((Result = lowerVECTOR_SHUFFLE_XVREPLVE0(DL, Mask, VT, V1, DAG)))
3490 return Result;
3491 // Try to widen vectors to gain more optimization opportunities.
3492 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3493 return NewShuffle;
3494 if ((Result =
3495 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3496 return Result;
3497 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3498 return Result;
3499 if ((Result =
3500 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3501 return Result;
3502
3503 // TODO: This comment may be enabled in the future to better match the
3504 // pattern for instruction selection.
3505 /* V2 = V1; */
3506 }
3507
3508 // It is recommended not to change the pattern comparison order for better
3509 // performance.
3510 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3511 return Result;
3512 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3513 return Result;
3514 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3515 return Result;
3516 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3517 return Result;
3518 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3519 return Result;
3520 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3521 return Result;
3522 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3523 (Result =
3524 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3525 return Result;
3526 if ((Result =
3527 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3528 return Result;
3529 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3530 Zeroable)))
3531 return Result;
3532 if ((Result =
3533 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3534 return Result;
3535 if ((Result =
3536 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3537 return Result;
3538 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3539 Subtarget)))
3540 return Result;
3541
3542 if ((Result =
3543 lowerVECTOR_SHUFFLE_XVPERMIQ(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3544 return Result;
3545
3546 // canonicalize non cross-lane shuffle vector
3547 SmallVector<int> NewMask(Mask);
3548 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3549 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3550
3551 // FIXME: Handling the remaining cases earlier can degrade performance
3552 // in some situations. Further analysis is required to enable more
3553 // effective optimizations.
3554 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT, V1,
3555 V2, DAG)))
3556 return Result;
3557
3558 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3559 return NewShuffle;
3560 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3561 return Result;
3562
3563 return SDValue();
3564}
3565
3566SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3567 SelectionDAG &DAG) const {
3568 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3569 ArrayRef<int> OrigMask = SVOp->getMask();
3570 SDValue V1 = Op.getOperand(0);
3571 SDValue V2 = Op.getOperand(1);
3572 MVT VT = Op.getSimpleValueType();
3573 int NumElements = VT.getVectorNumElements();
3574 SDLoc DL(Op);
3575
3576 bool V1IsUndef = V1.isUndef();
3577 bool V2IsUndef = V2.isUndef();
3578 if (V1IsUndef && V2IsUndef)
3579 return DAG.getUNDEF(VT);
3580
3581 // When we create a shuffle node we put the UNDEF node to second operand,
3582 // but in some cases the first operand may be transformed to UNDEF.
3583 // In this case we should just commute the node.
3584 if (V1IsUndef)
3585 return DAG.getCommutedVectorShuffle(*SVOp);
3586
3587 // Check for non-undef masks pointing at an undef vector and make the masks
3588 // undef as well. This makes it easier to match the shuffle based solely on
3589 // the mask.
3590 if (V2IsUndef &&
3591 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3592 SmallVector<int, 8> NewMask(OrigMask);
3593 for (int &M : NewMask)
3594 if (M >= NumElements)
3595 M = -1;
3596 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3597 }
3598
3599 // Check for illegal shuffle mask element index values.
3600 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3601 (void)MaskUpperLimit;
3602 assert(llvm::all_of(OrigMask,
3603 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3604 "Out of bounds shuffle index");
3605
3606 // For each vector width, delegate to a specialized lowering routine.
3607 if (VT.is128BitVector())
3608 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3609
3610 if (VT.is256BitVector())
3611 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3612
3613 return SDValue();
3614}
3615
3616SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3617 SelectionDAG &DAG) const {
3618 // Custom lower to ensure the libcall return is passed in an FPR on hard
3619 // float ABIs.
3620 SDLoc DL(Op);
3621 MakeLibCallOptions CallOptions;
3622 SDValue Op0 = Op.getOperand(0);
3623 SDValue Chain = SDValue();
3624 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3625 SDValue Res;
3626 std::tie(Res, Chain) =
3627 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3628 if (Subtarget.is64Bit())
3629 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3630 return DAG.getBitcast(MVT::i32, Res);
3631}
3632
3633SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3634 SelectionDAG &DAG) const {
3635 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3636 // float ABIs.
3637 SDLoc DL(Op);
3638 MakeLibCallOptions CallOptions;
3639 SDValue Op0 = Op.getOperand(0);
3640 SDValue Chain = SDValue();
3641 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3642 DL, MVT::f32, Op0)
3643 : DAG.getBitcast(MVT::f32, Op0);
3644 SDValue Res;
3645 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3646 CallOptions, DL, Chain);
3647 return Res;
3648}
3649
3650SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3651 SelectionDAG &DAG) const {
3652 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3653 SDLoc DL(Op);
3654 MakeLibCallOptions CallOptions;
3655 RTLIB::Libcall LC =
3656 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3657 SDValue Res =
3658 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3659 if (Subtarget.is64Bit())
3660 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3661 return DAG.getBitcast(MVT::i32, Res);
3662}
3663
3664SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3665 SelectionDAG &DAG) const {
3666 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3667 MVT VT = Op.getSimpleValueType();
3668 SDLoc DL(Op);
3669 Op = DAG.getNode(
3670 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3671 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3672 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3673 DL, MVT::f32, Op)
3674 : DAG.getBitcast(MVT::f32, Op);
3675 if (VT != MVT::f32)
3676 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3677 return Res;
3678}
3679
3680// Lower BUILD_VECTOR as broadcast load (if possible).
3681// For example:
3682// %a = load i8, ptr %ptr
3683// %b = build_vector %a, %a, %a, %a
3684// is lowered to :
3685// (VLDREPL_B $a0, 0)
3687 const SDLoc &DL,
3688 SelectionDAG &DAG) {
3689 MVT VT = BVOp->getSimpleValueType(0);
3690 int NumOps = BVOp->getNumOperands();
3691
3692 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3693 "Unsupported vector type for broadcast.");
3694
3695 SDValue IdentitySrc;
3696 bool IsIdeneity = true;
3697
3698 for (int i = 0; i != NumOps; i++) {
3699 SDValue Op = BVOp->getOperand(i);
3700 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3701 IsIdeneity = false;
3702 break;
3703 }
3704 IdentitySrc = BVOp->getOperand(0);
3705 }
3706
3707 // make sure that this load is valid and only has one user.
3708 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3709 return SDValue();
3710
3711 auto *LN = cast<LoadSDNode>(IdentitySrc);
3712 auto ExtType = LN->getExtensionType();
3713
3714 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3715 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3716 // Indexed loads and stores are not supported on LoongArch.
3717 assert(LN->isUnindexed() && "Unexpected indexed load.");
3718
3719 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3720 // The offset operand of unindexed load is always undefined, so there is
3721 // no need to pass it to VLDREPL.
3722 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3723 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3724 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3725 return BCast;
3726 }
3727 return SDValue();
3728}
3729
3730// Sequentially insert elements from Ops into Vector, from low to high indices.
3731// Note: Ops can have fewer elements than Vector.
3733 const LoongArchSubtarget &Subtarget, SDValue &Vector,
3734 EVT ResTy) {
3735 assert(Ops.size() <= ResTy.getVectorNumElements());
3736
3737 SDValue Op0 = Ops[0];
3738 if (!Op0.isUndef())
3739 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3740 for (unsigned i = 1; i < Ops.size(); ++i) {
3741 SDValue Opi = Ops[i];
3742 if (Opi.isUndef())
3743 continue;
3744 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3745 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3746 }
3747}
3748
3749// Build a ResTy subvector from Node, taking NumElts elements starting at index
3750// 'first'.
3752 SelectionDAG &DAG, SDLoc DL,
3753 const LoongArchSubtarget &Subtarget,
3754 EVT ResTy, unsigned first) {
3755 unsigned NumElts = ResTy.getVectorNumElements();
3756
3757 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3758
3759 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3760 Node->op_begin() + first + NumElts);
3761 SDValue Vector = DAG.getUNDEF(ResTy);
3762 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3763 return Vector;
3764}
3765
3766SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3767 SelectionDAG &DAG) const {
3768 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3769 MVT VT = Node->getSimpleValueType(0);
3770 EVT ResTy = Op->getValueType(0);
3771 unsigned NumElts = ResTy.getVectorNumElements();
3772 SDLoc DL(Op);
3773 APInt SplatValue, SplatUndef;
3774 unsigned SplatBitSize;
3775 bool HasAnyUndefs;
3776 bool IsConstant = false;
3777 bool UseSameConstant = true;
3778 SDValue ConstantValue;
3779 bool Is128Vec = ResTy.is128BitVector();
3780 bool Is256Vec = ResTy.is256BitVector();
3781
3782 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3783 (!Subtarget.hasExtLASX() || !Is256Vec))
3784 return SDValue();
3785
3786 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3787 return Result;
3788
3789 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3790 /*MinSplatBits=*/8) &&
3791 SplatBitSize <= 64) {
3792 // We can only cope with 8, 16, 32, or 64-bit elements.
3793 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3794 SplatBitSize != 64)
3795 return SDValue();
3796
3797 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3798 // We can only handle 64-bit elements that are within
3799 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3800 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3801 if (!SplatValue.isSignedIntN(10) &&
3802 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3803 return SDValue();
3804 if ((Is128Vec && ResTy == MVT::v4i32) ||
3805 (Is256Vec && ResTy == MVT::v8i32))
3806 return Op;
3807 }
3808
3809 EVT ViaVecTy;
3810
3811 switch (SplatBitSize) {
3812 default:
3813 return SDValue();
3814 case 8:
3815 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3816 break;
3817 case 16:
3818 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3819 break;
3820 case 32:
3821 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3822 break;
3823 case 64:
3824 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3825 break;
3826 }
3827
3828 // SelectionDAG::getConstant will promote SplatValue appropriately.
3829 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3830
3831 // Bitcast to the type we originally wanted.
3832 if (ViaVecTy != ResTy)
3833 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3834
3835 return Result;
3836 }
3837
3838 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3839 return Op;
3840
3841 for (unsigned i = 0; i < NumElts; ++i) {
3842 SDValue Opi = Node->getOperand(i);
3843 if (isIntOrFPConstant(Opi)) {
3844 IsConstant = true;
3845 if (!ConstantValue.getNode())
3846 ConstantValue = Opi;
3847 else if (ConstantValue != Opi)
3848 UseSameConstant = false;
3849 }
3850 }
3851
3852 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3853 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3854 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3855 for (unsigned i = 0; i < NumElts; ++i) {
3856 SDValue Opi = Node->getOperand(i);
3857 if (!isIntOrFPConstant(Opi))
3858 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3859 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3860 }
3861 return Result;
3862 }
3863
3864 if (!IsConstant) {
3865 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3866 // the sub-sequence of the vector and then broadcast the sub-sequence.
3867 //
3868 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3869 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3870 // generates worse code in some cases. This could be further optimized
3871 // with more consideration.
3873 BitVector UndefElements;
3874 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3875 UndefElements.count() == 0) {
3876 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3877 // because the high part can be simply treated as undef.
3878 SDValue Vector = DAG.getUNDEF(ResTy);
3879 EVT FillTy = Is256Vec
3881 : ResTy;
3882 SDValue FillVec =
3883 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3884
3885 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3886
3887 unsigned SeqLen = Sequence.size();
3888 unsigned SplatLen = NumElts / SeqLen;
3889 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3890 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3891
3892 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3893 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3894 if (SplatEltTy == MVT::i128)
3895 SplatTy = MVT::v4i64;
3896
3897 SDValue SplatVec;
3898 SDValue SrcVec = DAG.getBitcast(
3899 SplatTy,
3900 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3901 if (Is256Vec) {
3902 SplatVec =
3903 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3904 : LoongArchISD::XVREPLVE0,
3905 DL, SplatTy, SrcVec);
3906 } else {
3907 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3908 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3909 }
3910
3911 return DAG.getBitcast(ResTy, SplatVec);
3912 }
3913
3914 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3915 // using memory operations is much lower.
3916 //
3917 // For 256-bit vectors, normally split into two halves and concatenate.
3918 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
3919 // one non-undef element, skip spliting to avoid a worse result.
3920 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
3921 ResTy == MVT::v4f64) {
3922 unsigned NonUndefCount = 0;
3923 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
3924 if (!Node->getOperand(i).isUndef()) {
3925 ++NonUndefCount;
3926 if (NonUndefCount > 1)
3927 break;
3928 }
3929 }
3930 if (NonUndefCount == 1)
3931 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
3932 }
3933
3934 EVT VecTy =
3935 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
3936 SDValue Vector =
3937 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
3938
3939 if (Is128Vec)
3940 return Vector;
3941
3942 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
3943 VecTy, NumElts / 2);
3944
3945 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
3946 }
3947
3948 return SDValue();
3949}
3950
3951SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
3952 SelectionDAG &DAG) const {
3953 SDLoc DL(Op);
3954 MVT ResVT = Op.getSimpleValueType();
3955 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
3956
3957 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
3958 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
3959 return Op;
3960
3961 unsigned NumOperands = Op.getNumOperands();
3962 unsigned NumFreezeUndef = 0;
3963 unsigned NumZero = 0;
3964 unsigned NumNonZero = 0;
3965 unsigned NonZeros = 0;
3966 SmallSet<SDValue, 4> Undefs;
3967 for (unsigned i = 0; i != NumOperands; ++i) {
3968 SDValue SubVec = Op.getOperand(i);
3969 if (SubVec.isUndef())
3970 continue;
3971 if (ISD::isFreezeUndef(SubVec.getNode())) {
3972 // If the freeze(undef) has multiple uses then we must fold to zero.
3973 if (SubVec.hasOneUse()) {
3974 ++NumFreezeUndef;
3975 } else {
3976 ++NumZero;
3977 Undefs.insert(SubVec);
3978 }
3979 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
3980 ++NumZero;
3981 else {
3982 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
3983 NonZeros |= 1 << i;
3984 ++NumNonZero;
3985 }
3986 }
3987
3988 // If we have more than 2 non-zeros, build each half separately.
3989 if (NumNonZero > 2) {
3990 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
3991 ArrayRef<SDUse> Ops = Op->ops();
3992 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3993 Ops.slice(0, NumOperands / 2));
3994 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3995 Ops.slice(NumOperands / 2));
3996 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
3997 }
3998
3999 // Otherwise, build it up through insert_subvectors.
4000 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
4001 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
4002 : DAG.getUNDEF(ResVT));
4003
4004 // Replace Undef operands with ZeroVector.
4005 for (SDValue U : Undefs)
4006 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
4007
4008 MVT SubVT = Op.getOperand(0).getSimpleValueType();
4009 unsigned NumSubElems = SubVT.getVectorNumElements();
4010 for (unsigned i = 0; i != NumOperands; ++i) {
4011 if ((NonZeros & (1 << i)) == 0)
4012 continue;
4013
4014 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
4015 DAG.getVectorIdxConstant(i * NumSubElems, DL));
4016 }
4017
4018 return Vec;
4019}
4020
4021SDValue
4022LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
4023 SelectionDAG &DAG) const {
4024 MVT EltVT = Op.getSimpleValueType();
4025 SDValue Vec = Op->getOperand(0);
4026 EVT VecTy = Vec->getValueType(0);
4027 SDValue Idx = Op->getOperand(1);
4028 SDLoc DL(Op);
4029 MVT GRLenVT = Subtarget.getGRLenVT();
4030
4031 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
4032
4033 if (isa<ConstantSDNode>(Idx))
4034 return Op;
4035
4036 switch (VecTy.getSimpleVT().SimpleTy) {
4037 default:
4038 llvm_unreachable("Unexpected type");
4039 case MVT::v32i8:
4040 case MVT::v16i16:
4041 case MVT::v4i64:
4042 case MVT::v4f64: {
4043 // Extract the high half subvector and place it to the low half of a new
4044 // vector. It doesn't matter what the high half of the new vector is.
4045 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
4046 SDValue VecHi =
4047 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
4048 SDValue TmpVec =
4049 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
4050 VecHi, DAG.getConstant(0, DL, GRLenVT));
4051
4052 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
4053 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
4054 // desired element.
4055 SDValue IdxCp =
4056 Subtarget.is64Bit()
4057 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
4058 : DAG.getBitcast(MVT::f32, Idx);
4059 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
4060 SDValue MaskVec =
4061 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
4062 SDValue ResVec =
4063 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
4064
4065 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
4066 DAG.getConstant(0, DL, GRLenVT));
4067 }
4068 case MVT::v8i32:
4069 case MVT::v8f32: {
4070 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
4071 SDValue SplatValue =
4072 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
4073
4074 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
4075 DAG.getConstant(0, DL, GRLenVT));
4076 }
4077 }
4078}
4079
4080SDValue
4081LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
4082 SelectionDAG &DAG) const {
4083 MVT VT = Op.getSimpleValueType();
4084 MVT EltVT = VT.getVectorElementType();
4085 unsigned NumElts = VT.getVectorNumElements();
4086 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
4087 SDLoc DL(Op);
4088 SDValue Op0 = Op.getOperand(0);
4089 SDValue Op1 = Op.getOperand(1);
4090 SDValue Op2 = Op.getOperand(2);
4091
4092 if (isa<ConstantSDNode>(Op2))
4093 return Op;
4094
4095 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4096 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4097
4098 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4099 return SDValue();
4100
4101 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4102 SmallVector<SDValue, 32> RawIndices;
4103 SDValue SplatIdx;
4104 SDValue Indices;
4105
4106 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4107 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4108 for (unsigned i = 0; i < NumElts; ++i) {
4109 RawIndices.push_back(Op2);
4110 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4111 }
4112 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4113 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4114
4115 RawIndices.clear();
4116 for (unsigned i = 0; i < NumElts; ++i) {
4117 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4118 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4119 }
4120 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4121 Indices = DAG.getBitcast(IdxVTy, Indices);
4122 } else {
4123 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4124
4125 for (unsigned i = 0; i < NumElts; ++i)
4126 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4127 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4128 }
4129
4130 // insert vec, elt, idx
4131 // =>
4132 // select (splatidx == {0,1,2...}) ? splatelt : vec
4133 SDValue SelectCC =
4134 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4135 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4136}
4137
4138SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4139 SelectionDAG &DAG) const {
4140 SDLoc DL(Op);
4141 SyncScope::ID FenceSSID =
4142 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4143
4144 // singlethread fences only synchronize with signal handlers on the same
4145 // thread and thus only need to preserve instruction order, not actually
4146 // enforce memory ordering.
4147 if (FenceSSID == SyncScope::SingleThread)
4148 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4149 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4150
4151 return Op;
4152}
4153
4155 MVT GRLenVT, SDValue RMValue) {
4156 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4157 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4158 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4159 //
4160 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4161 // Since the transformation is self-inverse, it applies in both directions:
4162 // LLVM RM <-> LoongArch FCSR RM
4163 //
4164 // Transformation: RM ^ (~(RM >> 1) & 1)
4165 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4166 DAG.getConstant(1, DL, GRLenVT));
4167
4168 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4169 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4170 DAG.getConstant(1, DL, GRLenVT)),
4171 DAG.getConstant(1, DL, GRLenVT));
4172
4173 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4174}
4175
4176SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4177 SelectionDAG &DAG) const {
4178 MVT GRLenVT = Subtarget.getGRLenVT();
4179 SDLoc DL(Op);
4180 SDValue Chain = Op.getOperand(0);
4181 SDValue RMValue = Op.getOperand(1);
4182
4183 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4184 uint64_t RM = CVal->getZExtValue();
4185 if (RM > 3) {
4187 LLVMContext &C = MF.getFunction().getContext();
4188 C.diagnose(DiagnosticInfoUnsupported(
4189 MF.getFunction(),
4190 "rounding mode is not supported by LoongArch hardware",
4191 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4192 return Chain;
4193 }
4194 }
4195
4196 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4197 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4198
4199 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4200 // into position before writing via WRFCSR.
4201 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4202 DAG.getConstant(8, DL, GRLenVT));
4203
4204 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4205 // unrelated fields in FCSR0.
4206 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4207 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4208 FCSRNo, RMValue, Chain);
4209 return SDValue(RN, 0);
4210}
4211
4212SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4213 SelectionDAG &DAG) const {
4214 MVT GRLenVT = Subtarget.getGRLenVT();
4215 SDLoc DL(Op);
4216 SDValue Chain = Op->getOperand(0);
4217
4218 // FCSR3 is an alias of the RM field.
4219 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4220 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4221 MVT::Other, FCSRNo, Chain);
4222 SDValue RMValue = SDValue(FCSR, 0);
4223 Chain = SDValue(FCSR, 1);
4224
4225 // The RM field in FCSR is at bits [9:8].
4226 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4227 DAG.getConstant(8, DL, GRLenVT));
4228 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4229
4230 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4231 return DAG.getMergeValues({RetVal, Chain}, DL);
4232}
4233
4234SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4235 SelectionDAG &DAG) const {
4236
4237 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4238 DAG.getContext()->emitError(
4239 "On LA64, only 64-bit registers can be written.");
4240 return Op.getOperand(0);
4241 }
4242
4243 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4244 DAG.getContext()->emitError(
4245 "On LA32, only 32-bit registers can be written.");
4246 return Op.getOperand(0);
4247 }
4248
4249 return Op;
4250}
4251
4252SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4253 SelectionDAG &DAG) const {
4254 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4255 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4256 "be a constant integer");
4257 return SDValue();
4258 }
4259
4262 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4263 EVT VT = Op.getValueType();
4264 SDLoc DL(Op);
4265 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4266 unsigned Depth = Op.getConstantOperandVal(0);
4267 int GRLenInBytes = Subtarget.getGRLen() / 8;
4268
4269 while (Depth--) {
4270 int Offset = -(GRLenInBytes * 2);
4271 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4272 DAG.getSignedConstant(Offset, DL, VT));
4273 FrameAddr =
4274 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4275 }
4276 return FrameAddr;
4277}
4278
4279SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4280 SelectionDAG &DAG) const {
4281 // Currently only support lowering return address for current frame.
4282 if (Op.getConstantOperandVal(0) != 0) {
4283 DAG.getContext()->emitError(
4284 "return address can only be determined for the current frame");
4285 return SDValue();
4286 }
4287
4290 MVT GRLenVT = Subtarget.getGRLenVT();
4291
4292 // Return the value of the return address register, marking it an implicit
4293 // live-in.
4294 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4295 getRegClassFor(GRLenVT));
4296 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4297}
4298
4299SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4300 SelectionDAG &DAG) const {
4302 auto Size = Subtarget.getGRLen() / 8;
4303 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4304 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4305}
4306
4307SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4308 SelectionDAG &DAG) const {
4310 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4311
4312 SDLoc DL(Op);
4313 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4315
4316 // vastart just stores the address of the VarArgsFrameIndex slot into the
4317 // memory location argument.
4318 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4319 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4320 MachinePointerInfo(SV));
4321}
4322
4323SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4324 SelectionDAG &DAG) const {
4325 SDLoc DL(Op);
4326 SDValue Op0 = Op.getOperand(0);
4327 EVT VT = Op.getValueType();
4328 EVT Op0VT = Op0.getValueType();
4329
4330 if (VT.isVector()) {
4331 if (VT.getScalarSizeInBits() != Op0VT.getScalarSizeInBits())
4332 return SDValue();
4333 return Op;
4334 }
4335
4336 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4339 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4340
4341 // We can't do uint64 -> double -> float because of double-rounding issue.
4342 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4343 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4344 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4345 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4346 DAG.getIntPtrConstant(0, DL));
4347 return Conv;
4348 }
4349
4350 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4351 return SDValue();
4352
4353 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4354 !Subtarget.hasBasicD() && "unexpected target features");
4355
4356 if (Op0->getOpcode() == ISD::AND) {
4357 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4358 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4359 return Op;
4360 }
4361
4362 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4363 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4364 Op0.getConstantOperandVal(2) == UINT64_C(0))
4365 return Op;
4366
4367 if (Op0.getOpcode() == ISD::AssertZext &&
4368 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4369 return Op;
4370
4371 EVT OpVT = Op0.getValueType();
4372 EVT RetVT = Op.getValueType();
4373 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4374 MakeLibCallOptions CallOptions;
4375 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4376 SDValue Chain = SDValue();
4377 SDValue Result;
4378 std::tie(Result, Chain) =
4379 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4380 return Result;
4381}
4382
4383SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4384 SelectionDAG &DAG) const {
4385 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4386 !Subtarget.hasBasicD() && "unexpected target features");
4387
4388 SDLoc DL(Op);
4389 SDValue Op0 = Op.getOperand(0);
4390
4391 if ((Op0.getOpcode() == ISD::AssertSext ||
4393 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4394 return Op;
4395
4396 EVT OpVT = Op0.getValueType();
4397 EVT RetVT = Op.getValueType();
4398 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4399 MakeLibCallOptions CallOptions;
4400 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4401 SDValue Chain = SDValue();
4402 SDValue Result;
4403 std::tie(Result, Chain) =
4404 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4405 return Result;
4406}
4407
4408SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4409 SelectionDAG &DAG) const {
4410
4411 SDLoc DL(Op);
4412 EVT VT = Op.getValueType();
4413 SDValue Op0 = Op.getOperand(0);
4414 EVT Op0VT = Op0.getValueType();
4415
4416 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4417 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4418 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4419 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4420 }
4421 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4422 SDValue Lo, Hi;
4423 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4424 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4425 }
4426 return Op;
4427}
4428
4429SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4430 SelectionDAG &DAG) const {
4431
4432 SDLoc DL(Op);
4433 SDValue Op0 = Op.getOperand(0);
4434
4435 if (Op0.getValueType() == MVT::f16)
4436 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4437
4438 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4439 !Subtarget.hasBasicD()) {
4440 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4441 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4442 }
4443
4444 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4445 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4446 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4447}
4448
4449// [X]VFTINTRZ and FTINTRZ saturate out-of-range values and convert NaN to 0,
4450// which is exactly the semantics of FP_TO_SINT_SAT with a native saturation
4451// width.
4452SDValue LoongArchTargetLowering::lowerFP_TO_SINT_SAT(SDValue Op,
4453 SelectionDAG &DAG) const {
4454 SDLoc DL(Op);
4455 SDValue Src = Op.getOperand(0);
4456 EVT VT = Op.getValueType();
4457 EVT SrcVT = Src.getValueType();
4458 unsigned SatWidth = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
4459
4460 // Vectors are selected by patterns.
4461 if (VT.isVector()) {
4462 if (SatWidth == VT.getScalarSizeInBits() &&
4463 SatWidth == SrcVT.getScalarSizeInBits())
4464 return Op;
4465 return SDValue();
4466 }
4467
4468 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4469 return SDValue();
4470
4471 if (SatWidth == 32) {
4472 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Src);
4473 if (Subtarget.is64Bit())
4474 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, VT, Ftint);
4475 return DAG.getBitcast(VT, Ftint);
4476 }
4477
4478 if (SatWidth == 64 && Subtarget.is64Bit() && Subtarget.hasBasicD()) {
4479 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f64, Src);
4480 return DAG.getBitcast(VT, Ftint);
4481 }
4482
4483 return SDValue();
4484}
4485
4486SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4487 SelectionDAG &DAG) const {
4488 if (!Subtarget.hasExtLSX())
4489 return SDValue();
4490
4491 SDLoc DL(Op);
4492 SDValue Src = Op.getOperand(0);
4493 EVT VT = Op.getValueType();
4494 EVT SrcVT = Src.getValueType();
4495
4496 if (VT != MVT::i64)
4497 return SDValue();
4498
4499 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4500 return SDValue();
4501
4502 if (SrcVT == MVT::f32)
4503 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4504 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4505 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4506 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4507 DAG.getIntPtrConstant(0, DL));
4508}
4509
4511 SelectionDAG &DAG, unsigned Flags) {
4512 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4513}
4514
4516 SelectionDAG &DAG, unsigned Flags) {
4517 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4518 Flags);
4519}
4520
4522 SelectionDAG &DAG, unsigned Flags) {
4523 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4524 N->getOffset(), Flags);
4525}
4526
4528 SelectionDAG &DAG, unsigned Flags) {
4529 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4530}
4531
4532template <class NodeTy>
4533SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4535 bool IsLocal) const {
4536 SDLoc DL(N);
4537 EVT Ty = getPointerTy(DAG.getDataLayout());
4538 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4539 SDValue Load;
4540
4541 switch (M) {
4542 default:
4543 report_fatal_error("Unsupported code model");
4544
4545 case CodeModel::Large: {
4546 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4547
4548 // This is not actually used, but is necessary for successfully matching
4549 // the PseudoLA_*_LARGE nodes.
4550 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4551 if (IsLocal) {
4552 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4553 // eventually becomes the desired 5-insn code sequence.
4554 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4555 Tmp, Addr),
4556 0);
4557 } else {
4558 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4559 // eventually becomes the desired 5-insn code sequence.
4560 Load = SDValue(
4561 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4562 0);
4563 }
4564 break;
4565 }
4566
4567 case CodeModel::Small:
4568 case CodeModel::Medium:
4569 if (IsLocal) {
4570 // This generates the pattern (PseudoLA_PCREL sym), which
4571 //
4572 // for la32r expands to:
4573 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4574 //
4575 // for la32s and la64 expands to:
4576 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4577 Load = SDValue(
4578 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4579 } else {
4580 // This generates the pattern (PseudoLA_GOT sym), which
4581 //
4582 // for la32r expands to:
4583 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4584 //
4585 // for la32s and la64 expands to:
4586 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4587 Load =
4588 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4589 }
4590 }
4591
4592 if (!IsLocal) {
4593 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4595 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4599 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4600 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4601 }
4602
4603 return Load;
4604}
4605
4606SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4607 SelectionDAG &DAG) const {
4608 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4609 DAG.getTarget().getCodeModel());
4610}
4611
4612SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4613 SelectionDAG &DAG) const {
4614 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4615 DAG.getTarget().getCodeModel());
4616}
4617
4618SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4619 SelectionDAG &DAG) const {
4620 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4621 DAG.getTarget().getCodeModel());
4622}
4623
4624SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4625 SelectionDAG &DAG) const {
4626 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4627 assert(N->getOffset() == 0 && "unexpected offset in global node");
4628 auto CM = DAG.getTarget().getCodeModel();
4629 const GlobalValue *GV = N->getGlobal();
4630
4631 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4632 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4633 CM = *GCM;
4634 }
4635
4636 return getAddr(N, DAG, CM, GV->isDSOLocal());
4637}
4638
4639SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4640 SelectionDAG &DAG,
4641 unsigned Opc, bool UseGOT,
4642 bool Large) const {
4643 SDLoc DL(N);
4644 EVT Ty = getPointerTy(DAG.getDataLayout());
4645 MVT GRLenVT = Subtarget.getGRLenVT();
4646
4647 // This is not actually used, but is necessary for successfully matching the
4648 // PseudoLA_*_LARGE nodes.
4649 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4650 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4651
4652 // Only IE needs an extra argument for large code model.
4653 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4654 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4655 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4656
4657 // If it is LE for normal/medium code model, the add tp operation will occur
4658 // during the pseudo-instruction expansion.
4659 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4660 return Offset;
4661
4662 if (UseGOT) {
4663 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4665 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4669 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4670 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4671 }
4672
4673 // Add the thread pointer.
4674 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4675 DAG.getRegister(LoongArch::R2, GRLenVT));
4676}
4677
4678SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4679 SelectionDAG &DAG,
4680 unsigned Opc,
4681 bool Large) const {
4682 SDLoc DL(N);
4683 EVT Ty = getPointerTy(DAG.getDataLayout());
4684 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4685
4686 // This is not actually used, but is necessary for successfully matching the
4687 // PseudoLA_*_LARGE nodes.
4688 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4689
4690 // Use a PC-relative addressing mode to access the dynamic GOT address.
4691 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4692 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4693 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4694
4695 // Prepare argument list to generate call.
4697 Args.emplace_back(Load, CallTy);
4698
4699 // Setup call to __tls_get_addr.
4700 TargetLowering::CallLoweringInfo CLI(DAG);
4701 CLI.setDebugLoc(DL)
4702 .setChain(DAG.getEntryNode())
4703 .setLibCallee(CallingConv::C, CallTy,
4704 DAG.getExternalSymbol("__tls_get_addr", Ty),
4705 std::move(Args));
4706
4707 return LowerCallTo(CLI).first;
4708}
4709
4710SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4711 SelectionDAG &DAG, unsigned Opc,
4712 bool Large) const {
4713 SDLoc DL(N);
4714 EVT Ty = getPointerTy(DAG.getDataLayout());
4715 const GlobalValue *GV = N->getGlobal();
4716
4717 // This is not actually used, but is necessary for successfully matching the
4718 // PseudoLA_*_LARGE nodes.
4719 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4720
4721 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4722 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4723 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4724 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4725 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4726}
4727
4728SDValue
4729LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4730 SelectionDAG &DAG) const {
4733 report_fatal_error("In GHC calling convention TLS is not supported");
4734
4735 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4736 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4737
4738 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4739 assert(N->getOffset() == 0 && "unexpected offset in global node");
4740
4741 if (DAG.getTarget().useEmulatedTLS())
4742 reportFatalUsageError("the emulated TLS is prohibited");
4743
4744 bool IsDesc = DAG.getTarget().useTLSDESC();
4745
4746 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4748 // In this model, application code calls the dynamic linker function
4749 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4750 // runtime.
4751 if (!IsDesc)
4752 return getDynamicTLSAddr(N, DAG,
4753 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4754 : LoongArch::PseudoLA_TLS_GD,
4755 Large);
4756 break;
4758 // Same as GeneralDynamic, except for assembly modifiers and relocation
4759 // records.
4760 if (!IsDesc)
4761 return getDynamicTLSAddr(N, DAG,
4762 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4763 : LoongArch::PseudoLA_TLS_LD,
4764 Large);
4765 break;
4767 // This model uses the GOT to resolve TLS offsets.
4768 return getStaticTLSAddr(N, DAG,
4769 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4770 : LoongArch::PseudoLA_TLS_IE,
4771 /*UseGOT=*/true, Large);
4773 // This model is used when static linking as the TLS offsets are resolved
4774 // during program linking.
4775 //
4776 // This node doesn't need an extra argument for the large code model.
4777 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4778 /*UseGOT=*/false, Large);
4779 }
4780
4781 return getTLSDescAddr(N, DAG,
4782 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4783 : LoongArch::PseudoLA_TLS_DESC,
4784 Large);
4785}
4786
4787template <unsigned N>
4789 SelectionDAG &DAG, bool IsSigned = false) {
4790 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4791 // Check the ImmArg.
4792 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4793 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4794 DAG.getContext()->emitError(Op->getOperationName(0) +
4795 ": argument out of range.");
4796 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4797 }
4798 return SDValue();
4799}
4800
4801SDValue
4802LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4803 SelectionDAG &DAG) const {
4804 switch (Op.getConstantOperandVal(0)) {
4805 default:
4806 return SDValue(); // Don't custom lower most intrinsics.
4807 case Intrinsic::thread_pointer: {
4808 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4809 return DAG.getRegister(LoongArch::R2, PtrVT);
4810 }
4811 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4812 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4813 case Intrinsic::loongarch_lsx_vreplvei_d:
4814 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4815 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4816 case Intrinsic::loongarch_lsx_vreplvei_w:
4817 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4818 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4819 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
4820 case Intrinsic::loongarch_lasx_xvpickve_d:
4821 case Intrinsic::loongarch_lasx_xvpickve_d_f:
4822 return checkIntrinsicImmArg<2>(Op, 2, DAG);
4823 case Intrinsic::loongarch_lasx_xvinsve0_d:
4824 return checkIntrinsicImmArg<2>(Op, 3, DAG);
4825 case Intrinsic::loongarch_lsx_vsat_b:
4826 case Intrinsic::loongarch_lsx_vsat_bu:
4827 case Intrinsic::loongarch_lsx_vrotri_b:
4828 case Intrinsic::loongarch_lsx_vsllwil_h_b:
4829 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
4830 case Intrinsic::loongarch_lsx_vsrlri_b:
4831 case Intrinsic::loongarch_lsx_vsrari_b:
4832 case Intrinsic::loongarch_lsx_vreplvei_h:
4833 case Intrinsic::loongarch_lasx_xvsat_b:
4834 case Intrinsic::loongarch_lasx_xvsat_bu:
4835 case Intrinsic::loongarch_lasx_xvrotri_b:
4836 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
4837 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
4838 case Intrinsic::loongarch_lasx_xvsrlri_b:
4839 case Intrinsic::loongarch_lasx_xvsrari_b:
4840 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
4841 case Intrinsic::loongarch_lasx_xvpickve_w:
4842 case Intrinsic::loongarch_lasx_xvpickve_w_f:
4843 return checkIntrinsicImmArg<3>(Op, 2, DAG);
4844 case Intrinsic::loongarch_lasx_xvinsve0_w:
4845 return checkIntrinsicImmArg<3>(Op, 3, DAG);
4846 case Intrinsic::loongarch_lsx_vsat_h:
4847 case Intrinsic::loongarch_lsx_vsat_hu:
4848 case Intrinsic::loongarch_lsx_vrotri_h:
4849 case Intrinsic::loongarch_lsx_vsllwil_w_h:
4850 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
4851 case Intrinsic::loongarch_lsx_vsrlri_h:
4852 case Intrinsic::loongarch_lsx_vsrari_h:
4853 case Intrinsic::loongarch_lsx_vreplvei_b:
4854 case Intrinsic::loongarch_lasx_xvsat_h:
4855 case Intrinsic::loongarch_lasx_xvsat_hu:
4856 case Intrinsic::loongarch_lasx_xvrotri_h:
4857 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
4858 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
4859 case Intrinsic::loongarch_lasx_xvsrlri_h:
4860 case Intrinsic::loongarch_lasx_xvsrari_h:
4861 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
4862 return checkIntrinsicImmArg<4>(Op, 2, DAG);
4863 case Intrinsic::loongarch_lsx_vsrlni_b_h:
4864 case Intrinsic::loongarch_lsx_vsrani_b_h:
4865 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
4866 case Intrinsic::loongarch_lsx_vsrarni_b_h:
4867 case Intrinsic::loongarch_lsx_vssrlni_b_h:
4868 case Intrinsic::loongarch_lsx_vssrani_b_h:
4869 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
4870 case Intrinsic::loongarch_lsx_vssrani_bu_h:
4871 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
4872 case Intrinsic::loongarch_lsx_vssrarni_b_h:
4873 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
4874 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
4875 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
4876 case Intrinsic::loongarch_lasx_xvsrani_b_h:
4877 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
4878 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
4879 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
4880 case Intrinsic::loongarch_lasx_xvssrani_b_h:
4881 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
4882 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
4883 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
4884 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
4885 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
4886 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
4887 return checkIntrinsicImmArg<4>(Op, 3, DAG);
4888 case Intrinsic::loongarch_lsx_vsat_w:
4889 case Intrinsic::loongarch_lsx_vsat_wu:
4890 case Intrinsic::loongarch_lsx_vrotri_w:
4891 case Intrinsic::loongarch_lsx_vsllwil_d_w:
4892 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
4893 case Intrinsic::loongarch_lsx_vsrlri_w:
4894 case Intrinsic::loongarch_lsx_vsrari_w:
4895 case Intrinsic::loongarch_lsx_vslei_bu:
4896 case Intrinsic::loongarch_lsx_vslei_hu:
4897 case Intrinsic::loongarch_lsx_vslei_wu:
4898 case Intrinsic::loongarch_lsx_vslei_du:
4899 case Intrinsic::loongarch_lsx_vslti_bu:
4900 case Intrinsic::loongarch_lsx_vslti_hu:
4901 case Intrinsic::loongarch_lsx_vslti_wu:
4902 case Intrinsic::loongarch_lsx_vslti_du:
4903 case Intrinsic::loongarch_lsx_vbsll_v:
4904 case Intrinsic::loongarch_lsx_vbsrl_v:
4905 case Intrinsic::loongarch_lasx_xvsat_w:
4906 case Intrinsic::loongarch_lasx_xvsat_wu:
4907 case Intrinsic::loongarch_lasx_xvrotri_w:
4908 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
4909 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
4910 case Intrinsic::loongarch_lasx_xvsrlri_w:
4911 case Intrinsic::loongarch_lasx_xvsrari_w:
4912 case Intrinsic::loongarch_lasx_xvslei_bu:
4913 case Intrinsic::loongarch_lasx_xvslei_hu:
4914 case Intrinsic::loongarch_lasx_xvslei_wu:
4915 case Intrinsic::loongarch_lasx_xvslei_du:
4916 case Intrinsic::loongarch_lasx_xvslti_bu:
4917 case Intrinsic::loongarch_lasx_xvslti_hu:
4918 case Intrinsic::loongarch_lasx_xvslti_wu:
4919 case Intrinsic::loongarch_lasx_xvslti_du:
4920 case Intrinsic::loongarch_lasx_xvbsll_v:
4921 case Intrinsic::loongarch_lasx_xvbsrl_v:
4922 return checkIntrinsicImmArg<5>(Op, 2, DAG);
4923 case Intrinsic::loongarch_lsx_vseqi_b:
4924 case Intrinsic::loongarch_lsx_vseqi_h:
4925 case Intrinsic::loongarch_lsx_vseqi_w:
4926 case Intrinsic::loongarch_lsx_vseqi_d:
4927 case Intrinsic::loongarch_lsx_vslei_b:
4928 case Intrinsic::loongarch_lsx_vslei_h:
4929 case Intrinsic::loongarch_lsx_vslei_w:
4930 case Intrinsic::loongarch_lsx_vslei_d:
4931 case Intrinsic::loongarch_lsx_vslti_b:
4932 case Intrinsic::loongarch_lsx_vslti_h:
4933 case Intrinsic::loongarch_lsx_vslti_w:
4934 case Intrinsic::loongarch_lsx_vslti_d:
4935 case Intrinsic::loongarch_lasx_xvseqi_b:
4936 case Intrinsic::loongarch_lasx_xvseqi_h:
4937 case Intrinsic::loongarch_lasx_xvseqi_w:
4938 case Intrinsic::loongarch_lasx_xvseqi_d:
4939 case Intrinsic::loongarch_lasx_xvslei_b:
4940 case Intrinsic::loongarch_lasx_xvslei_h:
4941 case Intrinsic::loongarch_lasx_xvslei_w:
4942 case Intrinsic::loongarch_lasx_xvslei_d:
4943 case Intrinsic::loongarch_lasx_xvslti_b:
4944 case Intrinsic::loongarch_lasx_xvslti_h:
4945 case Intrinsic::loongarch_lasx_xvslti_w:
4946 case Intrinsic::loongarch_lasx_xvslti_d:
4947 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
4948 case Intrinsic::loongarch_lsx_vsrlni_h_w:
4949 case Intrinsic::loongarch_lsx_vsrani_h_w:
4950 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
4951 case Intrinsic::loongarch_lsx_vsrarni_h_w:
4952 case Intrinsic::loongarch_lsx_vssrlni_h_w:
4953 case Intrinsic::loongarch_lsx_vssrani_h_w:
4954 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
4955 case Intrinsic::loongarch_lsx_vssrani_hu_w:
4956 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
4957 case Intrinsic::loongarch_lsx_vssrarni_h_w:
4958 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
4959 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
4960 case Intrinsic::loongarch_lsx_vfrstpi_b:
4961 case Intrinsic::loongarch_lsx_vfrstpi_h:
4962 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
4963 case Intrinsic::loongarch_lasx_xvsrani_h_w:
4964 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
4965 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
4966 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
4967 case Intrinsic::loongarch_lasx_xvssrani_h_w:
4968 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
4969 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
4970 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
4971 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
4972 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
4973 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
4974 case Intrinsic::loongarch_lasx_xvfrstpi_b:
4975 case Intrinsic::loongarch_lasx_xvfrstpi_h:
4976 return checkIntrinsicImmArg<5>(Op, 3, DAG);
4977 case Intrinsic::loongarch_lsx_vsat_d:
4978 case Intrinsic::loongarch_lsx_vsat_du:
4979 case Intrinsic::loongarch_lsx_vrotri_d:
4980 case Intrinsic::loongarch_lsx_vsrlri_d:
4981 case Intrinsic::loongarch_lsx_vsrari_d:
4982 case Intrinsic::loongarch_lasx_xvsat_d:
4983 case Intrinsic::loongarch_lasx_xvsat_du:
4984 case Intrinsic::loongarch_lasx_xvrotri_d:
4985 case Intrinsic::loongarch_lasx_xvsrlri_d:
4986 case Intrinsic::loongarch_lasx_xvsrari_d:
4987 return checkIntrinsicImmArg<6>(Op, 2, DAG);
4988 case Intrinsic::loongarch_lsx_vsrlni_w_d:
4989 case Intrinsic::loongarch_lsx_vsrani_w_d:
4990 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
4991 case Intrinsic::loongarch_lsx_vsrarni_w_d:
4992 case Intrinsic::loongarch_lsx_vssrlni_w_d:
4993 case Intrinsic::loongarch_lsx_vssrani_w_d:
4994 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
4995 case Intrinsic::loongarch_lsx_vssrani_wu_d:
4996 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
4997 case Intrinsic::loongarch_lsx_vssrarni_w_d:
4998 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
4999 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
5000 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
5001 case Intrinsic::loongarch_lasx_xvsrani_w_d:
5002 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
5003 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
5004 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
5005 case Intrinsic::loongarch_lasx_xvssrani_w_d:
5006 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
5007 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
5008 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
5009 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
5010 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
5011 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
5012 return checkIntrinsicImmArg<6>(Op, 3, DAG);
5013 case Intrinsic::loongarch_lsx_vsrlni_d_q:
5014 case Intrinsic::loongarch_lsx_vsrani_d_q:
5015 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
5016 case Intrinsic::loongarch_lsx_vsrarni_d_q:
5017 case Intrinsic::loongarch_lsx_vssrlni_d_q:
5018 case Intrinsic::loongarch_lsx_vssrani_d_q:
5019 case Intrinsic::loongarch_lsx_vssrlni_du_q:
5020 case Intrinsic::loongarch_lsx_vssrani_du_q:
5021 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
5022 case Intrinsic::loongarch_lsx_vssrarni_d_q:
5023 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
5024 case Intrinsic::loongarch_lsx_vssrarni_du_q:
5025 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
5026 case Intrinsic::loongarch_lasx_xvsrani_d_q:
5027 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
5028 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
5029 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
5030 case Intrinsic::loongarch_lasx_xvssrani_d_q:
5031 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
5032 case Intrinsic::loongarch_lasx_xvssrani_du_q:
5033 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
5034 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
5035 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
5036 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
5037 return checkIntrinsicImmArg<7>(Op, 3, DAG);
5038 case Intrinsic::loongarch_lsx_vnori_b:
5039 case Intrinsic::loongarch_lsx_vshuf4i_b:
5040 case Intrinsic::loongarch_lsx_vshuf4i_h:
5041 case Intrinsic::loongarch_lsx_vshuf4i_w:
5042 case Intrinsic::loongarch_lasx_xvnori_b:
5043 case Intrinsic::loongarch_lasx_xvshuf4i_b:
5044 case Intrinsic::loongarch_lasx_xvshuf4i_h:
5045 case Intrinsic::loongarch_lasx_xvshuf4i_w:
5046 case Intrinsic::loongarch_lasx_xvpermi_d:
5047 return checkIntrinsicImmArg<8>(Op, 2, DAG);
5048 case Intrinsic::loongarch_lsx_vshuf4i_d:
5049 case Intrinsic::loongarch_lsx_vpermi_w:
5050 case Intrinsic::loongarch_lsx_vbitseli_b:
5051 case Intrinsic::loongarch_lsx_vextrins_b:
5052 case Intrinsic::loongarch_lsx_vextrins_h:
5053 case Intrinsic::loongarch_lsx_vextrins_w:
5054 case Intrinsic::loongarch_lsx_vextrins_d:
5055 case Intrinsic::loongarch_lasx_xvshuf4i_d:
5056 case Intrinsic::loongarch_lasx_xvpermi_w:
5057 case Intrinsic::loongarch_lasx_xvpermi_q:
5058 case Intrinsic::loongarch_lasx_xvbitseli_b:
5059 case Intrinsic::loongarch_lasx_xvextrins_b:
5060 case Intrinsic::loongarch_lasx_xvextrins_h:
5061 case Intrinsic::loongarch_lasx_xvextrins_w:
5062 case Intrinsic::loongarch_lasx_xvextrins_d:
5063 return checkIntrinsicImmArg<8>(Op, 3, DAG);
5064 case Intrinsic::loongarch_lsx_vrepli_b:
5065 case Intrinsic::loongarch_lsx_vrepli_h:
5066 case Intrinsic::loongarch_lsx_vrepli_w:
5067 case Intrinsic::loongarch_lsx_vrepli_d:
5068 case Intrinsic::loongarch_lasx_xvrepli_b:
5069 case Intrinsic::loongarch_lasx_xvrepli_h:
5070 case Intrinsic::loongarch_lasx_xvrepli_w:
5071 case Intrinsic::loongarch_lasx_xvrepli_d:
5072 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
5073 case Intrinsic::loongarch_lsx_vldi:
5074 case Intrinsic::loongarch_lasx_xvldi:
5075 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
5076 }
5077}
5078
5079// Helper function that emits error message for intrinsics with chain and return
5080// merge values of a UNDEF and the chain.
5082 StringRef ErrorMsg,
5083 SelectionDAG &DAG) {
5084 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5085 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
5086 SDLoc(Op));
5087}
5088
5089SDValue
5090LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
5091 SelectionDAG &DAG) const {
5092 SDLoc DL(Op);
5093 MVT GRLenVT = Subtarget.getGRLenVT();
5094 EVT VT = Op.getValueType();
5095 SDValue Chain = Op.getOperand(0);
5096 const StringRef ErrorMsgOOR = "argument out of range";
5097 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5098 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5099
5100 switch (Op.getConstantOperandVal(1)) {
5101 default:
5102 return Op;
5103 case Intrinsic::loongarch_crc_w_b_w:
5104 case Intrinsic::loongarch_crc_w_h_w:
5105 case Intrinsic::loongarch_crc_w_w_w:
5106 case Intrinsic::loongarch_crc_w_d_w:
5107 case Intrinsic::loongarch_crcc_w_b_w:
5108 case Intrinsic::loongarch_crcc_w_h_w:
5109 case Intrinsic::loongarch_crcc_w_w_w:
5110 case Intrinsic::loongarch_crcc_w_d_w:
5111 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
5112 case Intrinsic::loongarch_csrrd_w:
5113 case Intrinsic::loongarch_csrrd_d: {
5114 unsigned Imm = Op.getConstantOperandVal(2);
5115 return !isUInt<14>(Imm)
5116 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5117 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5118 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5119 }
5120 case Intrinsic::loongarch_csrwr_w:
5121 case Intrinsic::loongarch_csrwr_d: {
5122 unsigned Imm = Op.getConstantOperandVal(3);
5123 return !isUInt<14>(Imm)
5124 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5125 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5126 {Chain, Op.getOperand(2),
5127 DAG.getConstant(Imm, DL, GRLenVT)});
5128 }
5129 case Intrinsic::loongarch_csrxchg_w:
5130 case Intrinsic::loongarch_csrxchg_d: {
5131 unsigned Imm = Op.getConstantOperandVal(4);
5132 return !isUInt<14>(Imm)
5133 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5134 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5135 {Chain, Op.getOperand(2), Op.getOperand(3),
5136 DAG.getConstant(Imm, DL, GRLenVT)});
5137 }
5138 case Intrinsic::loongarch_iocsrrd_d: {
5139 return DAG.getNode(
5140 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5141 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5142 }
5143#define IOCSRRD_CASE(NAME, NODE) \
5144 case Intrinsic::loongarch_##NAME: { \
5145 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5146 {Chain, Op.getOperand(2)}); \
5147 }
5148 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5149 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5150 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5151#undef IOCSRRD_CASE
5152 case Intrinsic::loongarch_cpucfg: {
5153 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5154 {Chain, Op.getOperand(2)});
5155 }
5156 case Intrinsic::loongarch_lddir_d: {
5157 unsigned Imm = Op.getConstantOperandVal(3);
5158 return !isUInt<8>(Imm)
5159 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5160 : Op;
5161 }
5162 case Intrinsic::loongarch_movfcsr2gr: {
5163 if (!Subtarget.hasBasicF())
5164 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5165 unsigned Imm = Op.getConstantOperandVal(2);
5166 return !isUInt<2>(Imm)
5167 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5168 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5169 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5170 }
5171 case Intrinsic::loongarch_lsx_vld:
5172 case Intrinsic::loongarch_lsx_vldrepl_b:
5173 case Intrinsic::loongarch_lasx_xvld:
5174 case Intrinsic::loongarch_lasx_xvldrepl_b:
5175 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5176 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5177 : SDValue();
5178 case Intrinsic::loongarch_lsx_vldrepl_h:
5179 case Intrinsic::loongarch_lasx_xvldrepl_h:
5180 return !isShiftedInt<11, 1>(
5181 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5183 Op, "argument out of range or not a multiple of 2", DAG)
5184 : SDValue();
5185 case Intrinsic::loongarch_lsx_vldrepl_w:
5186 case Intrinsic::loongarch_lasx_xvldrepl_w:
5187 return !isShiftedInt<10, 2>(
5188 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5190 Op, "argument out of range or not a multiple of 4", DAG)
5191 : SDValue();
5192 case Intrinsic::loongarch_lsx_vldrepl_d:
5193 case Intrinsic::loongarch_lasx_xvldrepl_d:
5194 return !isShiftedInt<9, 3>(
5195 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5197 Op, "argument out of range or not a multiple of 8", DAG)
5198 : SDValue();
5199 }
5200}
5201
5202// Helper function that emits error message for intrinsics with void return
5203// value and return the chain.
5205 SelectionDAG &DAG) {
5206
5207 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5208 return Op.getOperand(0);
5209}
5210
5211SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5212 SelectionDAG &DAG) const {
5213 SDLoc DL(Op);
5214 MVT GRLenVT = Subtarget.getGRLenVT();
5215 SDValue Chain = Op.getOperand(0);
5216 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5217 SDValue Op2 = Op.getOperand(2);
5218 const StringRef ErrorMsgOOR = "argument out of range";
5219 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5220 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5221 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5222
5223 switch (IntrinsicEnum) {
5224 default:
5225 // TODO: Add more Intrinsics.
5226 return SDValue();
5227 case Intrinsic::loongarch_cacop_d:
5228 case Intrinsic::loongarch_cacop_w: {
5229 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5230 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5231 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5232 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5233 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5234 unsigned Imm1 = Op2->getAsZExtVal();
5235 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5236 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5237 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5238 return Op;
5239 }
5240 case Intrinsic::loongarch_dbar: {
5241 unsigned Imm = Op2->getAsZExtVal();
5242 return !isUInt<15>(Imm)
5243 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5244 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5245 DAG.getConstant(Imm, DL, GRLenVT));
5246 }
5247 case Intrinsic::loongarch_ibar: {
5248 unsigned Imm = Op2->getAsZExtVal();
5249 return !isUInt<15>(Imm)
5250 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5251 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5252 DAG.getConstant(Imm, DL, GRLenVT));
5253 }
5254 case Intrinsic::loongarch_break: {
5255 unsigned Imm = Op2->getAsZExtVal();
5256 return !isUInt<15>(Imm)
5257 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5258 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5259 DAG.getConstant(Imm, DL, GRLenVT));
5260 }
5261 case Intrinsic::loongarch_movgr2fcsr: {
5262 if (!Subtarget.hasBasicF())
5263 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5264 unsigned Imm = Op2->getAsZExtVal();
5265 return !isUInt<2>(Imm)
5266 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5267 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5268 DAG.getConstant(Imm, DL, GRLenVT),
5269 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5270 Op.getOperand(3)));
5271 }
5272 case Intrinsic::loongarch_syscall: {
5273 unsigned Imm = Op2->getAsZExtVal();
5274 return !isUInt<15>(Imm)
5275 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5276 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5277 DAG.getConstant(Imm, DL, GRLenVT));
5278 }
5279#define IOCSRWR_CASE(NAME, NODE) \
5280 case Intrinsic::loongarch_##NAME: { \
5281 SDValue Op3 = Op.getOperand(3); \
5282 return Subtarget.is64Bit() \
5283 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5284 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5285 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5286 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5287 Op3); \
5288 }
5289 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5290 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5291 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5292#undef IOCSRWR_CASE
5293 case Intrinsic::loongarch_iocsrwr_d: {
5294 return !Subtarget.is64Bit()
5295 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5296 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5297 Op2,
5298 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5299 Op.getOperand(3)));
5300 }
5301#define ASRT_LE_GT_CASE(NAME) \
5302 case Intrinsic::loongarch_##NAME: { \
5303 return !Subtarget.is64Bit() \
5304 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5305 : Op; \
5306 }
5307 ASRT_LE_GT_CASE(asrtle_d)
5308 ASRT_LE_GT_CASE(asrtgt_d)
5309#undef ASRT_LE_GT_CASE
5310 case Intrinsic::loongarch_ldpte_d: {
5311 unsigned Imm = Op.getConstantOperandVal(3);
5312 return !Subtarget.is64Bit()
5313 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5314 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5315 : Op;
5316 }
5317 case Intrinsic::loongarch_lsx_vst:
5318 case Intrinsic::loongarch_lasx_xvst:
5319 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5320 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5321 : SDValue();
5322 case Intrinsic::loongarch_lasx_xvstelm_b:
5323 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5324 !isUInt<5>(Op.getConstantOperandVal(5)))
5325 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5326 : SDValue();
5327 case Intrinsic::loongarch_lsx_vstelm_b:
5328 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5329 !isUInt<4>(Op.getConstantOperandVal(5)))
5330 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5331 : SDValue();
5332 case Intrinsic::loongarch_lasx_xvstelm_h:
5333 return (!isShiftedInt<8, 1>(
5334 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5335 !isUInt<4>(Op.getConstantOperandVal(5)))
5337 Op, "argument out of range or not a multiple of 2", DAG)
5338 : SDValue();
5339 case Intrinsic::loongarch_lsx_vstelm_h:
5340 return (!isShiftedInt<8, 1>(
5341 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5342 !isUInt<3>(Op.getConstantOperandVal(5)))
5344 Op, "argument out of range or not a multiple of 2", DAG)
5345 : SDValue();
5346 case Intrinsic::loongarch_lasx_xvstelm_w:
5347 return (!isShiftedInt<8, 2>(
5348 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5349 !isUInt<3>(Op.getConstantOperandVal(5)))
5351 Op, "argument out of range or not a multiple of 4", DAG)
5352 : SDValue();
5353 case Intrinsic::loongarch_lsx_vstelm_w:
5354 return (!isShiftedInt<8, 2>(
5355 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5356 !isUInt<2>(Op.getConstantOperandVal(5)))
5358 Op, "argument out of range or not a multiple of 4", DAG)
5359 : SDValue();
5360 case Intrinsic::loongarch_lasx_xvstelm_d:
5361 return (!isShiftedInt<8, 3>(
5362 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5363 !isUInt<2>(Op.getConstantOperandVal(5)))
5365 Op, "argument out of range or not a multiple of 8", DAG)
5366 : SDValue();
5367 case Intrinsic::loongarch_lsx_vstelm_d:
5368 return (!isShiftedInt<8, 3>(
5369 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5370 !isUInt<1>(Op.getConstantOperandVal(5)))
5372 Op, "argument out of range or not a multiple of 8", DAG)
5373 : SDValue();
5374 }
5375}
5376
5377SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5378 SelectionDAG &DAG) const {
5379 SDLoc DL(Op);
5380 SDValue Lo = Op.getOperand(0);
5381 SDValue Hi = Op.getOperand(1);
5382 SDValue Shamt = Op.getOperand(2);
5383 EVT VT = Lo.getValueType();
5384
5385 // if Shamt-GRLen < 0: // Shamt < GRLen
5386 // Lo = Lo << Shamt
5387 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5388 // else:
5389 // Lo = 0
5390 // Hi = Lo << (Shamt-GRLen)
5391
5392 SDValue Zero = DAG.getConstant(0, DL, VT);
5393 SDValue One = DAG.getConstant(1, DL, VT);
5394 SDValue MinusGRLen =
5395 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5396 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5397 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5398 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5399
5400 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5401 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5402 SDValue ShiftRightLo =
5403 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5404 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5405 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5406 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5407
5408 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5409
5410 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5411 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5412
5413 SDValue Parts[2] = {Lo, Hi};
5414 return DAG.getMergeValues(Parts, DL);
5415}
5416
5417SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5418 SelectionDAG &DAG,
5419 bool IsSRA) const {
5420 SDLoc DL(Op);
5421 SDValue Lo = Op.getOperand(0);
5422 SDValue Hi = Op.getOperand(1);
5423 SDValue Shamt = Op.getOperand(2);
5424 EVT VT = Lo.getValueType();
5425
5426 // SRA expansion:
5427 // if Shamt-GRLen < 0: // Shamt < GRLen
5428 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5429 // Hi = Hi >>s Shamt
5430 // else:
5431 // Lo = Hi >>s (Shamt-GRLen);
5432 // Hi = Hi >>s (GRLen-1)
5433 //
5434 // SRL expansion:
5435 // if Shamt-GRLen < 0: // Shamt < GRLen
5436 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5437 // Hi = Hi >>u Shamt
5438 // else:
5439 // Lo = Hi >>u (Shamt-GRLen);
5440 // Hi = 0;
5441
5442 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5443
5444 SDValue Zero = DAG.getConstant(0, DL, VT);
5445 SDValue One = DAG.getConstant(1, DL, VT);
5446 SDValue MinusGRLen =
5447 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5448 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5449 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5450 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5451
5452 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5453 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5454 SDValue ShiftLeftHi =
5455 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5456 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5457 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5458 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5459 SDValue HiFalse =
5460 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5461
5462 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5463
5464 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5465 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5466
5467 SDValue Parts[2] = {Lo, Hi};
5468 return DAG.getMergeValues(Parts, DL);
5469}
5470
5471// Returns the opcode of the target-specific SDNode that implements the 32-bit
5472// form of the given Opcode.
5473static unsigned getLoongArchWOpcode(unsigned Opcode) {
5474 switch (Opcode) {
5475 default:
5476 llvm_unreachable("Unexpected opcode");
5477 case ISD::SDIV:
5478 return LoongArchISD::DIV_W;
5479 case ISD::UDIV:
5480 return LoongArchISD::DIV_WU;
5481 case ISD::SREM:
5482 return LoongArchISD::MOD_W;
5483 case ISD::UREM:
5484 return LoongArchISD::MOD_WU;
5485 case ISD::SHL:
5486 return LoongArchISD::SLL_W;
5487 case ISD::SRA:
5488 return LoongArchISD::SRA_W;
5489 case ISD::SRL:
5490 return LoongArchISD::SRL_W;
5491 case ISD::ROTL:
5492 case ISD::ROTR:
5493 return LoongArchISD::ROTR_W;
5494 case ISD::CTTZ:
5495 return LoongArchISD::CTZ_W;
5496 case ISD::CTLZ:
5497 return LoongArchISD::CLZ_W;
5498 }
5499}
5500
5501// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5502// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5503// otherwise be promoted to i64, making it difficult to select the
5504// SLL_W/.../*W later one because the fact the operation was originally of
5505// type i8/i16/i32 is lost.
5507 unsigned ExtOpc = ISD::ANY_EXTEND) {
5508 SDLoc DL(N);
5509 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5510 SDValue NewOp0, NewRes;
5511
5512 switch (NumOp) {
5513 default:
5514 llvm_unreachable("Unexpected NumOp");
5515 case 1: {
5516 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5517 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5518 break;
5519 }
5520 case 2: {
5521 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5522 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5523 if (N->getOpcode() == ISD::ROTL) {
5524 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5525 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5526 }
5527 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5528 break;
5529 }
5530 // TODO:Handle more NumOp.
5531 }
5532
5533 // ReplaceNodeResults requires we maintain the same type for the return
5534 // value.
5535 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5536}
5537
5538// Converts the given 32-bit operation to a i64 operation with signed extension
5539// semantic to reduce the signed extension instructions.
5541 SDLoc DL(N);
5542 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5543 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5544 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5545 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5546 DAG.getValueType(MVT::i32));
5547 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5548}
5549
5550// Helper function that emits error message for intrinsics with/without chain
5551// and return a UNDEF or and the chain as the results.
5554 StringRef ErrorMsg, bool WithChain = true) {
5555 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5556 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5557 if (!WithChain)
5558 return;
5559 Results.push_back(N->getOperand(0));
5560}
5561
5562template <unsigned N>
5563static void
5565 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
5566 unsigned ResOp) {
5567 const StringRef ErrorMsgOOR = "argument out of range";
5568 unsigned Imm = Node->getConstantOperandVal(2);
5569 if (!isUInt<N>(Imm)) {
5571 /*WithChain=*/false);
5572 return;
5573 }
5574 SDLoc DL(Node);
5575 SDValue Vec = Node->getOperand(1);
5576
5577 SDValue PickElt =
5578 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5579 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5581 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5582 PickElt.getValue(0)));
5583}
5584
5587 SelectionDAG &DAG,
5588 const LoongArchSubtarget &Subtarget,
5589 unsigned ResOp) {
5590 SDLoc DL(N);
5591 SDValue Vec = N->getOperand(1);
5592
5593 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5594 Results.push_back(
5595 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5596}
5597
5598static void
5600 SelectionDAG &DAG,
5601 const LoongArchSubtarget &Subtarget) {
5602 switch (N->getConstantOperandVal(0)) {
5603 default:
5604 llvm_unreachable("Unexpected Intrinsic.");
5605 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5606 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5607 LoongArchISD::VPICK_SEXT_ELT);
5608 break;
5609 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5610 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5611 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5612 LoongArchISD::VPICK_SEXT_ELT);
5613 break;
5614 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5615 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5616 LoongArchISD::VPICK_SEXT_ELT);
5617 break;
5618 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5619 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5620 LoongArchISD::VPICK_ZEXT_ELT);
5621 break;
5622 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5623 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5624 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5625 LoongArchISD::VPICK_ZEXT_ELT);
5626 break;
5627 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5628 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5629 LoongArchISD::VPICK_ZEXT_ELT);
5630 break;
5631 case Intrinsic::loongarch_lsx_bz_b:
5632 case Intrinsic::loongarch_lsx_bz_h:
5633 case Intrinsic::loongarch_lsx_bz_w:
5634 case Intrinsic::loongarch_lsx_bz_d:
5635 case Intrinsic::loongarch_lasx_xbz_b:
5636 case Intrinsic::loongarch_lasx_xbz_h:
5637 case Intrinsic::loongarch_lasx_xbz_w:
5638 case Intrinsic::loongarch_lasx_xbz_d:
5639 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5640 LoongArchISD::VALL_ZERO);
5641 break;
5642 case Intrinsic::loongarch_lsx_bz_v:
5643 case Intrinsic::loongarch_lasx_xbz_v:
5644 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5645 LoongArchISD::VANY_ZERO);
5646 break;
5647 case Intrinsic::loongarch_lsx_bnz_b:
5648 case Intrinsic::loongarch_lsx_bnz_h:
5649 case Intrinsic::loongarch_lsx_bnz_w:
5650 case Intrinsic::loongarch_lsx_bnz_d:
5651 case Intrinsic::loongarch_lasx_xbnz_b:
5652 case Intrinsic::loongarch_lasx_xbnz_h:
5653 case Intrinsic::loongarch_lasx_xbnz_w:
5654 case Intrinsic::loongarch_lasx_xbnz_d:
5655 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5656 LoongArchISD::VALL_NONZERO);
5657 break;
5658 case Intrinsic::loongarch_lsx_bnz_v:
5659 case Intrinsic::loongarch_lasx_xbnz_v:
5660 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5661 LoongArchISD::VANY_NONZERO);
5662 break;
5663 }
5664}
5665
5668 SelectionDAG &DAG) {
5669 assert(N->getValueType(0) == MVT::i128 &&
5670 "AtomicCmpSwap on types less than 128 should be legal");
5671 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5672
5673 unsigned Opcode;
5674 switch (MemOp->getMergedOrdering()) {
5678 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5679 break;
5682 Opcode = LoongArch::PseudoCmpXchg128;
5683 break;
5684 default:
5685 llvm_unreachable("Unexpected ordering!");
5686 }
5687
5688 SDLoc DL(N);
5689 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5690 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5691 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5692 NewVal.first, NewVal.second, N->getOperand(0)};
5693
5694 SDNode *CmpSwap = DAG.getMachineNode(
5695 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5696 Ops);
5697 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5698 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5699 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5700 Results.push_back(SDValue(CmpSwap, 3));
5701}
5702
5705 SDLoc DL(N);
5706 EVT VT = N->getValueType(0);
5707 switch (N->getOpcode()) {
5708 default:
5709 llvm_unreachable("Don't know how to legalize this operation");
5710 case ISD::ADD:
5711 case ISD::SUB:
5712 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5713 "Unexpected custom legalisation");
5714 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5715 break;
5716 case ISD::SDIV:
5717 case ISD::UDIV:
5718 case ISD::SREM:
5719 case ISD::UREM:
5720 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5721 "Unexpected custom legalisation");
5722 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5723 Subtarget.hasDiv32() && VT == MVT::i32
5725 : ISD::SIGN_EXTEND));
5726 break;
5727 case ISD::SHL:
5728 case ISD::SRA:
5729 case ISD::SRL:
5730 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5731 "Unexpected custom legalisation");
5732 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5733 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5734 break;
5735 }
5736 break;
5737 case ISD::ROTL:
5738 case ISD::ROTR:
5739 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5740 "Unexpected custom legalisation");
5741 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5742 break;
5743 case ISD::LOAD: {
5744 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5745 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5746 // cast since type legalization will try to use an i64 load.
5747 MVT VT = N->getSimpleValueType(0);
5748 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5749 "Unexpected custom legalisation");
5751 "Unexpected type action!");
5752 if (!ISD::isNON_EXTLoad(N))
5753 return;
5754 auto *Ld = cast<LoadSDNode>(N);
5755 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5756 Ld->getPointerInfo(), Ld->getBaseAlign(),
5757 Ld->getMemOperand()->getFlags());
5758 SDValue Chain = Res.getValue(1);
5759 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5760 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5761 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5762 Res = DAG.getBitcast(WideVT, Res);
5763 Results.push_back(Res);
5764 Results.push_back(Chain);
5765 break;
5766 }
5767 case ISD::FP_TO_SINT: {
5768 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5769 "Unexpected custom legalisation");
5770 SDValue Src = N->getOperand(0);
5771 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5772 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5774 if (!isTypeLegal(Src.getValueType()))
5775 return;
5776 if (Src.getValueType() == MVT::f16)
5777 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5778 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5779 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5780 return;
5781 }
5782 // If the FP type needs to be softened, emit a library call using the 'si'
5783 // version. If we left it to default legalization we'd end up with 'di'.
5784 RTLIB::Libcall LC;
5785 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5786 MakeLibCallOptions CallOptions;
5787 EVT OpVT = Src.getValueType();
5788 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5789 SDValue Chain = SDValue();
5790 SDValue Result;
5791 std::tie(Result, Chain) =
5792 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5793 Results.push_back(Result);
5794 break;
5795 }
5796 case ISD::BITCAST: {
5797 SDValue Src = N->getOperand(0);
5798 EVT SrcVT = Src.getValueType();
5799 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5800 Subtarget.hasBasicF()) {
5801 SDValue Dst =
5802 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5803 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5804 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5805 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5806 DAG.getVTList(MVT::i32, MVT::i32), Src);
5807 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5808 NewReg.getValue(0), NewReg.getValue(1));
5809 Results.push_back(RetReg);
5810 }
5811 break;
5812 }
5813 case ISD::FP_TO_UINT: {
5814 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5815 "Unexpected custom legalisation");
5816 auto &TLI = DAG.getTargetLoweringInfo();
5817 SDValue Tmp1, Tmp2;
5818 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5819 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
5820 break;
5821 }
5822 case ISD::FP_ROUND: {
5823 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5824 "Unexpected custom legalisation");
5825 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
5826 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
5827 // a target-specific LoongArchISD::VFCVT to optimize it.
5828 SDValue Op0 = N->getOperand(0);
5829 EVT OpVT = Op0.getValueType();
5830 if (OpVT == MVT::v2f64) {
5831 SDValue Undef = DAG.getUNDEF(OpVT);
5832 SDValue Dst =
5833 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
5834 Results.push_back(Dst);
5835 }
5836 break;
5837 }
5838 case ISD::BSWAP: {
5839 SDValue Src = N->getOperand(0);
5840 assert((VT == MVT::i16 || VT == MVT::i32) &&
5841 "Unexpected custom legalization");
5842 MVT GRLenVT = Subtarget.getGRLenVT();
5843 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5844 SDValue Tmp;
5845 switch (VT.getSizeInBits()) {
5846 default:
5847 llvm_unreachable("Unexpected operand width");
5848 case 16:
5849 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
5850 break;
5851 case 32:
5852 // Only LA64 will get to here due to the size mismatch between VT and
5853 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
5854 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
5855 break;
5856 }
5857 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5858 break;
5859 }
5860 case ISD::BITREVERSE: {
5861 SDValue Src = N->getOperand(0);
5862 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
5863 "Unexpected custom legalization");
5864 MVT GRLenVT = Subtarget.getGRLenVT();
5865 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5866 SDValue Tmp;
5867 switch (VT.getSizeInBits()) {
5868 default:
5869 llvm_unreachable("Unexpected operand width");
5870 case 8:
5871 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
5872 break;
5873 case 32:
5874 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
5875 break;
5876 }
5877 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5878 break;
5879 }
5880 case ISD::CTLZ:
5881 case ISD::CTTZ: {
5882 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5883 "Unexpected custom legalisation");
5884 Results.push_back(customLegalizeToWOp(N, DAG, 1));
5885 break;
5886 }
5888 SDValue Chain = N->getOperand(0);
5889 SDValue Op2 = N->getOperand(2);
5890 MVT GRLenVT = Subtarget.getGRLenVT();
5891 const StringRef ErrorMsgOOR = "argument out of range";
5892 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5893 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5894
5895 switch (N->getConstantOperandVal(1)) {
5896 default:
5897 llvm_unreachable("Unexpected Intrinsic.");
5898 case Intrinsic::loongarch_movfcsr2gr: {
5899 if (!Subtarget.hasBasicF()) {
5900 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
5901 return;
5902 }
5903 unsigned Imm = Op2->getAsZExtVal();
5904 if (!isUInt<2>(Imm)) {
5905 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5906 return;
5907 }
5908 SDValue MOVFCSR2GRResults = DAG.getNode(
5909 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
5910 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5911 Results.push_back(
5912 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
5913 Results.push_back(MOVFCSR2GRResults.getValue(1));
5914 break;
5915 }
5916#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
5917 case Intrinsic::loongarch_##NAME: { \
5918 SDValue NODE = DAG.getNode( \
5919 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5920 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5921 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5922 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5923 Results.push_back(NODE.getValue(1)); \
5924 break; \
5925 }
5926 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
5927 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
5928 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
5929 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
5930 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
5931 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
5932#undef CRC_CASE_EXT_BINARYOP
5933
5934#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
5935 case Intrinsic::loongarch_##NAME: { \
5936 SDValue NODE = DAG.getNode( \
5937 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5938 {Chain, Op2, \
5939 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5940 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5941 Results.push_back(NODE.getValue(1)); \
5942 break; \
5943 }
5944 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
5945 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
5946#undef CRC_CASE_EXT_UNARYOP
5947#define CSR_CASE(ID) \
5948 case Intrinsic::loongarch_##ID: { \
5949 if (!Subtarget.is64Bit()) \
5950 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
5951 break; \
5952 }
5953 CSR_CASE(csrrd_d);
5954 CSR_CASE(csrwr_d);
5955 CSR_CASE(csrxchg_d);
5956 CSR_CASE(iocsrrd_d);
5957#undef CSR_CASE
5958 case Intrinsic::loongarch_csrrd_w: {
5959 unsigned Imm = Op2->getAsZExtVal();
5960 if (!isUInt<14>(Imm)) {
5961 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5962 return;
5963 }
5964 SDValue CSRRDResults =
5965 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5966 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5967 Results.push_back(
5968 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
5969 Results.push_back(CSRRDResults.getValue(1));
5970 break;
5971 }
5972 case Intrinsic::loongarch_csrwr_w: {
5973 unsigned Imm = N->getConstantOperandVal(3);
5974 if (!isUInt<14>(Imm)) {
5975 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5976 return;
5977 }
5978 SDValue CSRWRResults =
5979 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5980 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5981 DAG.getConstant(Imm, DL, GRLenVT)});
5982 Results.push_back(
5983 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
5984 Results.push_back(CSRWRResults.getValue(1));
5985 break;
5986 }
5987 case Intrinsic::loongarch_csrxchg_w: {
5988 unsigned Imm = N->getConstantOperandVal(4);
5989 if (!isUInt<14>(Imm)) {
5990 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5991 return;
5992 }
5993 SDValue CSRXCHGResults = DAG.getNode(
5994 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5995 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5996 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
5997 DAG.getConstant(Imm, DL, GRLenVT)});
5998 Results.push_back(
5999 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
6000 Results.push_back(CSRXCHGResults.getValue(1));
6001 break;
6002 }
6003#define IOCSRRD_CASE(NAME, NODE) \
6004 case Intrinsic::loongarch_##NAME: { \
6005 SDValue IOCSRRDResults = \
6006 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6007 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
6008 Results.push_back( \
6009 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
6010 Results.push_back(IOCSRRDResults.getValue(1)); \
6011 break; \
6012 }
6013 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
6014 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
6015 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
6016#undef IOCSRRD_CASE
6017 case Intrinsic::loongarch_cpucfg: {
6018 SDValue CPUCFGResults =
6019 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
6020 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
6021 Results.push_back(
6022 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
6023 Results.push_back(CPUCFGResults.getValue(1));
6024 break;
6025 }
6026 case Intrinsic::loongarch_lddir_d: {
6027 if (!Subtarget.is64Bit()) {
6028 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
6029 return;
6030 }
6031 break;
6032 }
6033 }
6034 break;
6035 }
6036 case ISD::READ_REGISTER: {
6037 if (Subtarget.is64Bit())
6038 DAG.getContext()->emitError(
6039 "On LA64, only 64-bit registers can be read.");
6040 else
6041 DAG.getContext()->emitError(
6042 "On LA32, only 32-bit registers can be read.");
6043 Results.push_back(DAG.getUNDEF(VT));
6044 Results.push_back(N->getOperand(0));
6045 break;
6046 }
6048 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
6049 break;
6050 }
6051 case ISD::LROUND: {
6052 SDValue Op0 = N->getOperand(0);
6053 EVT OpVT = Op0.getValueType();
6054 RTLIB::Libcall LC =
6055 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
6056 MakeLibCallOptions CallOptions;
6057 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
6058 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
6059 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
6060 Results.push_back(Result);
6061 break;
6062 }
6063 case ISD::ATOMIC_CMP_SWAP: {
6065 break;
6066 }
6067 case ISD::TRUNCATE: {
6068 MVT VT = N->getSimpleValueType(0);
6069 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
6070 return;
6071
6072 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
6073 SDValue In = N->getOperand(0);
6074 EVT InVT = In.getValueType();
6075 EVT InEltVT = InVT.getVectorElementType();
6076 EVT EltVT = VT.getVectorElementType();
6077 unsigned MinElts = VT.getVectorNumElements();
6078 unsigned WidenNumElts = WidenVT.getVectorNumElements();
6079 unsigned InBits = InVT.getSizeInBits();
6080
6081 // v8i64 -> (v8i32) -> v8i8
6082 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
6083 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
6084 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6085 InBits = 256;
6086 }
6087
6088 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
6089 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
6090 WidenVT.is128BitVector()) {
6091 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
6092 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6093 InBits = 128;
6094 InEltVT = InVT.getVectorElementType();
6095 }
6096
6097 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
6098 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
6099 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
6100 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
6101 for (unsigned I = 0; I < MinElts; ++I)
6102 TruncMask[I] = Scale * I;
6103
6104 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
6105 MVT SVT = In.getSimpleValueType().getScalarType();
6106 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
6107 SDValue WidenIn =
6108 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
6109 DAG.getVectorIdxConstant(0, DL));
6110 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
6111 "Illegal vector type in truncation");
6112 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
6113 Results.push_back(
6114 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
6115 return;
6116 }
6117 }
6118
6119 break;
6120 }
6121 case ISD::SIGN_EXTEND: {
6122 // LASX has native VEXT2XV_* for sign extension.
6123 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
6124 return;
6125
6126 EVT DstVT = N->getValueType(0);
6127 SDValue Src = N->getOperand(0);
6128 MVT SrcVT = Src.getSimpleValueType();
6129
6130 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
6131 unsigned DstEltBits = DstVT.getScalarSizeInBits();
6132 unsigned NumElts = DstVT.getVectorNumElements();
6133
6134 if (SrcVT.getSizeInBits() > 128)
6135 return;
6136
6137 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6138 return;
6139
6140 // Legalize and extend the src to 128-bit first.
6141 if (SrcVT.getSizeInBits() < 128) {
6142 unsigned WidenSrcElts = 128 / SrcEltBits;
6143 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6144 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6145 DAG.getUNDEF(WidenSrcVT), Src,
6146 DAG.getVectorIdxConstant(0, DL));
6147 SrcVT = WidenSrcVT;
6148
6149 unsigned FirstStageEltBits = 128 / NumElts;
6150 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6151 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6152 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6153 SrcVT = FirstStageVT;
6154 SrcEltBits = FirstStageEltBits;
6155 }
6156
6158 Blocks.push_back(Src);
6159
6160 // Sign-extend the src by using SLTI + VILVL + VILVH recursively.
6161 while (SrcEltBits < DstEltBits) {
6162 unsigned NextEltBits = SrcEltBits * 2;
6163 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6164 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6165 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6166 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6167
6168 SmallVector<SDValue, 8> NextBlocks;
6169 NextBlocks.reserve(Blocks.size() * 2);
6170 for (SDValue Block : Blocks) {
6171 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
6172 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Block, Zero,
6173 DAG.getCondCode(ISD::SETLT));
6174 SDValue LoInterleaved =
6175 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Block);
6176 SDValue HiInterleaved =
6177 DAG.getNode(LoongArchISD::VILVH, DL, SrcVT, Mask, Block);
6178
6179 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, LoInterleaved));
6180 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, HiInterleaved));
6181 }
6182
6183 Blocks = std::move(NextBlocks);
6184 SrcVT = NextBlockVT;
6185 SrcEltBits = NextEltBits;
6186 }
6187
6188 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6189 break;
6190 }
6191 case ISD::FP_EXTEND:
6192 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6193 // no target-specific lowering is required. Leave it unchanged and rely on
6194 // the default type legalization.
6195 break;
6196 }
6197}
6198
6199/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6201 SelectionDAG &DAG) {
6202 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6203
6204 MVT VT = N->getSimpleValueType(0);
6205 if (!VT.is128BitVector() && !VT.is256BitVector())
6206 return SDValue();
6207
6208 SDValue X, Y;
6209 SDValue N0 = N->getOperand(0);
6210 SDValue N1 = N->getOperand(1);
6211
6212 if (SDValue Not = isNOT(N0, DAG)) {
6213 X = Not;
6214 Y = N1;
6215 } else if (SDValue Not = isNOT(N1, DAG)) {
6216 X = Not;
6217 Y = N0;
6218 } else
6219 return SDValue();
6220
6221 X = DAG.getBitcast(VT, X);
6222 Y = DAG.getBitcast(VT, Y);
6223 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6224}
6225
6226static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6227 unsigned MinSizeInBits) {
6230
6231 if (!Node)
6232 return false;
6233
6234 APInt SplatUndef;
6235 unsigned SplatBitSize;
6236 bool HasAnyUndefs;
6237
6238 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6239 HasAnyUndefs, MinSizeInBits,
6240 /*IsBigEndian=*/false);
6241}
6242
6243static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6244 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6245 if (!BV)
6246 return SDValue();
6247
6248 SDValue Src;
6249 int Start = -1;
6250
6251 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6252 SDValue Op = BV->getOperand(i);
6253 if (Op.isUndef())
6254 continue;
6255 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6256 return SDValue();
6257
6258 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6259 if (!IdxC)
6260 return SDValue();
6261
6262 unsigned EltIdx = IdxC->getZExtValue();
6263 if (Start < 0)
6264 Start = (int)EltIdx - (int)(i * 2);
6265 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6266 return SDValue();
6267
6268 SDValue CurSrc = Op.getOperand(0);
6269 if (!Src)
6270 Src = CurSrc;
6271 else if (Src != CurSrc)
6272 return SDValue();
6273 }
6274
6275 if (!Src || Start < 0)
6276 return SDValue();
6277
6278 StartIndex = (unsigned)Start;
6279 return Src;
6280}
6281
6282static SDValue
6284 const LoongArchSubtarget &Subtarget) {
6285 if (!Subtarget.hasExtLSX())
6286 return SDValue();
6287
6288 unsigned Opc = N->getOpcode();
6289 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6290
6291 EVT VT = N->getValueType(0);
6292 SDLoc DL(N);
6293
6294 SDValue LHS = N->getOperand(0);
6295 SDValue RHS = N->getOperand(1);
6296
6297 bool isSigned;
6298 unsigned ExtOpc = LHS.getOpcode();
6299 if (ExtOpc == ISD::SIGN_EXTEND)
6300 isSigned = true;
6301 else if (ExtOpc == ISD::ZERO_EXTEND)
6302 isSigned = false;
6303 else
6304 return SDValue();
6305
6306 if (ExtOpc != RHS.getOpcode())
6307 return SDValue();
6308
6309 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6310 return SDValue();
6311
6312 unsigned OddIdx, EvenIdx;
6313 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6314 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6315
6316 if (!LHSVec || !RHSVec)
6317 return SDValue();
6318 if (OddIdx != 1 || EvenIdx != 0)
6319 return SDValue();
6320 if (LHSVec.getValueType() != RHSVec.getValueType())
6321 return SDValue();
6322
6323 EVT SrcVT = LHSVec.getValueType();
6324 EVT SrcEltVT = SrcVT.getVectorElementType();
6325 EVT DstEltVT = VT.getVectorElementType();
6326 auto &TLI = DAG.getTargetLoweringInfo();
6327
6328 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6329 return SDValue();
6330 if (!SrcVT.isVector() || !VT.isVector())
6331 return SDValue();
6332 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6333 return SDValue();
6334 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6335 return SDValue();
6336 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6337 return SDValue();
6338
6339 unsigned TargetOpc;
6340 if (Opc == ISD::ADD)
6341 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6342 else
6343 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6344
6345 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6346}
6347
6350 const LoongArchSubtarget &Subtarget) {
6351 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6352 return V;
6353
6354 if (DCI.isBeforeLegalizeOps())
6355 return SDValue();
6356
6357 EVT VT = N->getValueType(0);
6358 if (!VT.isVector())
6359 return SDValue();
6360
6361 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6362 return SDValue();
6363
6364 EVT EltVT = VT.getVectorElementType();
6365 if (!EltVT.isInteger())
6366 return SDValue();
6367
6368 // match:
6369 //
6370 // add
6371 // (and
6372 // (srl X, shift-1) / X
6373 // 1)
6374 // (srl/sra X, shift)
6375
6376 SDValue Add0 = N->getOperand(0);
6377 SDValue Add1 = N->getOperand(1);
6378 SDValue And;
6379 SDValue Shr;
6380
6381 if (Add0.getOpcode() == ISD::AND) {
6382 And = Add0;
6383 Shr = Add1;
6384 } else if (Add1.getOpcode() == ISD::AND) {
6385 And = Add1;
6386 Shr = Add0;
6387 } else {
6388 return SDValue();
6389 }
6390
6391 // match:
6392 //
6393 // srl/sra X, shift
6394
6395 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6396 return SDValue();
6397
6398 SDValue X = Shr.getOperand(0);
6399 SDValue Shift = Shr.getOperand(1);
6400 APInt ShiftVal;
6401
6402 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6403 return SDValue();
6404
6405 if (ShiftVal == 0)
6406 return SDValue();
6407
6408 // match:
6409 //
6410 // and
6411 // (srl X, shift-1) / X
6412 // 1
6413
6414 SDValue One = And.getOperand(1);
6415 APInt SplatVal;
6416
6417 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6418 return SDValue();
6419
6420 if (SplatVal != 1)
6421 return SDValue();
6422
6423 if (And.getOperand(0) == X) {
6424 // match:
6425 //
6426 // shift == 1
6427
6428 if (ShiftVal != 1)
6429 return SDValue();
6430 } else {
6431 // match:
6432 //
6433 // srl X, shift-1
6434
6435 SDValue Srl = And.getOperand(0);
6436
6437 if (Srl.getOpcode() != ISD::SRL)
6438 return SDValue();
6439
6440 if (Srl.getOperand(0) != X)
6441 return SDValue();
6442
6443 // match:
6444 //
6445 // shift-1
6446
6447 SDValue ShiftMinus1 = Srl.getOperand(1);
6448
6449 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6450 return SDValue();
6451
6452 if (ShiftVal != (SplatVal + 1))
6453 return SDValue();
6454 }
6455
6456 // We matched a rounded right shift pattern and can lower it
6457 // to a single vector rounded shift instruction.
6458
6459 SDLoc DL(N);
6460 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6461 : LoongArchISD::VSRAR,
6462 DL, VT, X, Shift);
6463}
6464
6467 const LoongArchSubtarget &Subtarget) {
6468 if (DCI.isBeforeLegalizeOps())
6469 return SDValue();
6470
6471 SDValue FirstOperand = N->getOperand(0);
6472 SDValue SecondOperand = N->getOperand(1);
6473 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6474 EVT ValTy = N->getValueType(0);
6475 SDLoc DL(N);
6476 uint64_t lsb, msb;
6477 unsigned SMIdx, SMLen;
6478 ConstantSDNode *CN;
6479 SDValue NewOperand;
6480 MVT GRLenVT = Subtarget.getGRLenVT();
6481
6482 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6483 return R;
6484
6485 // BSTRPICK requires the 32S feature.
6486 if (!Subtarget.has32S())
6487 return SDValue();
6488
6489 // Op's second operand must be a shifted mask.
6490 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6491 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6492 return SDValue();
6493
6494 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6495 // Pattern match BSTRPICK.
6496 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6497 // => BSTRPICK $dst, $src, msb, lsb
6498 // where msb = lsb + len - 1
6499
6500 // The second operand of the shift must be an immediate.
6501 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6502 return SDValue();
6503
6504 lsb = CN->getZExtValue();
6505
6506 // Return if the shifted mask does not start at bit 0 or the sum of its
6507 // length and lsb exceeds the word's size.
6508 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6509 return SDValue();
6510
6511 NewOperand = FirstOperand.getOperand(0);
6512 } else {
6513 // Pattern match BSTRPICK.
6514 // $dst = and $src, (2**len- 1) , if len > 12
6515 // => BSTRPICK $dst, $src, msb, lsb
6516 // where lsb = 0 and msb = len - 1
6517
6518 // If the mask is <= 0xfff, andi can be used instead.
6519 if (CN->getZExtValue() <= 0xfff)
6520 return SDValue();
6521
6522 // Return if the MSB exceeds.
6523 if (SMIdx + SMLen > ValTy.getSizeInBits())
6524 return SDValue();
6525
6526 if (SMIdx > 0) {
6527 // Omit if the constant has more than 2 uses. This a conservative
6528 // decision. Whether it is a win depends on the HW microarchitecture.
6529 // However it should always be better for 1 and 2 uses.
6530 if (CN->use_size() > 2)
6531 return SDValue();
6532 // Return if the constant can be composed by a single LU12I.W.
6533 if ((CN->getZExtValue() & 0xfff) == 0)
6534 return SDValue();
6535 // Return if the constand can be composed by a single ADDI with
6536 // the zero register.
6537 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6538 return SDValue();
6539 }
6540
6541 lsb = SMIdx;
6542 NewOperand = FirstOperand;
6543 }
6544
6545 msb = lsb + SMLen - 1;
6546 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6547 DAG.getConstant(msb, DL, GRLenVT),
6548 DAG.getConstant(lsb, DL, GRLenVT));
6549 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6550 return NR0;
6551 // Try to optimize to
6552 // bstrpick $Rd, $Rs, msb, lsb
6553 // slli $Rd, $Rd, lsb
6554 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6555 DAG.getConstant(lsb, DL, GRLenVT));
6556}
6557
6558// Return the original source vector if N consists of the half
6559// of each 128-bit lane.
6562
6563 EVT DstVT = N.getValueType();
6564 if (!DstVT.isVector())
6565 return SDValue();
6566
6567 unsigned NumElts = DstVT.getVectorNumElements();
6568
6569 // LSX canonical form:
6570 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6571 SDValue Src = N.getOperand(0);
6572 EVT SrcVT = Src.getValueType();
6573
6574 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6575 return SDValue();
6576 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6577 return SDValue();
6578 if (SrcVT.getVectorNumElements() != NumElts * 2)
6579 return SDValue();
6580 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6581 return SDValue();
6582
6583 return Src;
6584 }
6585
6586 // LASX canonical form:
6587 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6588 if (!BV)
6589 return SDValue();
6590
6591 if (NumElts % 2 != 0)
6592 return SDValue();
6593
6594 SDValue Src;
6595 EVT SrcVT;
6596
6597 for (unsigned I = 0; I != NumElts; ++I) {
6598 SDValue Elt = BV->getOperand(I);
6599 if (Elt.isUndef())
6600 continue;
6602 return SDValue();
6603
6604 SDValue ThisSrc = Elt.getOperand(0);
6605 SDValue Idx = Elt.getOperand(1);
6606 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6607 if (!CI)
6608 return SDValue();
6609
6610 if (!Src) {
6611 Src = ThisSrc;
6612 SrcVT = Src.getValueType();
6613 if (!SrcVT.isVector())
6614 return SDValue();
6615
6616 if (!SrcVT.is256BitVector())
6617 return SDValue();
6618 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6619 return SDValue();
6620 if (SrcVT.getVectorNumElements() != NumElts * 2)
6621 return SDValue();
6622 } else if (ThisSrc != Src) {
6623 return SDValue();
6624 }
6625
6626 unsigned Half = NumElts / 2;
6627 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6628 ExpectedIdx += isLow ? 0 : Half;
6629
6630 if (CI->getZExtValue() != ExpectedIdx)
6631 return SDValue();
6632 }
6633
6634 return Src;
6635}
6636
6639 const LoongArchSubtarget &Subtarget) {
6640 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6641
6642 EVT VT = N->getValueType(0);
6643 SDLoc DL(N);
6644
6645 SDValue LHS = N->getOperand(0);
6646 SDValue RHS = N->getOperand(1);
6647
6648 bool isSigned;
6649 unsigned ExtOpc = LHS.getOpcode();
6650 if (ExtOpc == ISD::SIGN_EXTEND)
6651 isSigned = true;
6652 else if (ExtOpc == ISD::ZERO_EXTEND)
6653 isSigned = false;
6654 else
6655 return SDValue();
6656
6657 if (!LHS.hasOneUse())
6658 return SDValue();
6659
6660 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
6661 N->getValueSizeInBits(0) != LHS->getOperand(0).getValueSizeInBits() * 2)
6662 return SDValue();
6663
6664 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6665 if (!Vec)
6666 return SDValue();
6667
6668 EVT SrcVT = Vec.getValueType();
6669 EVT SrcEltVT = SrcVT.getVectorElementType();
6670 EVT DstEltVT = VT.getVectorElementType();
6671 APInt Imm;
6672 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6673 return SDValue();
6674 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6675 return SDValue();
6676
6677 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6678 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6679 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6680}
6681
6684 const LoongArchSubtarget &Subtarget) {
6685 // BSTRPICK requires the 32S feature.
6686 if (!Subtarget.has32S())
6687 return SDValue();
6688
6689 if (DCI.isBeforeLegalizeOps())
6690 return SDValue();
6691
6692 // $dst = srl (and $src, Mask), Shamt
6693 // =>
6694 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6695 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6696 //
6697
6698 SDValue FirstOperand = N->getOperand(0);
6699 ConstantSDNode *CN;
6700 EVT ValTy = N->getValueType(0);
6701 SDLoc DL(N);
6702 MVT GRLenVT = Subtarget.getGRLenVT();
6703 unsigned MaskIdx, MaskLen;
6704 uint64_t Shamt;
6705
6706 // The first operand must be an AND and the second operand of the AND must be
6707 // a shifted mask.
6708 if (FirstOperand.getOpcode() != ISD::AND ||
6709 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6710 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6711 return SDValue();
6712
6713 // The second operand (shift amount) must be an immediate.
6714 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6715 return SDValue();
6716
6717 Shamt = CN->getZExtValue();
6718 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6719 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6720 FirstOperand->getOperand(0),
6721 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6722 DAG.getConstant(Shamt, DL, GRLenVT));
6723
6724 return SDValue();
6725}
6726
6729 const LoongArchSubtarget &Subtarget) {
6730 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6731 return V;
6732
6733 return SDValue();
6734}
6735
6736// Helper to peek through bitops/trunc/setcc to determine size of source vector.
6737// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
6738static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
6739 unsigned Depth) {
6740 // Limit recursion.
6742 return false;
6743 switch (Src.getOpcode()) {
6744 case ISD::SETCC:
6745 case ISD::TRUNCATE:
6746 return Src.getOperand(0).getValueSizeInBits() == Size;
6747 case ISD::FREEZE:
6748 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
6749 case ISD::AND:
6750 case ISD::XOR:
6751 case ISD::OR:
6752 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
6753 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
6754 case ISD::SELECT:
6755 case ISD::VSELECT:
6756 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
6757 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
6758 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
6759 case ISD::BUILD_VECTOR:
6760 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
6761 ISD::isBuildVectorAllOnes(Src.getNode());
6762 }
6763 return false;
6764}
6765
6766// Helper to push sign extension of vXi1 SETCC result through bitops.
6768 SDValue Src, const SDLoc &DL) {
6769 switch (Src.getOpcode()) {
6770 case ISD::SETCC:
6771 case ISD::FREEZE:
6772 case ISD::TRUNCATE:
6773 case ISD::BUILD_VECTOR:
6774 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6775 case ISD::AND:
6776 case ISD::XOR:
6777 case ISD::OR:
6778 return DAG.getNode(
6779 Src.getOpcode(), DL, SExtVT,
6780 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
6781 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
6782 case ISD::SELECT:
6783 case ISD::VSELECT:
6784 return DAG.getSelect(
6785 DL, SExtVT, Src.getOperand(0),
6786 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
6787 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
6788 }
6789 llvm_unreachable("Unexpected node type for vXi1 sign extension");
6790}
6791
6792static SDValue
6795 const LoongArchSubtarget &Subtarget) {
6796 SDLoc DL(N);
6797 EVT VT = N->getValueType(0);
6798 SDValue Src = N->getOperand(0);
6799 EVT SrcVT = Src.getValueType();
6800
6801 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
6802 return SDValue();
6803
6804 bool UseLASX;
6805 unsigned Opc = ISD::DELETED_NODE;
6806 EVT CmpVT = Src.getOperand(0).getValueType();
6807 EVT EltVT = CmpVT.getVectorElementType();
6808
6809 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
6810 UseLASX = false;
6811 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
6812 CmpVT.getSizeInBits() == 256)
6813 UseLASX = true;
6814 else
6815 return SDValue();
6816
6817 SDValue SrcN1 = Src.getOperand(1);
6818 switch (cast<CondCodeSDNode>(Src.getOperand(2))->get()) {
6819 default:
6820 break;
6821 case ISD::SETEQ:
6822 // x == 0 => not (vmsknez.b x)
6823 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6824 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
6825 break;
6826 case ISD::SETGT:
6827 // x > -1 => vmskgez.b x
6828 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
6829 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6830 break;
6831 case ISD::SETGE:
6832 // x >= 0 => vmskgez.b x
6833 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6834 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6835 break;
6836 case ISD::SETLT:
6837 // x < 0 => vmskltz.{b,h,w,d} x
6838 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
6839 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6840 EltVT == MVT::i64))
6841 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6842 break;
6843 case ISD::SETLE:
6844 // x <= -1 => vmskltz.{b,h,w,d} x
6845 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
6846 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6847 EltVT == MVT::i64))
6848 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6849 break;
6850 case ISD::SETNE:
6851 // x != 0 => vmsknez.b x
6852 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6853 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
6854 break;
6855 }
6856
6857 if (Opc == ISD::DELETED_NODE)
6858 return SDValue();
6859
6860 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
6862 V = DAG.getZExtOrTrunc(V, DL, T);
6863 return DAG.getBitcast(VT, V);
6864}
6865
6868 const LoongArchSubtarget &Subtarget) {
6869 SDLoc DL(N);
6870 EVT VT = N->getValueType(0);
6871 SDValue Src = N->getOperand(0);
6872 EVT SrcVT = Src.getValueType();
6873 MVT GRLenVT = Subtarget.getGRLenVT();
6874
6875 if (!DCI.isBeforeLegalizeOps())
6876 return SDValue();
6877
6878 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
6879 return SDValue();
6880
6881 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
6882 SDValue Res = performSETCC_BITCASTCombine(N, DAG, DCI, Subtarget);
6883 if (Res)
6884 return Res;
6885
6886 // Generate vXi1 using [X]VMSKLTZ
6887 MVT SExtVT;
6888 unsigned Opc;
6889 bool UseLASX = false;
6890 bool PropagateSExt = false;
6891
6892 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
6893 EVT CmpVT = Src.getOperand(0).getValueType();
6894 if (CmpVT.getSizeInBits() > 256)
6895 return SDValue();
6896 }
6897
6898 switch (SrcVT.getSimpleVT().SimpleTy) {
6899 default:
6900 return SDValue();
6901 case MVT::v2i1:
6902 SExtVT = MVT::v2i64;
6903 break;
6904 case MVT::v4i1:
6905 SExtVT = MVT::v4i32;
6906 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6907 SExtVT = MVT::v4i64;
6908 UseLASX = true;
6909 PropagateSExt = true;
6910 }
6911 break;
6912 case MVT::v8i1:
6913 SExtVT = MVT::v8i16;
6914 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6915 SExtVT = MVT::v8i32;
6916 UseLASX = true;
6917 PropagateSExt = true;
6918 }
6919 break;
6920 case MVT::v16i1:
6921 SExtVT = MVT::v16i8;
6922 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6923 SExtVT = MVT::v16i16;
6924 UseLASX = true;
6925 PropagateSExt = true;
6926 }
6927 break;
6928 case MVT::v32i1:
6929 SExtVT = MVT::v32i8;
6930 UseLASX = true;
6931 break;
6932 };
6933 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
6934 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6935
6936 SDValue V;
6937 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
6938 if (Src.getSimpleValueType() == MVT::v32i8) {
6939 SDValue Lo, Hi;
6940 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
6941 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
6942 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
6943 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
6944 DAG.getShiftAmountConstant(16, GRLenVT, DL));
6945 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
6946 } else if (UseLASX) {
6947 return SDValue();
6948 }
6949 }
6950
6951 if (!V) {
6952 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6953 V = DAG.getNode(Opc, DL, GRLenVT, Src);
6954 }
6955
6957 V = DAG.getZExtOrTrunc(V, DL, T);
6958 return DAG.getBitcast(VT, V);
6959}
6960
6963 const LoongArchSubtarget &Subtarget) {
6964 MVT GRLenVT = Subtarget.getGRLenVT();
6965 EVT ValTy = N->getValueType(0);
6966 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
6967 ConstantSDNode *CN0, *CN1;
6968 SDLoc DL(N);
6969 unsigned ValBits = ValTy.getSizeInBits();
6970 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
6971 unsigned Shamt;
6972 bool SwapAndRetried = false;
6973
6974 // BSTRPICK requires the 32S feature.
6975 if (!Subtarget.has32S())
6976 return SDValue();
6977
6978 if (DCI.isBeforeLegalizeOps())
6979 return SDValue();
6980
6981 if (ValBits != 32 && ValBits != 64)
6982 return SDValue();
6983
6984Retry:
6985 // 1st pattern to match BSTRINS:
6986 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
6987 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
6988 // =>
6989 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6990 if (N0.getOpcode() == ISD::AND &&
6991 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6992 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6993 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
6994 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6995 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6996 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
6997 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6998 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6999 (MaskIdx0 + MaskLen0 <= ValBits)) {
7000 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
7001 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7002 N1.getOperand(0).getOperand(0),
7003 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7004 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7005 }
7006
7007 // 2nd pattern to match BSTRINS:
7008 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
7009 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
7010 // =>
7011 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
7012 if (N0.getOpcode() == ISD::AND &&
7013 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7014 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7015 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7016 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7017 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
7018 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7019 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
7020 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
7021 (MaskIdx0 + MaskLen0 <= ValBits)) {
7022 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
7023 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7024 N1.getOperand(0).getOperand(0),
7025 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7026 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7027 }
7028
7029 // 3rd pattern to match BSTRINS:
7030 // R = or (and X, mask0), (and Y, mask1)
7031 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
7032 // =>
7033 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
7034 // where msb = lsb + size - 1
7035 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
7036 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7037 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7038 (MaskIdx0 + MaskLen0 <= 64) &&
7039 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
7040 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7041 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
7042 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7043 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
7044 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
7045 DAG.getConstant(ValBits == 32
7046 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7047 : (MaskIdx0 + MaskLen0 - 1),
7048 DL, GRLenVT),
7049 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7050 }
7051
7052 // 4th pattern to match BSTRINS:
7053 // R = or (and X, mask), (shl Y, shamt)
7054 // where mask = (2**shamt - 1)
7055 // =>
7056 // R = BSTRINS X, Y, ValBits - 1, shamt
7057 // where ValBits = 32 or 64
7058 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
7059 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7060 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
7061 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7062 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
7063 (MaskIdx0 + MaskLen0 <= ValBits)) {
7064 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
7065 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7066 N1.getOperand(0),
7067 DAG.getConstant((ValBits - 1), DL, GRLenVT),
7068 DAG.getConstant(Shamt, DL, GRLenVT));
7069 }
7070
7071 // 5th pattern to match BSTRINS:
7072 // R = or (and X, mask), const
7073 // where ~mask = (2**size - 1) << lsb, mask & const = 0
7074 // =>
7075 // R = BSTRINS X, (const >> lsb), msb, lsb
7076 // where msb = lsb + size - 1
7077 if (N0.getOpcode() == ISD::AND &&
7078 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7079 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7080 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
7081 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7082 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
7083 return DAG.getNode(
7084 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7085 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
7086 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7087 : (MaskIdx0 + MaskLen0 - 1),
7088 DL, GRLenVT),
7089 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7090 }
7091
7092 // 6th pattern.
7093 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
7094 // by the incoming bits are known to be zero.
7095 // =>
7096 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
7097 //
7098 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
7099 // pattern is more common than the 1st. So we put the 1st before the 6th in
7100 // order to match as many nodes as possible.
7101 ConstantSDNode *CNMask, *CNShamt;
7102 unsigned MaskIdx, MaskLen;
7103 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7104 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7105 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7106 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7107 CNShamt->getZExtValue() + MaskLen <= ValBits) {
7108 Shamt = CNShamt->getZExtValue();
7109 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
7110 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7111 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
7112 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7113 N1.getOperand(0).getOperand(0),
7114 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
7115 DAG.getConstant(Shamt, DL, GRLenVT));
7116 }
7117 }
7118
7119 // 7th pattern.
7120 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
7121 // overwritten by the incoming bits are known to be zero.
7122 // =>
7123 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7124 //
7125 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7126 // before the 7th in order to match as many nodes as possible.
7127 if (N1.getOpcode() == ISD::AND &&
7128 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7129 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7130 N1.getOperand(0).getOpcode() == ISD::SHL &&
7131 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7132 CNShamt->getZExtValue() == MaskIdx) {
7133 APInt ShMask(ValBits, CNMask->getZExtValue());
7134 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7135 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7136 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7137 N1.getOperand(0).getOperand(0),
7138 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7139 DAG.getConstant(MaskIdx, DL, GRLenVT));
7140 }
7141 }
7142
7143 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7144 if (!SwapAndRetried) {
7145 std::swap(N0, N1);
7146 SwapAndRetried = true;
7147 goto Retry;
7148 }
7149
7150 SwapAndRetried = false;
7151Retry2:
7152 // 8th pattern.
7153 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7154 // the incoming bits are known to be zero.
7155 // =>
7156 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7157 //
7158 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7159 // we put it here in order to match as many nodes as possible or generate less
7160 // instructions.
7161 if (N1.getOpcode() == ISD::AND &&
7162 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7163 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7164 APInt ShMask(ValBits, CNMask->getZExtValue());
7165 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7166 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7167 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7168 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7169 N1->getOperand(0),
7170 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7171 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7172 DAG.getConstant(MaskIdx, DL, GRLenVT));
7173 }
7174 }
7175 // Swap N0/N1 and retry.
7176 if (!SwapAndRetried) {
7177 std::swap(N0, N1);
7178 SwapAndRetried = true;
7179 goto Retry2;
7180 }
7181
7182 return SDValue();
7183}
7184
7185static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
7186 ExtType = ISD::NON_EXTLOAD;
7187
7188 switch (V.getNode()->getOpcode()) {
7189 case ISD::LOAD: {
7190 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7191 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7192 (LoadNode->getMemoryVT() == MVT::i16)) {
7193 ExtType = LoadNode->getExtensionType();
7194 return true;
7195 }
7196 return false;
7197 }
7198 case ISD::AssertSext: {
7199 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7200 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7201 ExtType = ISD::SEXTLOAD;
7202 return true;
7203 }
7204 return false;
7205 }
7206 case ISD::AssertZext: {
7207 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7208 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7209 ExtType = ISD::ZEXTLOAD;
7210 return true;
7211 }
7212 return false;
7213 }
7214 default:
7215 return false;
7216 }
7217
7218 return false;
7219}
7220
7221// Fold a lane-mask extraction that is only compared against zero into one of
7222// all-lane check instructions, which write the results into fcc register, so
7223// BCEQZ could use it directly.
7224//
7225// (VMSKLTZ X) != 0 -> VSETNEZ.V X
7226// (VMSKLTZ X) == 0 -> VSETEQZ.V X
7227//
7228// This is valid when X is the result of a vector compare instruction,
7229// so each lane of X has to be all-ones or all-zeros.
7231 const SDLoc &DL, SelectionDAG &DAG,
7232 const LoongArchSubtarget &Subtarget) {
7233 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7234 return SDValue();
7235 if (!isNullConstant(RHS))
7236 return SDValue();
7237
7238 unsigned MskOpc = LHS.getOpcode();
7239 if (MskOpc != LoongArchISD::VMSKLTZ && MskOpc != LoongArchISD::XVMSKLTZ)
7240 return SDValue();
7241 // Keeping the mask alive for another user would defeat the purpose.
7242 if (!LHS.hasOneUse())
7243 return SDValue();
7244
7245 SDValue Src = LHS.getOperand(0);
7246 EVT SrcVT = Src.getValueType();
7247 // Make sure every lane is all-ones or all-zeros.
7248 if (!SrcVT.isVector() ||
7249 DAG.ComputeNumSignBits(Src) != SrcVT.getScalarSizeInBits())
7250 return SDValue();
7251
7252 return DAG.getNode(CC == ISD::SETNE ? LoongArchISD::VANYNONZERO
7253 : LoongArchISD::VALLZERO,
7254 DL, Subtarget.getGRLenVT(), Src);
7255}
7256
7257// Eliminate redundant truncation and zero-extension nodes.
7258// * Case 1:
7259// +------------+ +------------+ +------------+
7260// | Input1 | | Input2 | | CC |
7261// +------------+ +------------+ +------------+
7262// | | |
7263// V V +----+
7264// +------------+ +------------+ |
7265// | TRUNCATE | | TRUNCATE | |
7266// +------------+ +------------+ |
7267// | | |
7268// V V |
7269// +------------+ +------------+ |
7270// | ZERO_EXT | | ZERO_EXT | |
7271// +------------+ +------------+ |
7272// | | |
7273// | +-------------+ |
7274// V V | |
7275// +----------------+ | |
7276// | AND | | |
7277// +----------------+ | |
7278// | | |
7279// +---------------+ | |
7280// | | |
7281// V V V
7282// +-------------+
7283// | CMP |
7284// +-------------+
7285// * Case 2:
7286// +------------+ +------------+ +-------------+ +------------+ +------------+
7287// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7288// +------------+ +------------+ +-------------+ +------------+ +------------+
7289// | | | | |
7290// V | | | |
7291// +------------+ | | | |
7292// | XOR |<---------------------+ | |
7293// +------------+ | | |
7294// | | | |
7295// V V +---------------+ |
7296// +------------+ +------------+ | |
7297// | TRUNCATE | | TRUNCATE | | +-------------------------+
7298// +------------+ +------------+ | |
7299// | | | |
7300// V V | |
7301// +------------+ +------------+ | |
7302// | ZERO_EXT | | ZERO_EXT | | |
7303// +------------+ +------------+ | |
7304// | | | |
7305// V V | |
7306// +----------------+ | |
7307// | AND | | |
7308// +----------------+ | |
7309// | | |
7310// +---------------+ | |
7311// | | |
7312// V V V
7313// +-------------+
7314// | CMP |
7315// +-------------+
7318 const LoongArchSubtarget &Subtarget) {
7319 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
7320
7321 if (N->getValueType(0) == Subtarget.getGRLenVT())
7322 if (SDValue V = foldVMskZeroTest(N->getOperand(0), N->getOperand(1), CC,
7323 SDLoc(N), DAG, Subtarget))
7324 return V;
7325
7326 SDNode *AndNode = N->getOperand(0).getNode();
7327 if (AndNode->getOpcode() != ISD::AND)
7328 return SDValue();
7329
7330 SDValue AndInputValue2 = AndNode->getOperand(1);
7331 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7332 return SDValue();
7333
7334 SDValue CmpInputValue = N->getOperand(1);
7335 SDValue AndInputValue1 = AndNode->getOperand(0);
7336 if (AndInputValue1.getOpcode() == ISD::XOR) {
7337 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7338 return SDValue();
7339 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7340 if (!CN || !CN->isAllOnes())
7341 return SDValue();
7342 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7343 if (!CN || !CN->isZero())
7344 return SDValue();
7345 AndInputValue1 = AndInputValue1.getOperand(0);
7346 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7347 return SDValue();
7348 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7349 if (AndInputValue2 != CmpInputValue)
7350 return SDValue();
7351 } else {
7352 return SDValue();
7353 }
7354
7355 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7356 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7357 return SDValue();
7358
7359 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7360 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7361 return SDValue();
7362
7363 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7364 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7365 ISD::LoadExtType ExtType1;
7366 ISD::LoadExtType ExtType2;
7367
7368 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7369 !checkValueWidth(TruncInputValue2, ExtType2))
7370 return SDValue();
7371
7372 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7373 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7374 return SDValue();
7375
7376 if ((ExtType2 != ISD::ZEXTLOAD) &&
7377 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7378 return SDValue();
7379
7380 // These truncation and zero-extension nodes are not necessary, remove them.
7381 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7382 TruncInputValue1, TruncInputValue2);
7383 SDValue NewSetCC =
7384 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7385 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7386 return SDValue(N, 0);
7387}
7388
7389// Strip a single outer ISD::SIGN_EXTEND_INREG from \p V, if present, and
7390// return the inner value together with the narrow VT it was extending
7391// from. If no such node is present, returns \p V unchanged and an invalid
7392// EVT.
7393//
7394// i32 (and other sub-GRLen) arithmetic is legalized to operate on the full
7395// GRLen-width register, with a `sign_extend_inreg` re-normalizing the
7396// result back into the narrow type's range afterwards (see e.g. the
7397// `add i32` -> `add` + `sign_extend_inreg ..., i32` legalization). Any
7398// combine that reassociates such a binop must track and reapply this
7399// extension, otherwise the transformed code can produce a value whose
7400// high bits no longer match the narrow-type semantics.
7401static std::pair<SDValue, EVT> stripSignExtendInReg(SDValue V) {
7402 if (V.getOpcode() == ISD::SIGN_EXTEND_INREG)
7403 return {V.getOperand(0), cast<VTSDNode>(V.getOperand(1))->getVT()};
7404 return {V, EVT()};
7405}
7406
7407// Try to match \p BinV (after optionally stripping an outer
7408// sign_extend_inreg) as a supported binary operation that has \p X as one
7409// of its operands, returning the matched opcode, the other operand (the
7410// "delta"), and the narrow VT of the sign_extend_inreg that was stripped
7411// (invalid EVT if none was present).
7412//
7413// For commutative ops (add/or/xor), \p X may be either operand, since
7414// `binop(X, Y) == binop(Y, X)` and the identity element (0) works on
7415// either side.
7416//
7417// For `sub`, the operation is NOT commutative: `sub(X, Y) != sub(Y, X)`.
7418// Only `sub(X, Y)` (i.e. \p X is the *minuend*, the first operand) can be
7419// rewritten using the identity `X - 0 == X`. If \p X were the *subtrahend*
7420// (second operand, i.e. the pattern is actually `sub(Y, X)`), there is no
7421// way to express `cond ? (Y - X) : X` (or the symmetric case) as
7422// `X op (select ...)` without introducing an extra negation, so that case
7423// must be rejected instead of "optimized" into worse code.
7424static std::tuple<unsigned, SDValue, EVT>
7426 auto [Inner, ExtVT] = stripSignExtendInReg(BinV);
7427
7428 unsigned Opc = Inner.getOpcode();
7429 switch (Opc) {
7430 case ISD::ADD:
7431 case ISD::OR:
7432 case ISD::XOR:
7433 if (Inner.getOperand(0) == X)
7434 return {Opc, Inner.getOperand(1), ExtVT};
7435 if (Inner.getOperand(1) == X)
7436 return {Opc, Inner.getOperand(0), ExtVT};
7437 return {0, SDValue(), EVT()};
7438 case ISD::SUB:
7439 // Only accept X as the minuend (first operand); see comment above.
7440 if (Inner.getOperand(0) == X)
7441 return {Opc, Inner.getOperand(1), ExtVT};
7442 return {0, SDValue(), EVT()};
7443 default:
7444 return {0, SDValue(), EVT()};
7445 }
7446}
7447
7448// Try to combine:
7449// select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
7450// select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
7451// for binop in {add, or, xor, sub}, where 0 is the identity element of the
7452// respective operation, additionally handling the common legalized form
7453// where the binop result is wrapped in a `sign_extend_inreg` (as happens
7454// for sub-GRLen types such as i32 on a 64-bit GRLen target). See
7455// matchBinOpWithSharedOperand() for the restrictions applied to
7456// non-commutative operations (currently only `sub`).
7459 const LoongArchSubtarget &Subtarget) {
7460 if (DCI.isBeforeLegalizeOps())
7461 return SDValue();
7462
7463 EVT VT = N->getValueType(0);
7464 // Restrict to the scalar GRLen integer type that maskeqz/masknez operate
7465 // on; this also naturally excludes float and vector selects.
7466 if (VT != Subtarget.getGRLenVT())
7467 return SDValue();
7468
7469 SDValue Cond = N->getOperand(0);
7470 SDValue TrueV = N->getOperand(1);
7471 SDValue FalseV = N->getOperand(2);
7472 SDLoc DL(N);
7473
7474 auto TryFold = [&](SDValue BinV, SDValue SharedV,
7475 bool BinIsTrueArm) -> SDValue {
7476 auto [Opc, Delta, ExtVT] = matchBinOpWithSharedOperand(BinV, SharedV);
7477 if (!Opc)
7478 return SDValue();
7479
7480 // Avoid infinite combine loops: bail out if Delta is trivially the
7481 // same node we would otherwise be selecting on (shouldn't normally
7482 // happen, but guards against degenerate/self-referential IR).
7483 if (Delta.getNode() == N)
7484 return SDValue();
7485
7486 SDValue Zero = DAG.getConstant(0, DL, VT);
7487 SDValue NewSel = BinIsTrueArm ? DAG.getSelect(DL, VT, Cond, Delta, Zero)
7488 : DAG.getSelect(DL, VT, Cond, Zero, Delta);
7489 SDValue NewBin = DAG.getNode(Opc, DL, VT, SharedV, NewSel);
7490
7491 // If the original binop result was normalized back into a narrower
7492 // type via sign_extend_inreg (e.g. i32 arithmetic on a 64-bit GRLen
7493 // target), the new binop must be re-normalized the same way: SharedV
7494 // is already known-sign-extended for that narrow type, but NewSel
7495 // (Delta or 0, selected) combined with SharedV via Opc can still
7496 // produce a 64-bit result whose high bits don't match the narrow
7497 // type's sign-extended representation.
7498 if (ExtVT != EVT())
7499 NewBin = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, NewBin,
7500 DAG.getValueType(ExtVT));
7501
7502 return NewBin;
7503 };
7504
7505 if (SDValue R = TryFold(TrueV, FalseV, /*BinIsTrueArm=*/true))
7506 return R;
7507 if (SDValue R = TryFold(FalseV, TrueV, /*BinIsTrueArm=*/false))
7508 return R;
7509
7510 return SDValue();
7511}
7512
7513// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7516 const LoongArchSubtarget &Subtarget) {
7517 if (DCI.isBeforeLegalizeOps())
7518 return SDValue();
7519
7520 SDValue Src = N->getOperand(0);
7521 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7522 return SDValue();
7523
7524 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7525 Src.getOperand(0));
7526}
7527
7528// Perform common combines for BR_CC and SELECT_CC conditions.
7529static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7530 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
7531 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7532
7533 // As far as arithmetic right shift always saves the sign,
7534 // shift can be omitted.
7535 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7536 // setge (sra X, N), 0 -> setge X, 0
7537 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7538 LHS.getOpcode() == ISD::SRA) {
7539 LHS = LHS.getOperand(0);
7540 return true;
7541 }
7542
7543 if (!ISD::isIntEqualitySetCC(CCVal))
7544 return false;
7545
7546 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7547 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7548 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7549 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7550 // If we're looking for eq 0 instead of ne 0, we need to invert the
7551 // condition.
7552 bool Invert = CCVal == ISD::SETEQ;
7553 CCVal = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
7554 if (Invert)
7555 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7556
7557 RHS = LHS.getOperand(1);
7558 LHS = LHS.getOperand(0);
7559 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7560
7561 CC = DAG.getCondCode(CCVal);
7562 return true;
7563 }
7564
7565 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7566 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7567 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7568 SDValue LHS0 = LHS.getOperand(0);
7569 if (LHS0.getOpcode() == ISD::AND &&
7570 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7571 uint64_t Mask = LHS0.getConstantOperandVal(1);
7572 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7573 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7574 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7575 CC = DAG.getCondCode(CCVal);
7576
7577 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7578 LHS = LHS0.getOperand(0);
7579 if (ShAmt != 0)
7580 LHS =
7581 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7582 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7583 return true;
7584 }
7585 }
7586 }
7587
7588 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7589 // This can occur when legalizing some floating point comparisons.
7590 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7591 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7592 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7593 CC = DAG.getCondCode(CCVal);
7594 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7595 return true;
7596 }
7597
7598 // Fold ((shl (extract_vector_elt X, I), GRLen - EleBits)), 0, eq/ne) ->
7599 // ((extract_vector_elt X, I), 0, eq/ne)
7600 if (isNullConstant(RHS) && (CCVal == ISD::SETEQ || CCVal == ISD::SETNE) &&
7601 LHS.getOpcode() == ISD::SHL && LHS.hasOneUse() &&
7602 isa<ConstantSDNode>(LHS.getOperand(1))) {
7603 SDValue Ext = LHS.getOperand(0);
7604 unsigned Sht = LHS.getConstantOperandVal(1);
7605 if (Ext.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
7606 SDValue Vec = Ext.getOperand(0);
7607 unsigned EleBits = Vec.getScalarValueSizeInBits();
7608 if ((EleBits + Sht) == Subtarget.getGRLen()) {
7609 LHS = Ext;
7610 return true;
7611 }
7612 }
7613 }
7614
7615 // Fold (C1, C2, cond) -> (0, 0, seteq/setne)
7617 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
7618 EVT VT = LHS.getValueType();
7619 EVT SetCCResVT =
7620 TLI->getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
7621 if (SDValue Folded = DAG.FoldSetCC(SetCCResVT, LHS, RHS, CCVal, DL)) {
7622 LHS = DAG.getConstant(0, DL, VT);
7623 RHS = DAG.getConstant(0, DL, VT);
7625 return true;
7626 }
7627 }
7628
7629 return false;
7630}
7631
7634 const LoongArchSubtarget &Subtarget) {
7635 SDValue LHS = N->getOperand(1);
7636 SDValue RHS = N->getOperand(2);
7637 SDValue CC = N->getOperand(3);
7638 SDLoc DL(N);
7639
7640 // CC was folded into V, so always return ISD::SETNE is fine.
7642 DL, DAG, Subtarget))
7643 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7644 N->getOperand(0), V,
7645 DAG.getConstant(0, DL, Subtarget.getGRLenVT()),
7646 DAG.getCondCode(ISD::SETNE), N->getOperand(4));
7647
7648 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7649 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7650 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7651
7652 return SDValue();
7653}
7654
7657 const LoongArchSubtarget &Subtarget) {
7658 // Transform
7659 SDValue LHS = N->getOperand(0);
7660 SDValue RHS = N->getOperand(1);
7661 SDValue CC = N->getOperand(2);
7662 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7663 SDValue TrueV = N->getOperand(3);
7664 SDValue FalseV = N->getOperand(4);
7665 SDLoc DL(N);
7666 EVT VT = N->getValueType(0);
7667
7668 // If the True and False values are the same, we don't need a select_cc.
7669 if (TrueV == FalseV)
7670 return TrueV;
7671
7672 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7673 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7674 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7676 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7677 if (CCVal == ISD::CondCode::SETGE)
7678 std::swap(TrueV, FalseV);
7679
7680 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7681 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7682 // Only handle simm12, if it is not in this range, it can be considered as
7683 // register.
7684 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7685 isInt<12>(TrueSImm - FalseSImm)) {
7686 SDValue SRA =
7687 DAG.getNode(ISD::SRA, DL, VT, LHS,
7688 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7689 SDValue AND =
7690 DAG.getNode(ISD::AND, DL, VT, SRA,
7691 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7692 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7693 }
7694
7695 if (CCVal == ISD::CondCode::SETGE)
7696 std::swap(TrueV, FalseV);
7697 }
7698
7699 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7700 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
7701 {LHS, RHS, CC, TrueV, FalseV});
7702
7703 return SDValue();
7704}
7705
7706template <unsigned N>
7708 SelectionDAG &DAG,
7709 const LoongArchSubtarget &Subtarget,
7710 bool IsSigned = false) {
7711 SDLoc DL(Node);
7712 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7713 // Check the ImmArg.
7714 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7715 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7716 DAG.getContext()->emitError(Node->getOperationName(0) +
7717 ": argument out of range.");
7718 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
7719 }
7720 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
7721}
7722
7723template <unsigned N>
7724static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
7725 SelectionDAG &DAG, bool IsSigned = false) {
7726 SDLoc DL(Node);
7727 EVT ResTy = Node->getValueType(0);
7728 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7729
7730 // Check the ImmArg.
7731 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7732 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7733 DAG.getContext()->emitError(Node->getOperationName(0) +
7734 ": argument out of range.");
7735 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7736 }
7737 return DAG.getConstant(
7739 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
7740 DL, ResTy);
7741}
7742
7744 SDLoc DL(Node);
7745 EVT ResTy = Node->getValueType(0);
7746 SDValue Vec = Node->getOperand(2);
7747 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
7748 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
7749}
7750
7752 SDLoc DL(Node);
7753 EVT ResTy = Node->getValueType(0);
7754 SDValue One = DAG.getConstant(1, DL, ResTy);
7755 SDValue Bit =
7756 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
7757
7758 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
7759 DAG.getNOT(DL, Bit, ResTy));
7760}
7761
7762template <unsigned N>
7764 SDLoc DL(Node);
7765 EVT ResTy = Node->getValueType(0);
7766 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7767 // Check the unsigned ImmArg.
7768 if (!isUInt<N>(CImm->getZExtValue())) {
7769 DAG.getContext()->emitError(Node->getOperationName(0) +
7770 ": argument out of range.");
7771 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7772 }
7773
7774 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7775 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
7776
7777 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
7778}
7779
7780template <unsigned N>
7782 SDLoc DL(Node);
7783 EVT ResTy = Node->getValueType(0);
7784 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7785 // Check the unsigned ImmArg.
7786 if (!isUInt<N>(CImm->getZExtValue())) {
7787 DAG.getContext()->emitError(Node->getOperationName(0) +
7788 ": argument out of range.");
7789 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7790 }
7791
7792 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7793 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7794 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
7795}
7796
7797template <unsigned N>
7799 SDLoc DL(Node);
7800 EVT ResTy = Node->getValueType(0);
7801 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7802 // Check the unsigned ImmArg.
7803 if (!isUInt<N>(CImm->getZExtValue())) {
7804 DAG.getContext()->emitError(Node->getOperationName(0) +
7805 ": argument out of range.");
7806 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7807 }
7808
7809 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7810 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7811 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
7812}
7813
7814template <unsigned W>
7816 unsigned ResOp) {
7817 unsigned Imm = N->getConstantOperandVal(2);
7818 if (!isUInt<W>(Imm)) {
7819 const StringRef ErrorMsg = "argument out of range";
7820 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
7821 return DAG.getUNDEF(N->getValueType(0));
7822 }
7823 SDLoc DL(N);
7824 SDValue Vec = N->getOperand(1);
7825 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
7827 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
7828}
7829
7830static SDValue
7833 const LoongArchSubtarget &Subtarget) {
7834 SDLoc DL(N);
7835 switch (N->getConstantOperandVal(0)) {
7836 default:
7837 break;
7838 case Intrinsic::loongarch_lsx_vadd_b:
7839 case Intrinsic::loongarch_lsx_vadd_h:
7840 case Intrinsic::loongarch_lsx_vadd_w:
7841 case Intrinsic::loongarch_lsx_vadd_d:
7842 case Intrinsic::loongarch_lasx_xvadd_b:
7843 case Intrinsic::loongarch_lasx_xvadd_h:
7844 case Intrinsic::loongarch_lasx_xvadd_w:
7845 case Intrinsic::loongarch_lasx_xvadd_d:
7846 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7847 N->getOperand(2));
7848 case Intrinsic::loongarch_lsx_vaddi_bu:
7849 case Intrinsic::loongarch_lsx_vaddi_hu:
7850 case Intrinsic::loongarch_lsx_vaddi_wu:
7851 case Intrinsic::loongarch_lsx_vaddi_du:
7852 case Intrinsic::loongarch_lasx_xvaddi_bu:
7853 case Intrinsic::loongarch_lasx_xvaddi_hu:
7854 case Intrinsic::loongarch_lasx_xvaddi_wu:
7855 case Intrinsic::loongarch_lasx_xvaddi_du:
7856 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7857 lowerVectorSplatImm<5>(N, 2, DAG));
7858 case Intrinsic::loongarch_lsx_vsub_b:
7859 case Intrinsic::loongarch_lsx_vsub_h:
7860 case Intrinsic::loongarch_lsx_vsub_w:
7861 case Intrinsic::loongarch_lsx_vsub_d:
7862 case Intrinsic::loongarch_lasx_xvsub_b:
7863 case Intrinsic::loongarch_lasx_xvsub_h:
7864 case Intrinsic::loongarch_lasx_xvsub_w:
7865 case Intrinsic::loongarch_lasx_xvsub_d:
7866 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7867 N->getOperand(2));
7868 case Intrinsic::loongarch_lsx_vsubi_bu:
7869 case Intrinsic::loongarch_lsx_vsubi_hu:
7870 case Intrinsic::loongarch_lsx_vsubi_wu:
7871 case Intrinsic::loongarch_lsx_vsubi_du:
7872 case Intrinsic::loongarch_lasx_xvsubi_bu:
7873 case Intrinsic::loongarch_lasx_xvsubi_hu:
7874 case Intrinsic::loongarch_lasx_xvsubi_wu:
7875 case Intrinsic::loongarch_lasx_xvsubi_du:
7876 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7877 lowerVectorSplatImm<5>(N, 2, DAG));
7878 case Intrinsic::loongarch_lsx_vneg_b:
7879 case Intrinsic::loongarch_lsx_vneg_h:
7880 case Intrinsic::loongarch_lsx_vneg_w:
7881 case Intrinsic::loongarch_lsx_vneg_d:
7882 case Intrinsic::loongarch_lasx_xvneg_b:
7883 case Intrinsic::loongarch_lasx_xvneg_h:
7884 case Intrinsic::loongarch_lasx_xvneg_w:
7885 case Intrinsic::loongarch_lasx_xvneg_d:
7886 return DAG.getNode(
7887 ISD::SUB, DL, N->getValueType(0),
7888 DAG.getConstant(
7889 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
7890 /*isSigned=*/true),
7891 SDLoc(N), N->getValueType(0)),
7892 N->getOperand(1));
7893 case Intrinsic::loongarch_lsx_vmax_b:
7894 case Intrinsic::loongarch_lsx_vmax_h:
7895 case Intrinsic::loongarch_lsx_vmax_w:
7896 case Intrinsic::loongarch_lsx_vmax_d:
7897 case Intrinsic::loongarch_lasx_xvmax_b:
7898 case Intrinsic::loongarch_lasx_xvmax_h:
7899 case Intrinsic::loongarch_lasx_xvmax_w:
7900 case Intrinsic::loongarch_lasx_xvmax_d:
7901 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7902 N->getOperand(2));
7903 case Intrinsic::loongarch_lsx_vmax_bu:
7904 case Intrinsic::loongarch_lsx_vmax_hu:
7905 case Intrinsic::loongarch_lsx_vmax_wu:
7906 case Intrinsic::loongarch_lsx_vmax_du:
7907 case Intrinsic::loongarch_lasx_xvmax_bu:
7908 case Intrinsic::loongarch_lasx_xvmax_hu:
7909 case Intrinsic::loongarch_lasx_xvmax_wu:
7910 case Intrinsic::loongarch_lasx_xvmax_du:
7911 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7912 N->getOperand(2));
7913 case Intrinsic::loongarch_lsx_vmaxi_b:
7914 case Intrinsic::loongarch_lsx_vmaxi_h:
7915 case Intrinsic::loongarch_lsx_vmaxi_w:
7916 case Intrinsic::loongarch_lsx_vmaxi_d:
7917 case Intrinsic::loongarch_lasx_xvmaxi_b:
7918 case Intrinsic::loongarch_lasx_xvmaxi_h:
7919 case Intrinsic::loongarch_lasx_xvmaxi_w:
7920 case Intrinsic::loongarch_lasx_xvmaxi_d:
7921 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7922 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7923 case Intrinsic::loongarch_lsx_vmaxi_bu:
7924 case Intrinsic::loongarch_lsx_vmaxi_hu:
7925 case Intrinsic::loongarch_lsx_vmaxi_wu:
7926 case Intrinsic::loongarch_lsx_vmaxi_du:
7927 case Intrinsic::loongarch_lasx_xvmaxi_bu:
7928 case Intrinsic::loongarch_lasx_xvmaxi_hu:
7929 case Intrinsic::loongarch_lasx_xvmaxi_wu:
7930 case Intrinsic::loongarch_lasx_xvmaxi_du:
7931 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7932 lowerVectorSplatImm<5>(N, 2, DAG));
7933 case Intrinsic::loongarch_lsx_vmin_b:
7934 case Intrinsic::loongarch_lsx_vmin_h:
7935 case Intrinsic::loongarch_lsx_vmin_w:
7936 case Intrinsic::loongarch_lsx_vmin_d:
7937 case Intrinsic::loongarch_lasx_xvmin_b:
7938 case Intrinsic::loongarch_lasx_xvmin_h:
7939 case Intrinsic::loongarch_lasx_xvmin_w:
7940 case Intrinsic::loongarch_lasx_xvmin_d:
7941 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7942 N->getOperand(2));
7943 case Intrinsic::loongarch_lsx_vmin_bu:
7944 case Intrinsic::loongarch_lsx_vmin_hu:
7945 case Intrinsic::loongarch_lsx_vmin_wu:
7946 case Intrinsic::loongarch_lsx_vmin_du:
7947 case Intrinsic::loongarch_lasx_xvmin_bu:
7948 case Intrinsic::loongarch_lasx_xvmin_hu:
7949 case Intrinsic::loongarch_lasx_xvmin_wu:
7950 case Intrinsic::loongarch_lasx_xvmin_du:
7951 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7952 N->getOperand(2));
7953 case Intrinsic::loongarch_lsx_vmini_b:
7954 case Intrinsic::loongarch_lsx_vmini_h:
7955 case Intrinsic::loongarch_lsx_vmini_w:
7956 case Intrinsic::loongarch_lsx_vmini_d:
7957 case Intrinsic::loongarch_lasx_xvmini_b:
7958 case Intrinsic::loongarch_lasx_xvmini_h:
7959 case Intrinsic::loongarch_lasx_xvmini_w:
7960 case Intrinsic::loongarch_lasx_xvmini_d:
7961 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7962 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7963 case Intrinsic::loongarch_lsx_vmini_bu:
7964 case Intrinsic::loongarch_lsx_vmini_hu:
7965 case Intrinsic::loongarch_lsx_vmini_wu:
7966 case Intrinsic::loongarch_lsx_vmini_du:
7967 case Intrinsic::loongarch_lasx_xvmini_bu:
7968 case Intrinsic::loongarch_lasx_xvmini_hu:
7969 case Intrinsic::loongarch_lasx_xvmini_wu:
7970 case Intrinsic::loongarch_lasx_xvmini_du:
7971 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7972 lowerVectorSplatImm<5>(N, 2, DAG));
7973 case Intrinsic::loongarch_lsx_vmul_b:
7974 case Intrinsic::loongarch_lsx_vmul_h:
7975 case Intrinsic::loongarch_lsx_vmul_w:
7976 case Intrinsic::loongarch_lsx_vmul_d:
7977 case Intrinsic::loongarch_lasx_xvmul_b:
7978 case Intrinsic::loongarch_lasx_xvmul_h:
7979 case Intrinsic::loongarch_lasx_xvmul_w:
7980 case Intrinsic::loongarch_lasx_xvmul_d:
7981 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
7982 N->getOperand(2));
7983 case Intrinsic::loongarch_lsx_vmadd_b:
7984 case Intrinsic::loongarch_lsx_vmadd_h:
7985 case Intrinsic::loongarch_lsx_vmadd_w:
7986 case Intrinsic::loongarch_lsx_vmadd_d:
7987 case Intrinsic::loongarch_lasx_xvmadd_b:
7988 case Intrinsic::loongarch_lasx_xvmadd_h:
7989 case Intrinsic::loongarch_lasx_xvmadd_w:
7990 case Intrinsic::loongarch_lasx_xvmadd_d: {
7991 EVT ResTy = N->getValueType(0);
7992 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
7993 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7994 N->getOperand(3)));
7995 }
7996 case Intrinsic::loongarch_lsx_vmsub_b:
7997 case Intrinsic::loongarch_lsx_vmsub_h:
7998 case Intrinsic::loongarch_lsx_vmsub_w:
7999 case Intrinsic::loongarch_lsx_vmsub_d:
8000 case Intrinsic::loongarch_lasx_xvmsub_b:
8001 case Intrinsic::loongarch_lasx_xvmsub_h:
8002 case Intrinsic::loongarch_lasx_xvmsub_w:
8003 case Intrinsic::loongarch_lasx_xvmsub_d: {
8004 EVT ResTy = N->getValueType(0);
8005 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
8006 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
8007 N->getOperand(3)));
8008 }
8009 case Intrinsic::loongarch_lsx_vdiv_b:
8010 case Intrinsic::loongarch_lsx_vdiv_h:
8011 case Intrinsic::loongarch_lsx_vdiv_w:
8012 case Intrinsic::loongarch_lsx_vdiv_d:
8013 case Intrinsic::loongarch_lasx_xvdiv_b:
8014 case Intrinsic::loongarch_lasx_xvdiv_h:
8015 case Intrinsic::loongarch_lasx_xvdiv_w:
8016 case Intrinsic::loongarch_lasx_xvdiv_d:
8017 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
8018 N->getOperand(2));
8019 case Intrinsic::loongarch_lsx_vdiv_bu:
8020 case Intrinsic::loongarch_lsx_vdiv_hu:
8021 case Intrinsic::loongarch_lsx_vdiv_wu:
8022 case Intrinsic::loongarch_lsx_vdiv_du:
8023 case Intrinsic::loongarch_lasx_xvdiv_bu:
8024 case Intrinsic::loongarch_lasx_xvdiv_hu:
8025 case Intrinsic::loongarch_lasx_xvdiv_wu:
8026 case Intrinsic::loongarch_lasx_xvdiv_du:
8027 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
8028 N->getOperand(2));
8029 case Intrinsic::loongarch_lsx_vmod_b:
8030 case Intrinsic::loongarch_lsx_vmod_h:
8031 case Intrinsic::loongarch_lsx_vmod_w:
8032 case Intrinsic::loongarch_lsx_vmod_d:
8033 case Intrinsic::loongarch_lasx_xvmod_b:
8034 case Intrinsic::loongarch_lasx_xvmod_h:
8035 case Intrinsic::loongarch_lasx_xvmod_w:
8036 case Intrinsic::loongarch_lasx_xvmod_d:
8037 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
8038 N->getOperand(2));
8039 case Intrinsic::loongarch_lsx_vmod_bu:
8040 case Intrinsic::loongarch_lsx_vmod_hu:
8041 case Intrinsic::loongarch_lsx_vmod_wu:
8042 case Intrinsic::loongarch_lsx_vmod_du:
8043 case Intrinsic::loongarch_lasx_xvmod_bu:
8044 case Intrinsic::loongarch_lasx_xvmod_hu:
8045 case Intrinsic::loongarch_lasx_xvmod_wu:
8046 case Intrinsic::loongarch_lasx_xvmod_du:
8047 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
8048 N->getOperand(2));
8049 case Intrinsic::loongarch_lsx_vand_v:
8050 case Intrinsic::loongarch_lasx_xvand_v:
8051 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8052 N->getOperand(2));
8053 case Intrinsic::loongarch_lsx_vor_v:
8054 case Intrinsic::loongarch_lasx_xvor_v:
8055 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8056 N->getOperand(2));
8057 case Intrinsic::loongarch_lsx_vxor_v:
8058 case Intrinsic::loongarch_lasx_xvxor_v:
8059 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8060 N->getOperand(2));
8061 case Intrinsic::loongarch_lsx_vnor_v:
8062 case Intrinsic::loongarch_lasx_xvnor_v: {
8063 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8064 N->getOperand(2));
8065 return DAG.getNOT(DL, Res, Res->getValueType(0));
8066 }
8067 case Intrinsic::loongarch_lsx_vandi_b:
8068 case Intrinsic::loongarch_lasx_xvandi_b:
8069 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8070 lowerVectorSplatImm<8>(N, 2, DAG));
8071 case Intrinsic::loongarch_lsx_vori_b:
8072 case Intrinsic::loongarch_lasx_xvori_b:
8073 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8074 lowerVectorSplatImm<8>(N, 2, DAG));
8075 case Intrinsic::loongarch_lsx_vxori_b:
8076 case Intrinsic::loongarch_lasx_xvxori_b:
8077 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8078 lowerVectorSplatImm<8>(N, 2, DAG));
8079 case Intrinsic::loongarch_lsx_vsll_b:
8080 case Intrinsic::loongarch_lsx_vsll_h:
8081 case Intrinsic::loongarch_lsx_vsll_w:
8082 case Intrinsic::loongarch_lsx_vsll_d:
8083 case Intrinsic::loongarch_lasx_xvsll_b:
8084 case Intrinsic::loongarch_lasx_xvsll_h:
8085 case Intrinsic::loongarch_lasx_xvsll_w:
8086 case Intrinsic::loongarch_lasx_xvsll_d:
8087 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8088 truncateVecElts(N, DAG));
8089 case Intrinsic::loongarch_lsx_vslli_b:
8090 case Intrinsic::loongarch_lasx_xvslli_b:
8091 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8092 lowerVectorSplatImm<3>(N, 2, DAG));
8093 case Intrinsic::loongarch_lsx_vslli_h:
8094 case Intrinsic::loongarch_lasx_xvslli_h:
8095 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8096 lowerVectorSplatImm<4>(N, 2, DAG));
8097 case Intrinsic::loongarch_lsx_vslli_w:
8098 case Intrinsic::loongarch_lasx_xvslli_w:
8099 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8100 lowerVectorSplatImm<5>(N, 2, DAG));
8101 case Intrinsic::loongarch_lsx_vslli_d:
8102 case Intrinsic::loongarch_lasx_xvslli_d:
8103 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8104 lowerVectorSplatImm<6>(N, 2, DAG));
8105 case Intrinsic::loongarch_lsx_vsrl_b:
8106 case Intrinsic::loongarch_lsx_vsrl_h:
8107 case Intrinsic::loongarch_lsx_vsrl_w:
8108 case Intrinsic::loongarch_lsx_vsrl_d:
8109 case Intrinsic::loongarch_lasx_xvsrl_b:
8110 case Intrinsic::loongarch_lasx_xvsrl_h:
8111 case Intrinsic::loongarch_lasx_xvsrl_w:
8112 case Intrinsic::loongarch_lasx_xvsrl_d:
8113 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8114 truncateVecElts(N, DAG));
8115 case Intrinsic::loongarch_lsx_vsrli_b:
8116 case Intrinsic::loongarch_lasx_xvsrli_b:
8117 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8118 lowerVectorSplatImm<3>(N, 2, DAG));
8119 case Intrinsic::loongarch_lsx_vsrli_h:
8120 case Intrinsic::loongarch_lasx_xvsrli_h:
8121 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8122 lowerVectorSplatImm<4>(N, 2, DAG));
8123 case Intrinsic::loongarch_lsx_vsrli_w:
8124 case Intrinsic::loongarch_lasx_xvsrli_w:
8125 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8126 lowerVectorSplatImm<5>(N, 2, DAG));
8127 case Intrinsic::loongarch_lsx_vsrli_d:
8128 case Intrinsic::loongarch_lasx_xvsrli_d:
8129 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8130 lowerVectorSplatImm<6>(N, 2, DAG));
8131 case Intrinsic::loongarch_lsx_vsra_b:
8132 case Intrinsic::loongarch_lsx_vsra_h:
8133 case Intrinsic::loongarch_lsx_vsra_w:
8134 case Intrinsic::loongarch_lsx_vsra_d:
8135 case Intrinsic::loongarch_lasx_xvsra_b:
8136 case Intrinsic::loongarch_lasx_xvsra_h:
8137 case Intrinsic::loongarch_lasx_xvsra_w:
8138 case Intrinsic::loongarch_lasx_xvsra_d:
8139 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8140 truncateVecElts(N, DAG));
8141 case Intrinsic::loongarch_lsx_vsrai_b:
8142 case Intrinsic::loongarch_lasx_xvsrai_b:
8143 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8144 lowerVectorSplatImm<3>(N, 2, DAG));
8145 case Intrinsic::loongarch_lsx_vsrai_h:
8146 case Intrinsic::loongarch_lasx_xvsrai_h:
8147 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8148 lowerVectorSplatImm<4>(N, 2, DAG));
8149 case Intrinsic::loongarch_lsx_vsrai_w:
8150 case Intrinsic::loongarch_lasx_xvsrai_w:
8151 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8152 lowerVectorSplatImm<5>(N, 2, DAG));
8153 case Intrinsic::loongarch_lsx_vsrai_d:
8154 case Intrinsic::loongarch_lasx_xvsrai_d:
8155 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8156 lowerVectorSplatImm<6>(N, 2, DAG));
8157 case Intrinsic::loongarch_lsx_vclz_b:
8158 case Intrinsic::loongarch_lsx_vclz_h:
8159 case Intrinsic::loongarch_lsx_vclz_w:
8160 case Intrinsic::loongarch_lsx_vclz_d:
8161 case Intrinsic::loongarch_lasx_xvclz_b:
8162 case Intrinsic::loongarch_lasx_xvclz_h:
8163 case Intrinsic::loongarch_lasx_xvclz_w:
8164 case Intrinsic::loongarch_lasx_xvclz_d:
8165 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
8166 case Intrinsic::loongarch_lsx_vpcnt_b:
8167 case Intrinsic::loongarch_lsx_vpcnt_h:
8168 case Intrinsic::loongarch_lsx_vpcnt_w:
8169 case Intrinsic::loongarch_lsx_vpcnt_d:
8170 case Intrinsic::loongarch_lasx_xvpcnt_b:
8171 case Intrinsic::loongarch_lasx_xvpcnt_h:
8172 case Intrinsic::loongarch_lasx_xvpcnt_w:
8173 case Intrinsic::loongarch_lasx_xvpcnt_d:
8174 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
8175 case Intrinsic::loongarch_lsx_vbitclr_b:
8176 case Intrinsic::loongarch_lsx_vbitclr_h:
8177 case Intrinsic::loongarch_lsx_vbitclr_w:
8178 case Intrinsic::loongarch_lsx_vbitclr_d:
8179 case Intrinsic::loongarch_lasx_xvbitclr_b:
8180 case Intrinsic::loongarch_lasx_xvbitclr_h:
8181 case Intrinsic::loongarch_lasx_xvbitclr_w:
8182 case Intrinsic::loongarch_lasx_xvbitclr_d:
8183 return lowerVectorBitClear(N, DAG);
8184 case Intrinsic::loongarch_lsx_vbitclri_b:
8185 case Intrinsic::loongarch_lasx_xvbitclri_b:
8186 return lowerVectorBitClearImm<3>(N, DAG);
8187 case Intrinsic::loongarch_lsx_vbitclri_h:
8188 case Intrinsic::loongarch_lasx_xvbitclri_h:
8189 return lowerVectorBitClearImm<4>(N, DAG);
8190 case Intrinsic::loongarch_lsx_vbitclri_w:
8191 case Intrinsic::loongarch_lasx_xvbitclri_w:
8192 return lowerVectorBitClearImm<5>(N, DAG);
8193 case Intrinsic::loongarch_lsx_vbitclri_d:
8194 case Intrinsic::loongarch_lasx_xvbitclri_d:
8195 return lowerVectorBitClearImm<6>(N, DAG);
8196 case Intrinsic::loongarch_lsx_vbitset_b:
8197 case Intrinsic::loongarch_lsx_vbitset_h:
8198 case Intrinsic::loongarch_lsx_vbitset_w:
8199 case Intrinsic::loongarch_lsx_vbitset_d:
8200 case Intrinsic::loongarch_lasx_xvbitset_b:
8201 case Intrinsic::loongarch_lasx_xvbitset_h:
8202 case Intrinsic::loongarch_lasx_xvbitset_w:
8203 case Intrinsic::loongarch_lasx_xvbitset_d: {
8204 EVT VecTy = N->getValueType(0);
8205 SDValue One = DAG.getConstant(1, DL, VecTy);
8206 return DAG.getNode(
8207 ISD::OR, DL, VecTy, N->getOperand(1),
8208 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8209 }
8210 case Intrinsic::loongarch_lsx_vbitseti_b:
8211 case Intrinsic::loongarch_lasx_xvbitseti_b:
8212 return lowerVectorBitSetImm<3>(N, DAG);
8213 case Intrinsic::loongarch_lsx_vbitseti_h:
8214 case Intrinsic::loongarch_lasx_xvbitseti_h:
8215 return lowerVectorBitSetImm<4>(N, DAG);
8216 case Intrinsic::loongarch_lsx_vbitseti_w:
8217 case Intrinsic::loongarch_lasx_xvbitseti_w:
8218 return lowerVectorBitSetImm<5>(N, DAG);
8219 case Intrinsic::loongarch_lsx_vbitseti_d:
8220 case Intrinsic::loongarch_lasx_xvbitseti_d:
8221 return lowerVectorBitSetImm<6>(N, DAG);
8222 case Intrinsic::loongarch_lsx_vbitrev_b:
8223 case Intrinsic::loongarch_lsx_vbitrev_h:
8224 case Intrinsic::loongarch_lsx_vbitrev_w:
8225 case Intrinsic::loongarch_lsx_vbitrev_d:
8226 case Intrinsic::loongarch_lasx_xvbitrev_b:
8227 case Intrinsic::loongarch_lasx_xvbitrev_h:
8228 case Intrinsic::loongarch_lasx_xvbitrev_w:
8229 case Intrinsic::loongarch_lasx_xvbitrev_d: {
8230 EVT VecTy = N->getValueType(0);
8231 SDValue One = DAG.getConstant(1, DL, VecTy);
8232 return DAG.getNode(
8233 ISD::XOR, DL, VecTy, N->getOperand(1),
8234 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8235 }
8236 case Intrinsic::loongarch_lsx_vbitrevi_b:
8237 case Intrinsic::loongarch_lasx_xvbitrevi_b:
8238 return lowerVectorBitRevImm<3>(N, DAG);
8239 case Intrinsic::loongarch_lsx_vbitrevi_h:
8240 case Intrinsic::loongarch_lasx_xvbitrevi_h:
8241 return lowerVectorBitRevImm<4>(N, DAG);
8242 case Intrinsic::loongarch_lsx_vbitrevi_w:
8243 case Intrinsic::loongarch_lasx_xvbitrevi_w:
8244 return lowerVectorBitRevImm<5>(N, DAG);
8245 case Intrinsic::loongarch_lsx_vbitrevi_d:
8246 case Intrinsic::loongarch_lasx_xvbitrevi_d:
8247 return lowerVectorBitRevImm<6>(N, DAG);
8248 case Intrinsic::loongarch_lsx_vfadd_s:
8249 case Intrinsic::loongarch_lsx_vfadd_d:
8250 case Intrinsic::loongarch_lasx_xvfadd_s:
8251 case Intrinsic::loongarch_lasx_xvfadd_d:
8252 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
8253 N->getOperand(2));
8254 case Intrinsic::loongarch_lsx_vfsub_s:
8255 case Intrinsic::loongarch_lsx_vfsub_d:
8256 case Intrinsic::loongarch_lasx_xvfsub_s:
8257 case Intrinsic::loongarch_lasx_xvfsub_d:
8258 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
8259 N->getOperand(2));
8260 case Intrinsic::loongarch_lsx_vfmul_s:
8261 case Intrinsic::loongarch_lsx_vfmul_d:
8262 case Intrinsic::loongarch_lasx_xvfmul_s:
8263 case Intrinsic::loongarch_lasx_xvfmul_d:
8264 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
8265 N->getOperand(2));
8266 case Intrinsic::loongarch_lsx_vfdiv_s:
8267 case Intrinsic::loongarch_lsx_vfdiv_d:
8268 case Intrinsic::loongarch_lasx_xvfdiv_s:
8269 case Intrinsic::loongarch_lasx_xvfdiv_d:
8270 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
8271 N->getOperand(2));
8272 case Intrinsic::loongarch_lsx_vfmadd_s:
8273 case Intrinsic::loongarch_lsx_vfmadd_d:
8274 case Intrinsic::loongarch_lasx_xvfmadd_s:
8275 case Intrinsic::loongarch_lasx_xvfmadd_d:
8276 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
8277 N->getOperand(2), N->getOperand(3));
8278 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
8279 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8280 N->getOperand(1), N->getOperand(2),
8281 legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
8282 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
8283 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
8284 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8285 N->getOperand(1), N->getOperand(2),
8286 legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
8287 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
8288 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
8289 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8290 N->getOperand(1), N->getOperand(2),
8291 legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
8292 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
8293 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8294 N->getOperand(1), N->getOperand(2),
8295 legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
8296 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
8297 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
8298 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
8299 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
8300 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
8301 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
8302 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
8303 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
8304 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
8305 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8306 N->getOperand(1)));
8307 case Intrinsic::loongarch_lsx_vreplve_b:
8308 case Intrinsic::loongarch_lsx_vreplve_h:
8309 case Intrinsic::loongarch_lsx_vreplve_w:
8310 case Intrinsic::loongarch_lsx_vreplve_d:
8311 case Intrinsic::loongarch_lasx_xvreplve_b:
8312 case Intrinsic::loongarch_lasx_xvreplve_h:
8313 case Intrinsic::loongarch_lasx_xvreplve_w:
8314 case Intrinsic::loongarch_lasx_xvreplve_d:
8315 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
8316 N->getOperand(1),
8317 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8318 N->getOperand(2)));
8319 case Intrinsic::loongarch_lsx_vpickve2gr_b:
8320 if (!Subtarget.is64Bit())
8321 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8322 break;
8323 case Intrinsic::loongarch_lsx_vpickve2gr_h:
8324 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
8325 if (!Subtarget.is64Bit())
8326 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8327 break;
8328 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8329 if (!Subtarget.is64Bit())
8330 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8331 break;
8332 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8333 if (!Subtarget.is64Bit())
8334 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8335 break;
8336 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8337 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8338 if (!Subtarget.is64Bit())
8339 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8340 break;
8341 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8342 if (!Subtarget.is64Bit())
8343 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8344 break;
8345 case Intrinsic::loongarch_lsx_bz_b:
8346 case Intrinsic::loongarch_lsx_bz_h:
8347 case Intrinsic::loongarch_lsx_bz_w:
8348 case Intrinsic::loongarch_lsx_bz_d:
8349 case Intrinsic::loongarch_lasx_xbz_b:
8350 case Intrinsic::loongarch_lasx_xbz_h:
8351 case Intrinsic::loongarch_lasx_xbz_w:
8352 case Intrinsic::loongarch_lasx_xbz_d:
8353 if (!Subtarget.is64Bit())
8354 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8355 N->getOperand(1));
8356 break;
8357 case Intrinsic::loongarch_lsx_bz_v:
8358 case Intrinsic::loongarch_lasx_xbz_v:
8359 if (!Subtarget.is64Bit())
8360 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8361 N->getOperand(1));
8362 break;
8363 case Intrinsic::loongarch_lsx_bnz_b:
8364 case Intrinsic::loongarch_lsx_bnz_h:
8365 case Intrinsic::loongarch_lsx_bnz_w:
8366 case Intrinsic::loongarch_lsx_bnz_d:
8367 case Intrinsic::loongarch_lasx_xbnz_b:
8368 case Intrinsic::loongarch_lasx_xbnz_h:
8369 case Intrinsic::loongarch_lasx_xbnz_w:
8370 case Intrinsic::loongarch_lasx_xbnz_d:
8371 if (!Subtarget.is64Bit())
8372 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8373 N->getOperand(1));
8374 break;
8375 case Intrinsic::loongarch_lsx_bnz_v:
8376 case Intrinsic::loongarch_lasx_xbnz_v:
8377 if (!Subtarget.is64Bit())
8378 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8379 N->getOperand(1));
8380 break;
8381 case Intrinsic::loongarch_lasx_concat_128_s:
8382 case Intrinsic::loongarch_lasx_concat_128_d:
8383 case Intrinsic::loongarch_lasx_concat_128:
8384 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8385 N->getOperand(1), N->getOperand(2));
8386 }
8387 return SDValue();
8388}
8389
8392 const LoongArchSubtarget &Subtarget) {
8393 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8394 // conversion is unnecessary and can be replaced with the
8395 // MOVFR2GR_S_LA64 operand.
8396 SDValue Op0 = N->getOperand(0);
8397 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8398 return Op0.getOperand(0);
8399 return SDValue();
8400}
8401
8404 const LoongArchSubtarget &Subtarget) {
8405 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8406 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8407 // operand.
8408 SDValue Op0 = N->getOperand(0);
8409 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8410 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8411 "Unexpected value type!");
8412 return Op0.getOperand(0);
8413 }
8414 return SDValue();
8415}
8416
8417static SDValue
8420 MVT VT = N->getSimpleValueType(0);
8421 unsigned NumBits = VT.getScalarSizeInBits();
8422
8423 // Simplify the inputs.
8424 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8425 APInt DemandedMask(APInt::getAllOnes(NumBits));
8426 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8427 return SDValue(N, 0);
8428
8429 return SDValue();
8430}
8431
8432static SDValue
8435 const LoongArchSubtarget &Subtarget) {
8436 SDValue Op0 = N->getOperand(0);
8437 SDLoc DL(N);
8438
8439 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8440 // redundant. Instead, use BuildPairF64's operands directly.
8441 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8442 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8443
8444 if (Op0->isUndef()) {
8445 SDValue Lo = DAG.getUNDEF(MVT::i32);
8446 SDValue Hi = DAG.getUNDEF(MVT::i32);
8447 return DCI.CombineTo(N, Lo, Hi);
8448 }
8449
8450 // It's cheaper to materialise two 32-bit integers than to load a double
8451 // from the constant pool and transfer it to integer registers through the
8452 // stack.
8454 APInt V = C->getValueAPF().bitcastToAPInt();
8455 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8456 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8457 return DCI.CombineTo(N, Lo, Hi);
8458 }
8459
8460 return SDValue();
8461}
8462
8463/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8466 const LoongArchSubtarget &Subtarget) {
8467 SDValue N0 = N->getOperand(0);
8468 SDValue N1 = N->getOperand(1);
8469 MVT VT = N->getSimpleValueType(0);
8470 SDLoc DL(N);
8471
8472 // VANDN(undef, x) -> 0
8473 // VANDN(x, undef) -> 0
8474 if (N0.isUndef() || N1.isUndef())
8475 return DAG.getConstant(0, DL, VT);
8476
8477 // VANDN(0, x) -> x
8479 return N1;
8480
8481 // VANDN(x, 0) -> 0
8483 return DAG.getConstant(0, DL, VT);
8484
8485 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8487 return DAG.getNOT(DL, N0, VT);
8488
8489 // Turn VANDN back to AND if input is inverted.
8490 if (SDValue Not = isNOT(N0, DAG))
8491 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8492
8493 // Folds for better commutativity:
8494 if (N1->hasOneUse()) {
8495 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8496 if (SDValue Not = isNOT(N1, DAG))
8497 return DAG.getNOT(
8498 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8499
8500 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8501 // -> NOT(OR(x, SplatVector(-Imm))
8502 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8503 // gain benefits.
8504 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8505 N1.getOpcode() == ISD::BUILD_VECTOR) {
8506 if (SDValue SplatValue =
8507 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8508 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8509 return SDValue();
8510
8511 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8512 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8513 SDValue Not =
8514 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8515 return DAG.getNOT(
8516 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8517 VT);
8518 }
8519 }
8520 }
8521 }
8522
8523 return SDValue();
8524}
8525
8526static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8527 SDLoc DL(N);
8528 EVT VT = N->getValueType(0);
8529 SDValue Src = N->getOperand(0);
8530 EVT SrcVT = Src.getValueType();
8531
8532 unsigned DstElts = VT.getVectorNumElements();
8533 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8534 unsigned DstEltBits = VT.getScalarSizeInBits();
8535
8536 if (SrcEltBits >= DstEltBits)
8537 return SDValue();
8538
8539 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8540 EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
8541
8542 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8543 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8544}
8545
8546// Merge two 64 to 32 convert instructions into one,
8547// e.g.
8548// vffint.s.l $vr0, $vr1, $vr2
8549// will convert 4 si64 into 4 float at once.
8550// or
8551// vftintrz.w.d $vr0, $vr1, $vr2
8552// which will convert 4 double into 4 si32 at once.
8553// also deal with their 256-bits LASX version.
8554static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8555 unsigned BlockBits) {
8556 SDLoc DL(N);
8557 MVT DstVT = N->getSimpleValueType(0);
8558 SDValue Src = N->getOperand(0);
8559 MVT SrcVT = Src.getSimpleValueType();
8560 unsigned SrcBits = SrcVT.getSizeInBits();
8561
8563 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8564 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8565 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8566 Src.getOperand(0).getValueType() == BlockVT) {
8567 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8568 Blocks.push_back(Src.getOperand(i));
8569 } else if (SrcBits > BlockBits) {
8570 // Wider than one register: extract each BlockBits-wide sub-vector.
8571 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8572 Blocks.push_back(
8573 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8574 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8575 } else {
8576 BlockBits = SrcBits;
8577 Blocks.push_back(Src);
8578 }
8579
8580 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8581 BlockBits / DstVT.getScalarSizeInBits());
8583 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8584 SDValue Lo = Blocks[i];
8585 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8586 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8587
8588 if (BlockBits == 256) {
8589 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8590 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8591 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8592 Res = DAG.getBitcast(NativeVecVT, Res);
8593 }
8594
8595 Parts.push_back(Res);
8596 }
8597
8598 if (Blocks.size() == 1)
8599 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8600 DAG.getVectorIdxConstant(0, DL));
8601 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8602}
8603
8606 const LoongArchSubtarget &Subtarget) {
8607 SDLoc DL(N);
8608 EVT VT = N->getValueType(0);
8609 SDValue Src = N->getOperand(0);
8610 EVT SrcVT = Src.getValueType();
8611
8612 if (VT.isVector()) {
8613 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8614 unsigned DstEltBits = VT.getScalarSizeInBits();
8615 unsigned NumElts = VT.getVectorNumElements();
8616 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8617
8618 // Sign-extend src to avoid scalarization.
8619 if (SrcEltBits <= DstEltBits)
8620 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8621
8622 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8623 return SDValue();
8624
8625 if (!SrcVT.isSimple() || !VT.isSimple())
8626 return SDValue();
8627
8628 // [x]vffint.s.l needs LSX and at least one full 128-bit source register.
8629 if (!Subtarget.hasExtLSX() || SrcVT.getSizeInBits() < 128)
8630 return SDValue();
8631
8632 // Combine [x]vffint.s.l for vector si64 to float conversion.
8633 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8634 }
8635
8636 if (VT != MVT::f32 && VT != MVT::f64)
8637 return SDValue();
8638 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8639 return SDValue();
8640 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8641 return SDValue();
8642
8643 // Only optimize when the source and destination types have the same width.
8644 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8645 return SDValue();
8646
8647 // If the result of an integer load is only used by an integer-to-float
8648 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8649 // (movgr2fr) instruction.
8650 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8651 // Do not change the width of a volatile load. This condition check is
8652 // inspired by AArch64.
8653 !cast<LoadSDNode>(Src)->isVolatile()) {
8654 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8655 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8656 LN0->getPointerInfo(), LN0->getAlign(),
8657 LN0->getMemOperand()->getFlags());
8658
8659 // Make sure successors of the original load stay after it by updating them
8660 // to use the new Chain.
8661 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8662 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8663 }
8664
8665 return SDValue();
8666}
8667
8670 const LoongArchSubtarget &Subtarget) {
8671 SDLoc DL(N);
8672 EVT VT = N->getValueType(0);
8673
8674 // Zero-extend src to avoid scalarization.
8675 if (VT.isVector())
8676 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8677
8678 return SDValue();
8679}
8680
8681// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
8682// For example:
8683// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
8684// Can be combined into:
8685// v4i32 = VFTINTRZ_W_D v2f64. v2f64
8688 const LoongArchSubtarget &Subtarget) {
8689 if (!Subtarget.hasExtLSX())
8690 return SDValue();
8691
8692 SDLoc DL(N);
8693 EVT DstVT = N->getValueType(0);
8694 SDValue Src = N->getOperand(0);
8695 EVT SrcVT = Src.getValueType();
8696 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
8697
8698 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
8699 return SDValue();
8700
8701 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8702 unsigned SrcBits = SrcVT.getSizeInBits();
8703 unsigned DstEltBits = DstVT.getScalarSizeInBits();
8704 unsigned NumElts = DstVT.getVectorNumElements();
8705 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8706
8707 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
8708 return SDValue();
8709
8710 if (SrcBits % BlockBits != 0 && SrcBits != 128)
8711 return SDValue();
8712
8713 if (DstEltBits < 32) {
8714 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
8715 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
8716 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
8717 }
8718
8719 if (SrcEltBits != 64 || DstEltBits != 32)
8720 return SDValue();
8721
8722 if (!IsSigned) {
8723 // LASX already has pattern for double convert to uint32.
8724 if (Subtarget.hasExtLASX())
8725 return SDValue();
8726 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
8727 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
8728 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
8729 }
8730
8731 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
8732}
8733
8734// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
8735// logical operations, like in the example below.
8736// or (and (truncate x, truncate y)),
8737// (xor (truncate z, build_vector (constants)))
8738// Given a target type \p VT, we generate
8739// or (and x, y), (xor z, zext(build_vector (constants)))
8740// given x, y and z are of type \p VT. We can do so, if operands are either
8741// truncates from VT types, the second operand is a vector of constants, can
8742// be recursively promoted or is an existing extension we can extend further.
8744 SelectionDAG &DAG,
8745 const LoongArchSubtarget &Subtarget,
8746 unsigned Depth) {
8747 // Limit recursion to avoid excessive compile times.
8749 return SDValue();
8750
8751 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
8752 return SDValue();
8753
8754 SDValue N0 = N.getOperand(0);
8755 SDValue N1 = N.getOperand(1);
8756
8757 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8758 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
8759 return SDValue();
8760
8761 if (SDValue NN0 =
8762 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
8763 N0 = NN0;
8764 else {
8765 // The left side has to be a 'trunc'.
8766 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
8767 N0.getOperand(0).getValueType() == VT;
8768 if (LHSTrunc)
8769 N0 = N0.getOperand(0);
8770 else
8771 return SDValue();
8772 }
8773
8774 if (SDValue NN1 =
8775 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
8776 N1 = NN1;
8777 else {
8778 // The right side has to be a 'trunc', a (foldable) constant or an
8779 // existing extension we can extend further.
8780 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
8781 N1.getOperand(0).getValueType() == VT;
8782 if (RHSTrunc)
8783 N1 = N1.getOperand(0);
8784 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
8785 Subtarget.hasExtLASX() && N1.hasOneUse())
8786 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
8787 // On 32-bit platform, i64 is an illegal integer scalar type, and
8788 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
8789 // future.
8790 else if (SDValue Cst =
8792 N1 = Cst;
8793 else
8794 return SDValue();
8795 }
8796
8797 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
8798}
8799
8800// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
8801// is LSX-sized register. In most cases we actually compare or select LASX-sized
8802// registers and mixing the two types creates horrible code. This method
8803// optimizes some of the transition sequences.
8805 SelectionDAG &DAG,
8806 const LoongArchSubtarget &Subtarget) {
8807 EVT VT = N.getValueType();
8808 assert(VT.isVector() && "Expected vector type");
8809 assert((N.getOpcode() == ISD::ANY_EXTEND ||
8810 N.getOpcode() == ISD::ZERO_EXTEND ||
8811 N.getOpcode() == ISD::SIGN_EXTEND) &&
8812 "Invalid Node");
8813
8814 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
8815 return SDValue();
8816
8817 SDValue Narrow = N.getOperand(0);
8818 EVT NarrowVT = Narrow.getValueType();
8819
8820 // Generate the wide operation.
8821 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
8822 if (!Op)
8823 return SDValue();
8824 switch (N.getOpcode()) {
8825 default:
8826 llvm_unreachable("Unexpected opcode");
8827 case ISD::ANY_EXTEND:
8828 return Op;
8829 case ISD::ZERO_EXTEND:
8830 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
8831 case ISD::SIGN_EXTEND:
8832 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
8833 DAG.getValueType(NarrowVT));
8834 }
8835}
8836
8839 const LoongArchSubtarget &Subtarget) {
8840 EVT VT = N->getValueType(0);
8841 SDLoc DL(N);
8842
8843 if (VT.isVector()) {
8844 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
8845 return R;
8846
8847 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
8848 N->getValueSizeInBits(0) != N->getOperand(0).getValueSizeInBits() * 2)
8849 return SDValue();
8850
8851 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
8852 if (N->getOpcode() == ISD::SIGN_EXTEND)
8853 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
8854 if (N->getOpcode() == ISD::ZERO_EXTEND)
8855 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
8856 }
8857 }
8858
8859 return SDValue();
8860}
8861
8862static SDValue
8865 const LoongArchSubtarget &Subtarget) {
8866 SDLoc DL(N);
8867 EVT VT = N->getValueType(0);
8868
8869 if (VT.isVector() && N->getNumOperands() == 2)
8870 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
8871 return R;
8872
8873 return SDValue();
8874}
8875
8878 const LoongArchSubtarget &Subtarget) {
8879 if (DCI.isBeforeLegalizeOps())
8880 return SDValue();
8881
8882 EVT VT = N->getValueType(0);
8883 if (!VT.isVector())
8884 return SDValue();
8885
8886 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
8887 return SDValue();
8888
8889 EVT EltVT = VT.getVectorElementType();
8890 if (!EltVT.isInteger())
8891 return SDValue();
8892
8893 SDValue Cond = N->getOperand(0);
8894 SDValue TrueVal = N->getOperand(1);
8895 SDValue FalseVal = N->getOperand(2);
8896
8897 // match:
8898 //
8899 // vselect (setcc shift, 0, seteq),
8900 // x,
8901 // rounded_shift
8902
8903 if (Cond.getOpcode() != ISD::SETCC)
8904 return SDValue();
8905
8906 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
8907 return SDValue();
8908
8909 auto *CC = cast<CondCodeSDNode>(Cond.getOperand(2));
8910 if (CC->get() != ISD::SETEQ)
8911 return SDValue();
8912
8913 SDValue Shift = Cond.getOperand(0);
8914
8915 // True branch must be original value:
8916 //
8917 // vselect cond, x, ...
8918
8919 SDValue X = TrueVal;
8920
8921 // Now match rounded shift pattern:
8922 //
8923 // add
8924 // (and
8925 // (srl X, shift-1)
8926 // 1)
8927 // (srl/sra X, shift)
8928
8929 if (FalseVal.getOpcode() != ISD::ADD)
8930 return SDValue();
8931
8932 SDValue Add0 = FalseVal.getOperand(0);
8933 SDValue Add1 = FalseVal.getOperand(1);
8934 SDValue And;
8935 SDValue Shr;
8936
8937 if (Add0.getOpcode() == ISD::AND) {
8938 And = Add0;
8939 Shr = Add1;
8940 } else if (Add1.getOpcode() == ISD::AND) {
8941 And = Add1;
8942 Shr = Add0;
8943 } else {
8944 return SDValue();
8945 }
8946
8947 // match:
8948 //
8949 // srl/sra X, shift
8950
8951 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
8952 return SDValue();
8953
8954 if (Shr.getOperand(0) != X)
8955 return SDValue();
8956
8957 if (Shr.getOperand(1) != Shift)
8958 return SDValue();
8959
8960 // match:
8961 //
8962 // and
8963 // (srl X, shift-1)
8964 // 1
8965
8966 SDValue Srl = And.getOperand(0);
8967 SDValue One = And.getOperand(1);
8968 APInt SplatVal;
8969
8970 if (Srl.getOpcode() != ISD::SRL)
8971 return SDValue();
8972
8973 One = peekThroughBitcasts(One);
8974 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
8975 return SDValue();
8976
8977 if (SplatVal != 1)
8978 return SDValue();
8979
8980 if (Srl.getOperand(0) != X)
8981 return SDValue();
8982
8983 // match:
8984 //
8985 // shift-1
8986
8987 SDValue ShiftMinus1 = Srl.getOperand(1);
8988
8989 if (ShiftMinus1.getOpcode() != ISD::ADD)
8990 return SDValue();
8991
8992 if (ShiftMinus1.getOperand(0) != Shift)
8993 return SDValue();
8994
8996 return SDValue();
8997
8998 // We matched a rounded right shift pattern and can lower it
8999 // to a single vector rounded shift instruction.
9000
9001 SDLoc DL(N);
9002 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
9003 : LoongArchISD::VSRAR,
9004 DL, VT, X, Shift);
9005}
9006
9008 DAGCombinerInfo &DCI) const {
9009 SelectionDAG &DAG = DCI.DAG;
9010 switch (N->getOpcode()) {
9011 default:
9012 break;
9013 case ISD::ADD:
9014 return performADDCombine(N, DAG, DCI, Subtarget);
9015 case ISD::AND:
9016 return performANDCombine(N, DAG, DCI, Subtarget);
9017 case ISD::OR:
9018 return performORCombine(N, DAG, DCI, Subtarget);
9019 case ISD::SETCC:
9020 return performSETCCCombine(N, DAG, DCI, Subtarget);
9021 case ISD::SELECT:
9022 return performSELECTCombine(N, DAG, DCI, Subtarget);
9023 case ISD::SHL:
9024 return performSHLCombine(N, DAG, DCI, Subtarget);
9025 case ISD::SRL:
9026 return performSRLCombine(N, DAG, DCI, Subtarget);
9027 case ISD::SUB:
9028 return performSUBCombine(N, DAG, DCI, Subtarget);
9029 case ISD::BITCAST:
9030 return performBITCASTCombine(N, DAG, DCI, Subtarget);
9031 case ISD::ANY_EXTEND:
9032 case ISD::ZERO_EXTEND:
9033 case ISD::SIGN_EXTEND:
9034 return performEXTENDCombine(N, DAG, DCI, Subtarget);
9035 case ISD::SINT_TO_FP:
9036 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9037 case ISD::UINT_TO_FP:
9038 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9039 case ISD::FP_TO_SINT:
9040 case ISD::FP_TO_UINT:
9041 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
9042 case LoongArchISD::BITREV_W:
9043 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
9044 case LoongArchISD::BR_CC:
9045 return performBR_CCCombine(N, DAG, DCI, Subtarget);
9046 case LoongArchISD::SELECT_CC:
9047 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
9049 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
9050 case LoongArchISD::MOVGR2FR_W_LA64:
9051 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
9052 case LoongArchISD::MOVFR2GR_S_LA64:
9053 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
9054 case LoongArchISD::CRC_W_B_W:
9055 case LoongArchISD::CRC_W_H_W:
9056 case LoongArchISD::CRCC_W_B_W:
9057 case LoongArchISD::CRCC_W_H_W:
9058 case LoongArchISD::VMSKLTZ:
9059 case LoongArchISD::XVMSKLTZ:
9060 return performDemandedBitsCombine(N, DAG, DCI);
9061 case LoongArchISD::SPLIT_PAIR_F64:
9062 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
9063 case LoongArchISD::VANDN:
9064 return performVANDNCombine(N, DAG, DCI, Subtarget);
9066 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
9067 case ISD::VSELECT:
9068 return performVSELECTCombine(N, DAG, DCI, Subtarget);
9069 case LoongArchISD::VPACKEV:
9070 case LoongArchISD::VPERMI:
9071 if (SDValue Result =
9072 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
9073 return Result;
9074 }
9075 return SDValue();
9076}
9077
9080 if (!ZeroDivCheck)
9081 return MBB;
9082
9083 // Build instructions:
9084 // MBB:
9085 // div(or mod) $dst, $dividend, $divisor
9086 // bne $divisor, $zero, SinkMBB
9087 // BreakMBB:
9088 // break 7 // BRK_DIVZERO
9089 // SinkMBB:
9090 // fallthrough
9091 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
9092 MachineFunction::iterator It = ++MBB->getIterator();
9093 MachineFunction *MF = MBB->getParent();
9094 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9095 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9096 MF->insert(It, BreakMBB);
9097 MF->insert(It, SinkMBB);
9098
9099 // Transfer the remainder of MBB and its successor edges to SinkMBB.
9100 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
9101 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
9102
9103 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
9104 DebugLoc DL = MI.getDebugLoc();
9105 MachineOperand &Divisor = MI.getOperand(2);
9106 Register DivisorReg = Divisor.getReg();
9107
9108 // MBB:
9109 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
9110 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
9111 .addReg(LoongArch::R0)
9112 .addMBB(SinkMBB);
9113 MBB->addSuccessor(BreakMBB);
9114 MBB->addSuccessor(SinkMBB);
9115
9116 // BreakMBB:
9117 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
9118 // definition of BRK_DIVZERO.
9119 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
9120 BreakMBB->addSuccessor(SinkMBB);
9121
9122 // Clear Divisor's kill flag.
9123 Divisor.setIsKill(false);
9124
9125 return SinkMBB;
9126}
9127
9128static MachineBasicBlock *
9130 const LoongArchSubtarget &Subtarget) {
9131 unsigned CondOpc;
9132 switch (MI.getOpcode()) {
9133 default:
9134 llvm_unreachable("Unexpected opcode");
9135 case LoongArch::PseudoVBZ:
9136 CondOpc = LoongArch::VSETEQZ_V;
9137 break;
9138 case LoongArch::PseudoVBZ_B:
9139 CondOpc = LoongArch::VSETANYEQZ_B;
9140 break;
9141 case LoongArch::PseudoVBZ_H:
9142 CondOpc = LoongArch::VSETANYEQZ_H;
9143 break;
9144 case LoongArch::PseudoVBZ_W:
9145 CondOpc = LoongArch::VSETANYEQZ_W;
9146 break;
9147 case LoongArch::PseudoVBZ_D:
9148 CondOpc = LoongArch::VSETANYEQZ_D;
9149 break;
9150 case LoongArch::PseudoVBNZ:
9151 CondOpc = LoongArch::VSETNEZ_V;
9152 break;
9153 case LoongArch::PseudoVBNZ_B:
9154 CondOpc = LoongArch::VSETALLNEZ_B;
9155 break;
9156 case LoongArch::PseudoVBNZ_H:
9157 CondOpc = LoongArch::VSETALLNEZ_H;
9158 break;
9159 case LoongArch::PseudoVBNZ_W:
9160 CondOpc = LoongArch::VSETALLNEZ_W;
9161 break;
9162 case LoongArch::PseudoVBNZ_D:
9163 CondOpc = LoongArch::VSETALLNEZ_D;
9164 break;
9165 case LoongArch::PseudoXVBZ:
9166 CondOpc = LoongArch::XVSETEQZ_V;
9167 break;
9168 case LoongArch::PseudoXVBZ_B:
9169 CondOpc = LoongArch::XVSETANYEQZ_B;
9170 break;
9171 case LoongArch::PseudoXVBZ_H:
9172 CondOpc = LoongArch::XVSETANYEQZ_H;
9173 break;
9174 case LoongArch::PseudoXVBZ_W:
9175 CondOpc = LoongArch::XVSETANYEQZ_W;
9176 break;
9177 case LoongArch::PseudoXVBZ_D:
9178 CondOpc = LoongArch::XVSETANYEQZ_D;
9179 break;
9180 case LoongArch::PseudoXVBNZ:
9181 CondOpc = LoongArch::XVSETNEZ_V;
9182 break;
9183 case LoongArch::PseudoXVBNZ_B:
9184 CondOpc = LoongArch::XVSETALLNEZ_B;
9185 break;
9186 case LoongArch::PseudoXVBNZ_H:
9187 CondOpc = LoongArch::XVSETALLNEZ_H;
9188 break;
9189 case LoongArch::PseudoXVBNZ_W:
9190 CondOpc = LoongArch::XVSETALLNEZ_W;
9191 break;
9192 case LoongArch::PseudoXVBNZ_D:
9193 CondOpc = LoongArch::XVSETALLNEZ_D;
9194 break;
9195 }
9196
9197 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9198 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9199 DebugLoc DL = MI.getDebugLoc();
9202
9203 MachineFunction *F = BB->getParent();
9204 MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
9205 MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
9206 MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
9207
9208 F->insert(It, FalseBB);
9209 F->insert(It, TrueBB);
9210 F->insert(It, SinkBB);
9211
9212 // Transfer the remainder of MBB and its successor edges to Sink.
9213 SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
9215
9216 // Insert the real instruction to BB.
9217 Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
9218 BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
9219
9220 // Insert branch.
9221 BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
9222 BB->addSuccessor(FalseBB);
9223 BB->addSuccessor(TrueBB);
9224
9225 // FalseBB.
9226 Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9227 BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
9228 .addReg(LoongArch::R0)
9229 .addImm(0);
9230 BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
9231 FalseBB->addSuccessor(SinkBB);
9232
9233 // TrueBB.
9234 Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9235 BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
9236 .addReg(LoongArch::R0)
9237 .addImm(1);
9238 TrueBB->addSuccessor(SinkBB);
9239
9240 // SinkBB: merge the results.
9241 BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
9242 MI.getOperand(0).getReg())
9243 .addReg(RD1)
9244 .addMBB(FalseBB)
9245 .addReg(RD2)
9246 .addMBB(TrueBB);
9247
9248 // The pseudo instruction is gone now.
9249 MI.eraseFromParent();
9250 return SinkBB;
9251}
9252
9253static MachineBasicBlock *
9255 const LoongArchSubtarget &Subtarget) {
9256 unsigned InsOp;
9257 unsigned BroadcastOp;
9258 unsigned HalfSize;
9259 switch (MI.getOpcode()) {
9260 default:
9261 llvm_unreachable("Unexpected opcode");
9262 case LoongArch::PseudoXVINSGR2VR_B:
9263 HalfSize = 16;
9264 BroadcastOp = LoongArch::XVREPLGR2VR_B;
9265 InsOp = LoongArch::XVEXTRINS_B;
9266 break;
9267 case LoongArch::PseudoXVINSGR2VR_H:
9268 HalfSize = 8;
9269 BroadcastOp = LoongArch::XVREPLGR2VR_H;
9270 InsOp = LoongArch::XVEXTRINS_H;
9271 break;
9272 }
9273 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9274 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
9275 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
9276 DebugLoc DL = MI.getDebugLoc();
9278 // XDst = vector_insert XSrc, Elt, Idx
9279 Register XDst = MI.getOperand(0).getReg();
9280 Register XSrc = MI.getOperand(1).getReg();
9281 Register Elt = MI.getOperand(2).getReg();
9282 unsigned Idx = MI.getOperand(3).getImm();
9283
9284 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
9285 Idx < HalfSize) {
9286 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
9287 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
9288
9289 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
9290 .addReg(XSrc, {}, LoongArch::sub_128);
9291 BuildMI(*BB, MI, DL,
9292 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
9293 : LoongArch::VINSGR2VR_B),
9294 ScratchSubReg2)
9295 .addReg(ScratchSubReg1)
9296 .addReg(Elt)
9297 .addImm(Idx);
9298
9299 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
9300 .addReg(ScratchSubReg2)
9301 .addImm(LoongArch::sub_128);
9302 } else {
9303 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9304 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9305
9306 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
9307
9308 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
9309 .addReg(ScratchReg1)
9310 .addReg(XSrc)
9311 .addImm(Idx >= HalfSize ? 48 : 18);
9312
9313 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
9314 .addReg(XSrc)
9315 .addReg(ScratchReg2)
9316 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
9317 }
9318
9319 MI.eraseFromParent();
9320 return BB;
9321}
9322
9325 const LoongArchSubtarget &Subtarget) {
9326 assert(Subtarget.hasExtLSX());
9327 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9328 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9329 DebugLoc DL = MI.getDebugLoc();
9331 Register Dst = MI.getOperand(0).getReg();
9332 Register Src = MI.getOperand(1).getReg();
9333
9334 unsigned BroadcastOp, CTOp, PickOp;
9335 switch (MI.getOpcode()) {
9336 default:
9337 llvm_unreachable("Unexpected opcode");
9338 case LoongArch::PseudoCTPOP_B:
9339 BroadcastOp = LoongArch::VREPLGR2VR_B;
9340 CTOp = LoongArch::VPCNT_B;
9341 PickOp = LoongArch::VPICKVE2GR_B;
9342 break;
9343 case LoongArch::PseudoCTPOP_H:
9344 case LoongArch::PseudoCTPOP_H_LA32:
9345 BroadcastOp = LoongArch::VREPLGR2VR_H;
9346 CTOp = LoongArch::VPCNT_H;
9347 PickOp = LoongArch::VPICKVE2GR_H;
9348 break;
9349 case LoongArch::PseudoCTPOP_W:
9350 case LoongArch::PseudoCTPOP_W_LA32:
9351 BroadcastOp = LoongArch::VREPLGR2VR_W;
9352 CTOp = LoongArch::VPCNT_W;
9353 PickOp = LoongArch::VPICKVE2GR_W;
9354 break;
9355 case LoongArch::PseudoCTPOP_D:
9356 BroadcastOp = LoongArch::VREPLGR2VR_D;
9357 CTOp = LoongArch::VPCNT_D;
9358 PickOp = LoongArch::VPICKVE2GR_D;
9359 break;
9360 }
9361
9362 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9363 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9364 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9365 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9366 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9367
9368 MI.eraseFromParent();
9369 return BB;
9370}
9371
9372static MachineBasicBlock *
9374 const LoongArchSubtarget &Subtarget) {
9375 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9376 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9377 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9379 Register Dst = MI.getOperand(0).getReg();
9380 Register Src = MI.getOperand(1).getReg();
9381 DebugLoc DL = MI.getDebugLoc();
9382 unsigned EleBits = 8;
9383 unsigned NotOpc = 0;
9384 unsigned MskOpc;
9385
9386 switch (MI.getOpcode()) {
9387 default:
9388 llvm_unreachable("Unexpected opcode");
9389 case LoongArch::PseudoVMSKLTZ_B:
9390 MskOpc = LoongArch::VMSKLTZ_B;
9391 break;
9392 case LoongArch::PseudoVMSKLTZ_H:
9393 MskOpc = LoongArch::VMSKLTZ_H;
9394 EleBits = 16;
9395 break;
9396 case LoongArch::PseudoVMSKLTZ_W:
9397 MskOpc = LoongArch::VMSKLTZ_W;
9398 EleBits = 32;
9399 break;
9400 case LoongArch::PseudoVMSKLTZ_D:
9401 MskOpc = LoongArch::VMSKLTZ_D;
9402 EleBits = 64;
9403 break;
9404 case LoongArch::PseudoVMSKGEZ_B:
9405 MskOpc = LoongArch::VMSKGEZ_B;
9406 break;
9407 case LoongArch::PseudoVMSKEQZ_B:
9408 MskOpc = LoongArch::VMSKNZ_B;
9409 NotOpc = LoongArch::VNOR_V;
9410 break;
9411 case LoongArch::PseudoVMSKNEZ_B:
9412 MskOpc = LoongArch::VMSKNZ_B;
9413 break;
9414 case LoongArch::PseudoXVMSKLTZ_B:
9415 MskOpc = LoongArch::XVMSKLTZ_B;
9416 RC = &LoongArch::LASX256RegClass;
9417 break;
9418 case LoongArch::PseudoXVMSKLTZ_H:
9419 MskOpc = LoongArch::XVMSKLTZ_H;
9420 RC = &LoongArch::LASX256RegClass;
9421 EleBits = 16;
9422 break;
9423 case LoongArch::PseudoXVMSKLTZ_W:
9424 MskOpc = LoongArch::XVMSKLTZ_W;
9425 RC = &LoongArch::LASX256RegClass;
9426 EleBits = 32;
9427 break;
9428 case LoongArch::PseudoXVMSKLTZ_D:
9429 MskOpc = LoongArch::XVMSKLTZ_D;
9430 RC = &LoongArch::LASX256RegClass;
9431 EleBits = 64;
9432 break;
9433 case LoongArch::PseudoXVMSKGEZ_B:
9434 MskOpc = LoongArch::XVMSKGEZ_B;
9435 RC = &LoongArch::LASX256RegClass;
9436 break;
9437 case LoongArch::PseudoXVMSKEQZ_B:
9438 MskOpc = LoongArch::XVMSKNZ_B;
9439 NotOpc = LoongArch::XVNOR_V;
9440 RC = &LoongArch::LASX256RegClass;
9441 break;
9442 case LoongArch::PseudoXVMSKNEZ_B:
9443 MskOpc = LoongArch::XVMSKNZ_B;
9444 RC = &LoongArch::LASX256RegClass;
9445 break;
9446 }
9447
9448 Register Msk = MRI.createVirtualRegister(RC);
9449 if (NotOpc) {
9450 Register Tmp = MRI.createVirtualRegister(RC);
9451 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9452 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk)
9453 .addReg(Tmp)
9454 .addReg(Tmp);
9455 } else {
9456 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9457 }
9458
9459 if (TRI->getRegSizeInBits(*RC) > 128) {
9460 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9461 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9462 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9463 .addReg(Msk)
9464 .addImm(0);
9465 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9466 .addReg(Msk)
9467 .addImm(4);
9468 BuildMI(*BB, MI, DL,
9469 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9470 : LoongArch::BSTRINS_W),
9471 Dst)
9472 .addReg(Lo)
9473 .addReg(Hi)
9474 .addImm(256 / EleBits - 1)
9475 .addImm(128 / EleBits);
9476 } else {
9477 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9478 .addReg(Msk)
9479 .addImm(0);
9480 }
9481
9482 MI.eraseFromParent();
9483 return BB;
9484}
9485
9486static MachineBasicBlock *
9488 const LoongArchSubtarget &Subtarget) {
9489 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9490 "Unexpected instruction");
9491
9492 MachineFunction &MF = *BB->getParent();
9493 DebugLoc DL = MI.getDebugLoc();
9495 Register LoReg = MI.getOperand(0).getReg();
9496 Register HiReg = MI.getOperand(1).getReg();
9497 Register SrcReg = MI.getOperand(2).getReg();
9498
9499 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9500 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9501 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9502 MI.eraseFromParent(); // The pseudo instruction is gone now.
9503 return BB;
9504}
9505
9506static MachineBasicBlock *
9508 const LoongArchSubtarget &Subtarget) {
9509 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9510 "Unexpected instruction");
9511
9512 MachineFunction &MF = *BB->getParent();
9513 DebugLoc DL = MI.getDebugLoc();
9516 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9517 Register DstReg = MI.getOperand(0).getReg();
9518 Register LoReg = MI.getOperand(1).getReg();
9519 Register HiReg = MI.getOperand(2).getReg();
9520
9521 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
9522 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
9523 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
9524 .addReg(TmpReg)
9525 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
9526 MI.eraseFromParent(); // The pseudo instruction is gone now.
9527 return BB;
9528}
9529
9531 switch (MI.getOpcode()) {
9532 default:
9533 return false;
9534 case LoongArch::Select_GPR_Using_CC_GPR:
9535 return true;
9536 }
9537}
9538
9539static MachineBasicBlock *
9541 const LoongArchSubtarget &Subtarget) {
9542 // To "insert" Select_* instructions, we actually have to insert the triangle
9543 // control-flow pattern. The incoming instructions know the destination vreg
9544 // to set, the condition code register to branch on, the true/false values to
9545 // select between, and the condcode to use to select the appropriate branch.
9546 //
9547 // We produce the following control flow:
9548 // HeadMBB
9549 // | \
9550 // | IfFalseMBB
9551 // | /
9552 // TailMBB
9553 //
9554 // When we find a sequence of selects we attempt to optimize their emission
9555 // by sharing the control flow. Currently we only handle cases where we have
9556 // multiple selects with the exact same condition (same LHS, RHS and CC).
9557 // The selects may be interleaved with other instructions if the other
9558 // instructions meet some requirements we deem safe:
9559 // - They are not pseudo instructions.
9560 // - They are debug instructions. Otherwise,
9561 // - They do not have side-effects, do not access memory and their inputs do
9562 // not depend on the results of the select pseudo-instructions.
9563 // The TrueV/FalseV operands of the selects cannot depend on the result of
9564 // previous selects in the sequence.
9565 // These conditions could be further relaxed. See the X86 target for a
9566 // related approach and more information.
9567
9568 Register LHS = MI.getOperand(1).getReg();
9569 Register RHS;
9570 if (MI.getOperand(2).isReg())
9571 RHS = MI.getOperand(2).getReg();
9572 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
9573
9574 SmallVector<MachineInstr *, 4> SelectDebugValues;
9575 SmallSet<Register, 4> SelectDests;
9576 SelectDests.insert(MI.getOperand(0).getReg());
9577
9578 MachineInstr *LastSelectPseudo = &MI;
9579 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
9580 SequenceMBBI != E; ++SequenceMBBI) {
9581 if (SequenceMBBI->isDebugInstr())
9582 continue;
9583 if (isSelectPseudo(*SequenceMBBI)) {
9584 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
9585 !SequenceMBBI->getOperand(2).isReg() ||
9586 SequenceMBBI->getOperand(2).getReg() != RHS ||
9587 SequenceMBBI->getOperand(3).getImm() != CC ||
9588 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
9589 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
9590 break;
9591 LastSelectPseudo = &*SequenceMBBI;
9592 SequenceMBBI->collectDebugValues(SelectDebugValues);
9593 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
9594 continue;
9595 }
9596 if (SequenceMBBI->hasUnmodeledSideEffects() ||
9597 SequenceMBBI->mayLoadOrStore() ||
9598 SequenceMBBI->usesCustomInsertionHook())
9599 break;
9600 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
9601 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
9602 }))
9603 break;
9604 }
9605
9606 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
9607 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9608 DebugLoc DL = MI.getDebugLoc();
9610
9611 MachineBasicBlock *HeadMBB = BB;
9612 MachineFunction *F = BB->getParent();
9613 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
9614 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
9615
9616 F->insert(I, IfFalseMBB);
9617 F->insert(I, TailMBB);
9618
9619 // Set the call frame size on entry to the new basic blocks.
9620 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
9621 IfFalseMBB->setCallFrameSize(CallFrameSize);
9622 TailMBB->setCallFrameSize(CallFrameSize);
9623
9624 // Transfer debug instructions associated with the selects to TailMBB.
9625 for (MachineInstr *DebugInstr : SelectDebugValues) {
9626 TailMBB->push_back(DebugInstr->removeFromParent());
9627 }
9628
9629 // Move all instructions after the sequence to TailMBB.
9630 TailMBB->splice(TailMBB->end(), HeadMBB,
9631 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
9632 // Update machine-CFG edges by transferring all successors of the current
9633 // block to the new block which will contain the Phi nodes for the selects.
9634 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
9635 // Set the successors for HeadMBB.
9636 HeadMBB->addSuccessor(IfFalseMBB);
9637 HeadMBB->addSuccessor(TailMBB);
9638
9639 // Insert appropriate branch.
9640 if (MI.getOperand(2).isImm())
9641 BuildMI(HeadMBB, DL, TII.get(CC))
9642 .addReg(LHS)
9643 .addImm(MI.getOperand(2).getImm())
9644 .addMBB(TailMBB);
9645 else
9646 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
9647
9648 // IfFalseMBB just falls through to TailMBB.
9649 IfFalseMBB->addSuccessor(TailMBB);
9650
9651 // Create PHIs for all of the select pseudo-instructions.
9652 auto SelectMBBI = MI.getIterator();
9653 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
9654 auto InsertionPoint = TailMBB->begin();
9655 while (SelectMBBI != SelectEnd) {
9656 auto Next = std::next(SelectMBBI);
9657 if (isSelectPseudo(*SelectMBBI)) {
9658 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
9659 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
9660 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
9661 .addReg(SelectMBBI->getOperand(4).getReg())
9662 .addMBB(HeadMBB)
9663 .addReg(SelectMBBI->getOperand(5).getReg())
9664 .addMBB(IfFalseMBB);
9665 SelectMBBI->eraseFromParent();
9666 }
9667 SelectMBBI = Next;
9668 }
9669
9670 F->getProperties().resetNoPHIs();
9671 return TailMBB;
9672}
9673
9674MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
9675 MachineInstr &MI, MachineBasicBlock *BB) const {
9676 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9677 DebugLoc DL = MI.getDebugLoc();
9678
9679 switch (MI.getOpcode()) {
9680 default:
9681 llvm_unreachable("Unexpected instr type to insert");
9682 case LoongArch::DIV_W:
9683 case LoongArch::DIV_WU:
9684 case LoongArch::MOD_W:
9685 case LoongArch::MOD_WU:
9686 case LoongArch::DIV_D:
9687 case LoongArch::DIV_DU:
9688 case LoongArch::MOD_D:
9689 case LoongArch::MOD_DU:
9690 return insertDivByZeroTrap(MI, BB);
9691 break;
9692 case LoongArch::WRFCSR: {
9693 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
9694 LoongArch::FCSR0 + MI.getOperand(0).getImm())
9695 .addReg(MI.getOperand(1).getReg());
9696 MI.eraseFromParent();
9697 return BB;
9698 }
9699 case LoongArch::RDFCSR: {
9700 MachineInstr *ReadFCSR =
9701 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
9702 MI.getOperand(0).getReg())
9703 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
9704 ReadFCSR->getOperand(1).setIsUndef();
9705 MI.eraseFromParent();
9706 return BB;
9707 }
9708 case LoongArch::Select_GPR_Using_CC_GPR:
9709 return emitSelectPseudo(MI, BB, Subtarget);
9710 case LoongArch::BuildPairF64Pseudo:
9711 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
9712 case LoongArch::SplitPairF64Pseudo:
9713 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
9714 case LoongArch::PseudoVBZ:
9715 case LoongArch::PseudoVBZ_B:
9716 case LoongArch::PseudoVBZ_H:
9717 case LoongArch::PseudoVBZ_W:
9718 case LoongArch::PseudoVBZ_D:
9719 case LoongArch::PseudoVBNZ:
9720 case LoongArch::PseudoVBNZ_B:
9721 case LoongArch::PseudoVBNZ_H:
9722 case LoongArch::PseudoVBNZ_W:
9723 case LoongArch::PseudoVBNZ_D:
9724 case LoongArch::PseudoXVBZ:
9725 case LoongArch::PseudoXVBZ_B:
9726 case LoongArch::PseudoXVBZ_H:
9727 case LoongArch::PseudoXVBZ_W:
9728 case LoongArch::PseudoXVBZ_D:
9729 case LoongArch::PseudoXVBNZ:
9730 case LoongArch::PseudoXVBNZ_B:
9731 case LoongArch::PseudoXVBNZ_H:
9732 case LoongArch::PseudoXVBNZ_W:
9733 case LoongArch::PseudoXVBNZ_D:
9734 return emitVecCondBranchPseudo(MI, BB, Subtarget);
9735 case LoongArch::PseudoXVINSGR2VR_B:
9736 case LoongArch::PseudoXVINSGR2VR_H:
9737 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
9738 case LoongArch::PseudoCTPOP_B:
9739 case LoongArch::PseudoCTPOP_H:
9740 case LoongArch::PseudoCTPOP_W:
9741 case LoongArch::PseudoCTPOP_D:
9742 case LoongArch::PseudoCTPOP_H_LA32:
9743 case LoongArch::PseudoCTPOP_W_LA32:
9744 return emitPseudoCTPOP(MI, BB, Subtarget);
9745 case LoongArch::PseudoVMSKLTZ_B:
9746 case LoongArch::PseudoVMSKLTZ_H:
9747 case LoongArch::PseudoVMSKLTZ_W:
9748 case LoongArch::PseudoVMSKLTZ_D:
9749 case LoongArch::PseudoVMSKGEZ_B:
9750 case LoongArch::PseudoVMSKEQZ_B:
9751 case LoongArch::PseudoVMSKNEZ_B:
9752 case LoongArch::PseudoXVMSKLTZ_B:
9753 case LoongArch::PseudoXVMSKLTZ_H:
9754 case LoongArch::PseudoXVMSKLTZ_W:
9755 case LoongArch::PseudoXVMSKLTZ_D:
9756 case LoongArch::PseudoXVMSKGEZ_B:
9757 case LoongArch::PseudoXVMSKEQZ_B:
9758 case LoongArch::PseudoXVMSKNEZ_B:
9759 return emitPseudoVMSKCOND(MI, BB, Subtarget);
9760 case TargetOpcode::STATEPOINT:
9761 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
9762 // while bl call instruction (where statepoint will be lowered at the
9763 // end) has implicit def. This def is early-clobber as it will be set at
9764 // the moment of the call and earlier than any use is read.
9765 // Add this implicit dead def here as a workaround.
9766 MI.addOperand(*MI.getMF(),
9768 LoongArch::R1, /*isDef*/ true,
9769 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
9770 /*isUndef*/ false, /*isEarlyClobber*/ true));
9771 if (!Subtarget.is64Bit())
9772 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
9773 return emitPatchPoint(MI, BB);
9774 case LoongArch::PROBED_STACKALLOC_DYN:
9775 return emitDynamicProbedAlloc(MI, BB);
9776 }
9777}
9778
9780 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
9781 unsigned *Fast) const {
9782 if (!Subtarget.hasUAL())
9783 return false;
9784
9785 // TODO: set reasonable speed number.
9786 if (Fast)
9787 *Fast = 1;
9788 return true;
9789}
9790
9791//===----------------------------------------------------------------------===//
9792// Calling Convention Implementation
9793//===----------------------------------------------------------------------===//
9794
9795// Eight general-purpose registers a0-a7 used for passing integer arguments,
9796// with a0-a1 reused to return values. Generally, the GPRs are used to pass
9797// fixed-point arguments, and floating-point arguments when no FPR is available
9798// or with soft float ABI.
9799const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
9800 LoongArch::R7, LoongArch::R8, LoongArch::R9,
9801 LoongArch::R10, LoongArch::R11};
9802
9803// PreserveNone calling convention:
9804// Arguments may be passed in any general-purpose registers except:
9805// - R1 : return address register
9806// - R22 : frame pointer
9807// - R31 : base pointer
9808//
9809// All general-purpose registers are treated as caller-saved,
9810// except R1 (RA) and R22 (FP).
9811//
9812// Non-volatile registers are allocated first so that a function
9813// can call normal functions without having to spill and reload
9814// argument registers.
9816 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
9817 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
9818 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
9819 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
9820 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
9821 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
9822 LoongArch::R20};
9823
9824// Eight floating-point registers fa0-fa7 used for passing floating-point
9825// arguments, and fa0-fa1 are also used to return values.
9826const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
9827 LoongArch::F3, LoongArch::F4, LoongArch::F5,
9828 LoongArch::F6, LoongArch::F7};
9829// FPR32 and FPR64 alias each other.
9831 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
9832 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
9833
9834const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
9835 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
9836 LoongArch::VR6, LoongArch::VR7};
9837
9838const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
9839 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
9840 LoongArch::XR6, LoongArch::XR7};
9841
9843 switch (State.getCallingConv()) {
9845 if (!State.isVarArg())
9846 return State.AllocateReg(PreserveNoneArgGPRs);
9847 [[fallthrough]];
9848 default:
9849 return State.AllocateReg(ArgGPRs);
9850 }
9851}
9852
9853// Pass a 2*GRLen argument that has been split into two GRLen values through
9854// registers or the stack as necessary.
9855static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
9856 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
9857 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
9858 ISD::ArgFlagsTy ArgFlags2) {
9859 unsigned GRLenInBytes = GRLen / 8;
9860 if (Register Reg = allocateArgGPR(State)) {
9861 // At least one half can be passed via register.
9862 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
9863 VA1.getLocVT(), CCValAssign::Full));
9864 } else {
9865 // Both halves must be passed on the stack, with proper alignment.
9866 Align StackAlign =
9867 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
9868 State.addLoc(
9870 State.AllocateStack(GRLenInBytes, StackAlign),
9871 VA1.getLocVT(), CCValAssign::Full));
9872 State.addLoc(CCValAssign::getMem(
9873 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9874 LocVT2, CCValAssign::Full));
9875 return false;
9876 }
9877 if (Register Reg = allocateArgGPR(State)) {
9878 // The second half can also be passed via register.
9879 State.addLoc(
9880 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
9881 } else {
9882 // The second half is passed via the stack, without additional alignment.
9883 State.addLoc(CCValAssign::getMem(
9884 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9885 LocVT2, CCValAssign::Full));
9886 }
9887 return false;
9888}
9889
9890// Implements the LoongArch calling convention. Returns true upon failure.
9892 unsigned ValNo, MVT ValVT,
9893 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
9894 CCState &State, bool IsRet, Type *OrigTy) {
9895 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
9896 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
9897 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
9898 MVT LocVT = ValVT;
9899
9900 // Any return value split into more than two values can't be returned
9901 // directly.
9902 if (IsRet && ValNo > 1)
9903 return true;
9904
9905 // If passing a variadic argument, or if no FPR is available.
9906 bool UseGPRForFloat = true;
9907
9908 switch (ABI) {
9909 default:
9910 llvm_unreachable("Unexpected ABI");
9911 break;
9916 UseGPRForFloat = ArgFlags.isVarArg();
9917 break;
9920 break;
9921 }
9922
9923 // If this is a variadic argument, the LoongArch calling convention requires
9924 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
9925 // byte alignment. An aligned register should be used regardless of whether
9926 // the original argument was split during legalisation or not. The argument
9927 // will not be passed by registers if the original type is larger than
9928 // 2*GRLen, so the register alignment rule does not apply.
9929 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
9930 if (ArgFlags.isVarArg() &&
9931 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
9932 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
9933 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
9934 // Skip 'odd' register if necessary.
9935 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
9936 State.AllocateReg(ArgGPRs);
9937 }
9938
9939 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
9940 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
9941 State.getPendingArgFlags();
9942
9943 assert(PendingLocs.size() == PendingArgFlags.size() &&
9944 "PendingLocs and PendingArgFlags out of sync");
9945
9946 // FPR32 and FPR64 alias each other.
9947 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
9948 UseGPRForFloat = true;
9949
9950 if (UseGPRForFloat && ValVT == MVT::f32) {
9951 LocVT = GRLenVT;
9952 LocInfo = CCValAssign::BCvt;
9953 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
9954 LocVT = MVT::i64;
9955 LocInfo = CCValAssign::BCvt;
9956 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
9957 // Handle passing f64 on LA32D with a soft float ABI or when floating point
9958 // registers are exhausted.
9959 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
9960 // Depending on available argument GPRS, f64 may be passed in a pair of
9961 // GPRs, split between a GPR and the stack, or passed completely on the
9962 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
9963 // cases.
9964 MCRegister Reg = allocateArgGPR(State);
9965 if (!Reg) {
9966 int64_t StackOffset = State.AllocateStack(8, Align(8));
9967 State.addLoc(
9968 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9969 return false;
9970 }
9971 LocVT = MVT::i32;
9972 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9973 MCRegister HiReg = allocateArgGPR(State);
9974 if (HiReg) {
9975 State.addLoc(
9976 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
9977 } else {
9978 int64_t StackOffset = State.AllocateStack(4, Align(4));
9979 State.addLoc(
9980 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9981 }
9982 return false;
9983 }
9984
9985 // Split arguments might be passed indirectly, so keep track of the pending
9986 // values.
9987 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
9988 LocVT = GRLenVT;
9989 LocInfo = CCValAssign::Indirect;
9990 PendingLocs.push_back(
9991 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
9992 PendingArgFlags.push_back(ArgFlags);
9993 if (!ArgFlags.isSplitEnd()) {
9994 return false;
9995 }
9996 }
9997
9998 // If the split argument only had two elements, it should be passed directly
9999 // in registers or on the stack.
10000 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
10001 PendingLocs.size() <= 2) {
10002 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
10003 // Apply the normal calling convention rules to the first half of the
10004 // split argument.
10005 CCValAssign VA = PendingLocs[0];
10006 ISD::ArgFlagsTy AF = PendingArgFlags[0];
10007 PendingLocs.clear();
10008 PendingArgFlags.clear();
10009 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
10010 ArgFlags);
10011 }
10012
10013 // Allocate to a register if possible, or else a stack slot.
10014 Register Reg;
10015 unsigned StoreSizeBytes = GRLen / 8;
10016 Align StackAlign = Align(GRLen / 8);
10017
10018 if (ValVT == MVT::f32 && !UseGPRForFloat) {
10019 Reg = State.AllocateReg(ArgFPR32s);
10020 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
10021 Reg = State.AllocateReg(ArgFPR64s);
10022 } else if (ValVT.is128BitVector()) {
10023 Reg = State.AllocateReg(ArgVRs);
10024 UseGPRForFloat = false;
10025 StoreSizeBytes = 16;
10026 StackAlign = Align(16);
10027 } else if (ValVT.is256BitVector()) {
10028 Reg = State.AllocateReg(ArgXRs);
10029 UseGPRForFloat = false;
10030 StoreSizeBytes = 32;
10031 StackAlign = Align(32);
10032 } else {
10033 Reg = allocateArgGPR(State);
10034 }
10035
10036 unsigned StackOffset =
10037 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
10038
10039 // If we reach this point and PendingLocs is non-empty, we must be at the
10040 // end of a split argument that must be passed indirectly.
10041 if (!PendingLocs.empty()) {
10042 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
10043 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
10044 for (auto &It : PendingLocs) {
10045 if (Reg)
10046 It.convertToReg(Reg);
10047 else
10048 It.convertToMem(StackOffset);
10049 State.addLoc(It);
10050 }
10051 PendingLocs.clear();
10052 PendingArgFlags.clear();
10053 return false;
10054 }
10055 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
10056 "Expected an GRLenVT at this stage");
10057
10058 if (Reg) {
10059 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10060 return false;
10061 }
10062
10063 // When a floating-point value is passed on the stack, no bit-cast is needed.
10064 if (ValVT.isFloatingPoint()) {
10065 LocVT = ValVT;
10066 LocInfo = CCValAssign::Full;
10067 }
10068
10069 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10070 return false;
10071}
10072
10073void LoongArchTargetLowering::analyzeInputArgs(
10074 MachineFunction &MF, CCState &CCInfo,
10075 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
10076 LoongArchCCAssignFn Fn) const {
10077 FunctionType *FType = MF.getFunction().getFunctionType();
10078 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
10079 MVT ArgVT = Ins[i].VT;
10080 Type *ArgTy = nullptr;
10081 if (IsRet)
10082 ArgTy = FType->getReturnType();
10083 else if (Ins[i].isOrigArg())
10084 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
10086 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10087 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
10088 CCInfo, IsRet, ArgTy)) {
10089 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
10090 << '\n');
10091 llvm_unreachable("");
10092 }
10093 }
10094}
10095
10096void LoongArchTargetLowering::analyzeOutputArgs(
10097 MachineFunction &MF, CCState &CCInfo,
10098 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
10099 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
10100 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10101 MVT ArgVT = Outs[i].VT;
10102 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
10104 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10105 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
10106 CCInfo, IsRet, OrigTy)) {
10107 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
10108 << "\n");
10109 llvm_unreachable("");
10110 }
10111 }
10112}
10113
10114// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
10115// values.
10117 const CCValAssign &VA, const SDLoc &DL) {
10118 switch (VA.getLocInfo()) {
10119 default:
10120 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10121 case CCValAssign::Full:
10123 break;
10124 case CCValAssign::BCvt:
10125 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10126 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
10127 else
10128 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10129 break;
10130 }
10131 return Val;
10132}
10133
10135 const CCValAssign &VA, const SDLoc &DL,
10136 const ISD::InputArg &In,
10137 const LoongArchTargetLowering &TLI) {
10140 EVT LocVT = VA.getLocVT();
10141 SDValue Val;
10142 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
10143 Register VReg = RegInfo.createVirtualRegister(RC);
10144 RegInfo.addLiveIn(VA.getLocReg(), VReg);
10145 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
10146
10147 // If input is sign extended from 32 bits, note it for the OptW pass.
10148 if (In.isOrigArg()) {
10149 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
10150 if (OrigArg->getType()->isIntegerTy()) {
10151 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
10152 // An input zero extended from i31 can also be considered sign extended.
10153 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
10154 (BitWidth < 32 && In.Flags.isZExt())) {
10157 LAFI->addSExt32Register(VReg);
10158 }
10159 }
10160 }
10161
10162 return convertLocVTToValVT(DAG, Val, VA, DL);
10163}
10164
10165// The caller is responsible for loading the full value if the argument is
10166// passed with CCValAssign::Indirect.
10168 const CCValAssign &VA, const SDLoc &DL) {
10170 MachineFrameInfo &MFI = MF.getFrameInfo();
10171 EVT ValVT = VA.getValVT();
10172 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
10173 /*IsImmutable=*/true);
10174 SDValue FIN = DAG.getFrameIndex(
10176
10177 ISD::LoadExtType ExtType;
10178 switch (VA.getLocInfo()) {
10179 default:
10180 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10181 case CCValAssign::Full:
10183 case CCValAssign::BCvt:
10184 ExtType = ISD::NON_EXTLOAD;
10185 break;
10186 }
10187 return DAG.getExtLoad(
10188 ExtType, DL, VA.getLocVT(), Chain, FIN,
10190}
10191
10193 const CCValAssign &VA,
10194 const CCValAssign &HiVA,
10195 const SDLoc &DL) {
10196 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
10197 "Unexpected VA");
10199 MachineFrameInfo &MFI = MF.getFrameInfo();
10201
10202 assert(VA.isRegLoc() && "Expected register VA assignment");
10203
10204 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10205 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
10206 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
10207 SDValue Hi;
10208 if (HiVA.isMemLoc()) {
10209 // Second half of f64 is passed on the stack.
10210 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
10211 /*IsImmutable=*/true);
10212 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
10213 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
10215 } else {
10216 // Second half of f64 is passed in another GPR.
10217 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10218 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
10219 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
10220 }
10221 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
10222}
10223
10225 const CCValAssign &VA, const SDLoc &DL) {
10226 EVT LocVT = VA.getLocVT();
10227
10228 switch (VA.getLocInfo()) {
10229 default:
10230 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10231 case CCValAssign::Full:
10232 break;
10233 case CCValAssign::BCvt:
10234 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10235 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
10236 else
10237 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10238 break;
10239 }
10240 return Val;
10241}
10242
10243static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
10244 CCValAssign::LocInfo LocInfo,
10245 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
10246 CCState &State) {
10247 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
10248 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
10249 // s0 s1 s2 s3 s4 s5 s6 s7 s8
10250 static const MCPhysReg GPRList[] = {
10251 LoongArch::R23, LoongArch::R24, LoongArch::R25,
10252 LoongArch::R26, LoongArch::R27, LoongArch::R28,
10253 LoongArch::R29, LoongArch::R30, LoongArch::R31};
10254 if (MCRegister Reg = State.AllocateReg(GPRList)) {
10255 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10256 return false;
10257 }
10258 }
10259
10260 if (LocVT == MVT::f32) {
10261 // Pass in STG registers: F1, F2, F3, F4
10262 // fs0,fs1,fs2,fs3
10263 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
10264 LoongArch::F26, LoongArch::F27};
10265 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
10266 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10267 return false;
10268 }
10269 }
10270
10271 if (LocVT == MVT::f64) {
10272 // Pass in STG registers: D1, D2, D3, D4
10273 // fs4,fs5,fs6,fs7
10274 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
10275 LoongArch::F30_64, LoongArch::F31_64};
10276 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
10277 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10278 return false;
10279 }
10280 }
10281
10282 report_fatal_error("No registers left in GHC calling convention");
10283 return true;
10284}
10285
10286// Transform physical registers into virtual registers.
10288 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10289 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
10290 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
10291
10293
10294 switch (CallConv) {
10295 default:
10296 llvm_unreachable("Unsupported calling convention");
10297 case CallingConv::C:
10298 case CallingConv::Fast:
10301 break;
10302 case CallingConv::GHC:
10303 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
10304 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
10306 "GHC calling convention requires the F and D extensions");
10307 }
10308
10309 const Function &Func = MF.getFunction();
10310 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10311 MVT GRLenVT = Subtarget.getGRLenVT();
10312 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
10313
10314 // Check if this function has any musttail calls. If so, incoming indirect
10315 // arg pointers must be saved in virtual registers so they survive across
10316 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
10317 // when needed to avoid adding register pressure to non-musttail functions.
10318 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
10319 return llvm::any_of(BB, [](const Instruction &I) {
10320 if (const auto *CI = dyn_cast<CallInst>(&I))
10321 return CI->isMustTailCall();
10322 return false;
10323 });
10324 });
10325 // Used with varargs to acumulate store chains.
10326 std::vector<SDValue> OutChains;
10327
10328 // Assign locations to all of the incoming arguments.
10330 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10331
10332 if (CallConv == CallingConv::GHC)
10334 else
10335 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
10336
10337 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10338 CCValAssign &VA = ArgLocs[i];
10339 SDValue ArgValue;
10340 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10341 // case.
10342 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10343 assert(VA.needsCustom());
10344 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10345 } else if (VA.isRegLoc())
10346 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10347 else
10348 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10349 if (VA.getLocInfo() == CCValAssign::Indirect) {
10350 // If the original argument was split and passed by reference, we need to
10351 // load all parts of it here (using the same address).
10352 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10354 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10355 if (HasMusttail) {
10358 Register VReg =
10359 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10360 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10361 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10362 }
10363 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10364 assert(ArgPartOffset == 0);
10365 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10366 CCValAssign &PartVA = ArgLocs[i + 1];
10367 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10368 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10369 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10370 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10372 ++i;
10373 ++InsIdx;
10374 }
10375 continue;
10376 }
10377 InVals.push_back(ArgValue);
10378 }
10379
10380 if (IsVarArg) {
10382 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10383 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10384 MachineFrameInfo &MFI = MF.getFrameInfo();
10385 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10386 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10387
10388 // Offset of the first variable argument from stack pointer, and size of
10389 // the vararg save area. For now, the varargs save area is either zero or
10390 // large enough to hold a0-a7.
10391 int VaArgOffset, VarArgsSaveSize;
10392
10393 // If all registers are allocated, then all varargs must be passed on the
10394 // stack and we don't need to save any argregs.
10395 if (ArgRegs.size() == Idx) {
10396 VaArgOffset = CCInfo.getStackSize();
10397 VarArgsSaveSize = 0;
10398 } else {
10399 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10400 VaArgOffset = -VarArgsSaveSize;
10401 }
10402
10403 // Record the frame index of the first variable argument
10404 // which is a value necessary to VASTART.
10405 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10406 LoongArchFI->setVarArgsFrameIndex(FI);
10407
10408 // If saving an odd number of registers then create an extra stack slot to
10409 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10410 // offsets to even-numbered registered remain 2*GRLen-aligned.
10411 if (Idx % 2) {
10412 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10413 true);
10414 VarArgsSaveSize += GRLenInBytes;
10415 }
10416
10417 // Copy the integer registers that may have been used for passing varargs
10418 // to the vararg save area.
10419 for (unsigned I = Idx; I < ArgRegs.size();
10420 ++I, VaArgOffset += GRLenInBytes) {
10421 const Register Reg = RegInfo.createVirtualRegister(RC);
10422 RegInfo.addLiveIn(ArgRegs[I], Reg);
10423 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10424 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10425 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10426 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10428 cast<StoreSDNode>(Store.getNode())
10429 ->getMemOperand()
10430 ->setValue((Value *)nullptr);
10431 OutChains.push_back(Store);
10432 }
10433 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10434 }
10435
10436 // All stores are grouped in one node to allow the matching between
10437 // the size of Ins and InVals. This only happens for vararg functions.
10438 if (!OutChains.empty()) {
10439 OutChains.push_back(Chain);
10440 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10441 }
10442
10443 return Chain;
10444}
10445
10447 return CI->isTailCall();
10448}
10449
10450// Check if the return value is used as only a return value, as otherwise
10451// we can't perform a tail-call.
10453 SDValue &Chain) const {
10454 if (N->getNumValues() != 1)
10455 return false;
10456 if (!N->hasNUsesOfValue(1, 0))
10457 return false;
10458
10459 SDNode *Copy = *N->user_begin();
10460 if (Copy->getOpcode() != ISD::CopyToReg)
10461 return false;
10462
10463 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10464 // isn't safe to perform a tail call.
10465 if (Copy->getGluedNode())
10466 return false;
10467
10468 // The copy must be used by a LoongArchISD::RET, and nothing else.
10469 bool HasRet = false;
10470 for (SDNode *Node : Copy->users()) {
10471 if (Node->getOpcode() != LoongArchISD::RET)
10472 return false;
10473 HasRet = true;
10474 }
10475
10476 if (!HasRet)
10477 return false;
10478
10479 Chain = Copy->getOperand(0);
10480 return true;
10481}
10482
10483// Check whether the call is eligible for tail call optimization.
10484bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10485 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10486 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10487
10488 auto CalleeCC = CLI.CallConv;
10489 auto &Outs = CLI.Outs;
10490 auto &Caller = MF.getFunction();
10491 auto CallerCC = Caller.getCallingConv();
10492
10493 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10494
10495 // Byval parameters hand the function a pointer directly into the stack area
10496 // we want to reuse during a tail call. Working around this *is* possible
10497 // but less efficient and uglier in LowerCall. For musttail, there is no
10498 // workaround today: a byval arg requires a local copy that becomes invalid
10499 // after the tail call deallocates the caller's frame, so rejecting here
10500 // (and triggering reportFatalInternalError in LowerCall) is safer than
10501 // miscompiling.
10502 for (auto &Arg : Outs)
10503 if (Arg.Flags.isByVal())
10504 return false;
10505
10506 // musttail bypasses the remaining checks: the checks either reject cases
10507 // we handle specially (indirect args are forwarded via incoming pointers,
10508 // stack-passed args reuse the matching incoming layout, sret is forwarded
10509 // like any other pointer arg) or are optimizations not applicable to
10510 // mandatory tail calls.
10511 if (IsMustTail)
10512 return true;
10513
10514 // Do not tail call opt if the stack is used to pass parameters.
10515 if (CCInfo.getStackSize() != 0)
10516 return false;
10517
10518 // Do not tail call opt if any parameters need to be passed indirectly.
10519 for (auto &VA : ArgLocs)
10520 if (VA.getLocInfo() == CCValAssign::Indirect)
10521 return false;
10522
10523 // Do not tail call opt if either caller or callee uses struct return
10524 // semantics.
10525 auto IsCallerStructRet = Caller.hasStructRetAttr();
10526 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10527 if (IsCallerStructRet || IsCalleeStructRet)
10528 return false;
10529
10530 // The callee has to preserve all registers the caller needs to preserve.
10531 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10532 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10533 if (CalleeCC != CallerCC) {
10534 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10535 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10536 return false;
10537 }
10538 return true;
10539}
10540
10542 return DAG.getDataLayout().getPrefTypeAlign(
10543 VT.getTypeForEVT(*DAG.getContext()));
10544}
10545
10546// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
10547// and output parameter nodes.
10548SDValue
10550 SmallVectorImpl<SDValue> &InVals) const {
10551 SelectionDAG &DAG = CLI.DAG;
10552 SDLoc &DL = CLI.DL;
10554 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10556 SDValue Chain = CLI.Chain;
10557 SDValue Callee = CLI.Callee;
10558 CallingConv::ID CallConv = CLI.CallConv;
10559 bool IsVarArg = CLI.IsVarArg;
10560 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10561 MVT GRLenVT = Subtarget.getGRLenVT();
10562 bool &IsTailCall = CLI.IsTailCall;
10563
10565
10566 // Analyze the operands of the call, assigning locations to each operand.
10568 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10569
10570 if (CallConv == CallingConv::GHC)
10571 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
10572 else
10573 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
10574
10575 // Check if it's really possible to do a tail call.
10576 if (IsTailCall)
10577 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
10578
10579 if (IsTailCall)
10580 ++NumTailCalls;
10581 else if (CLI.CB && CLI.CB->isMustTailCall())
10582 report_fatal_error("failed to perform tail call elimination on a call "
10583 "site marked musttail");
10584
10585 // Get a count of how many bytes are to be pushed on the stack.
10586 unsigned NumBytes = ArgCCInfo.getStackSize();
10587
10588 // Create local copies for byval args.
10589 SmallVector<SDValue> ByValArgs;
10590 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10591 ISD::ArgFlagsTy Flags = Outs[i].Flags;
10592 if (!Flags.isByVal())
10593 continue;
10594
10595 SDValue Arg = OutVals[i];
10596 unsigned Size = Flags.getByValSize();
10597 Align Alignment = Flags.getNonZeroByValAlign();
10598
10599 int FI =
10600 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
10601 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10602 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
10603
10604 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
10605 /*IsVolatile=*/false,
10606 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
10608 ByValArgs.push_back(FIPtr);
10609 }
10610
10611 if (!IsTailCall)
10612 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
10613
10614 // Copy argument values to their designated locations.
10616 SmallVector<SDValue> MemOpChains;
10617 SDValue StackPtr;
10618 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
10619 ++i, ++OutIdx) {
10620 CCValAssign &VA = ArgLocs[i];
10621 SDValue ArgValue = OutVals[OutIdx];
10622 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
10623
10624 // Handle passing f64 on LA32D with a soft float ABI as a special case.
10625 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10626 assert(VA.isRegLoc() && "Expected register VA assignment");
10627 assert(VA.needsCustom());
10628 SDValue SplitF64 =
10629 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10630 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
10631 SDValue Lo = SplitF64.getValue(0);
10632 SDValue Hi = SplitF64.getValue(1);
10633
10634 Register RegLo = VA.getLocReg();
10635 RegsToPass.push_back(std::make_pair(RegLo, Lo));
10636
10637 // Get the CCValAssign for the Hi part.
10638 CCValAssign &HiVA = ArgLocs[++i];
10639
10640 if (HiVA.isMemLoc()) {
10641 // Second half of f64 is passed on the stack.
10642 if (!StackPtr.getNode())
10643 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10645 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10646 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
10647 // Emit the store.
10648 MemOpChains.push_back(DAG.getStore(
10649 Chain, DL, Hi, Address,
10651 } else {
10652 // Second half of f64 is passed in another GPR.
10653 Register RegHigh = HiVA.getLocReg();
10654 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
10655 }
10656 continue;
10657 }
10658
10659 // Promote the value if needed.
10660 // For now, only handle fully promoted and indirect arguments.
10661 if (VA.getLocInfo() == CCValAssign::Indirect) {
10662 // For musttail calls, reuse incoming indirect pointers instead of
10663 // creating new stack temporaries. The incoming pointers point to the
10664 // caller's caller's frame, which remains valid after a tail call.
10665 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
10668 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
10669
10670 // Resolve which formal parameter is being passed at this call
10671 // position.
10672 //
10673 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
10674 // but Outs[].OrigArgIndex is an index into a filtered arg list
10675 // (empty types removed, via CallLoweringInfo in the target-
10676 // independent layer). IncomingIndirectArgs is keyed by the
10677 // caller's unfiltered Argument::getArgNo(), so we have to walk
10678 // the caller's formals (same filter) to translate the index.
10679 // This target-independent asymmetry should be normalized so
10680 // backends do not need to re-derive the mapping.
10681 //
10682 // Steps:
10683 // 1. Find the call operand at filtered position CallArgIdx.
10684 // 2. If it is an Argument, use getArgNo() directly (same filter
10685 // for caller formals and call operands).
10686 // 3. Otherwise (computed value), walk the caller's formals and
10687 // skip empty types to map the filtered index to getArgNo().
10688 const Argument *FormalArg = nullptr;
10689 unsigned FilteredIdx = 0;
10690 for (const auto &CallArg : CLI.CB->args()) {
10691 if (CallArg->getType()->isEmptyTy())
10692 continue;
10693 if (FilteredIdx == CallArgIdx) {
10694 FormalArg = dyn_cast<Argument>(CallArg);
10695 break;
10696 }
10697 ++FilteredIdx;
10698 }
10699
10700 // For forwarded args, getArgNo() gives the unfiltered index directly.
10701 // For computed args, walk the caller's formals to resolve it.
10702 unsigned FormalArgIdx = CallArgIdx;
10703 if (FormalArg) {
10704 FormalArgIdx = FormalArg->getArgNo();
10705 } else {
10706 FilteredIdx = 0;
10707 for (const auto &Arg : MF.getFunction().args()) {
10708 if (Arg.getType()->isEmptyTy())
10709 continue;
10710 if (FilteredIdx == CallArgIdx) {
10711 FormalArgIdx = Arg.getArgNo();
10712 break;
10713 }
10714 ++FilteredIdx;
10715 }
10716 }
10717
10718 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
10719 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
10720 // Thread the CopyFromReg output chain through MemOpChains so the
10721 // TokenFactor below sequences the copy with any stores we emit
10722 // for this argument.
10723 MemOpChains.push_back(CopyOp.getValue(1));
10724 SDValue IncomingPtr = CopyOp;
10725
10726 if (!FormalArg) {
10727 // Computed value: store into the incoming indirect pointer for the
10728 // same-position formal parameter (musttail guarantees matching
10729 // prototypes, so types match). The pointer survives the tail call
10730 // since it points to the caller's caller's frame.
10731 //
10732 // The data-flow edge through IncomingPtr already prevents the
10733 // store from being scheduled before the CopyFromReg. Threading
10734 // CopyOp.getValue(1) (the copy's output chain) into the store
10735 // makes that ordering explicit on the chain edge as well, which
10736 // is the convention for memory ops chaining off their producers.
10737 MemOpChains.push_back(
10738 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
10740 // Store any split parts at their respective offsets.
10741 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10742 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10743 SDValue PartValue = OutVals[OutIdx + 1];
10744 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10745 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10746 SDValue Addr =
10747 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
10748 MemOpChains.push_back(
10749 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
10751 ++i;
10752 ++OutIdx;
10753 }
10754 }
10755 ArgValue = IncomingPtr;
10756
10757 // Skip any remaining split parts (for forwarded args, they are
10758 // covered by the forwarded pointer).
10759 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10760 ++i;
10761 ++OutIdx;
10762 }
10763 } else {
10764 // Store the argument in a stack slot and pass its address.
10765 Align StackAlign =
10766 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
10767 getPrefTypeAlign(ArgValue.getValueType(), DAG));
10768 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
10769 // If the original argument was split and passed by reference, we need
10770 // to store the required parts of it here (and pass just one address).
10771 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
10772 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10773 assert(ArgPartOffset == 0);
10774 // Calculate the total size to store. We don't have access to what we're
10775 // actually storing other than performing the loop and collecting the
10776 // info.
10778 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
10779 SDValue PartValue = OutVals[OutIdx + 1];
10780 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10781 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10782 EVT PartVT = PartValue.getValueType();
10783 StoredSize += PartVT.getStoreSize();
10784 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
10785 Parts.push_back(std::make_pair(PartValue, Offset));
10786 ++i;
10787 ++OutIdx;
10788 }
10789 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
10790 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
10791 MemOpChains.push_back(
10792 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
10794 for (const auto &Part : Parts) {
10795 SDValue PartValue = Part.first;
10796 SDValue PartOffset = Part.second;
10798 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
10799 MemOpChains.push_back(
10800 DAG.getStore(Chain, DL, PartValue, Address,
10802 }
10803 ArgValue = SpillSlot;
10804 }
10805 } else {
10806 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
10807 }
10808
10809 // Use local copy if it is a byval arg.
10810 if (Flags.isByVal())
10811 ArgValue = ByValArgs[j++];
10812
10813 if (VA.isRegLoc()) {
10814 // Queue up the argument copies and emit them at the end.
10815 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
10816 } else {
10817 assert(VA.isMemLoc() && "Argument not register or memory");
10818 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
10819 "Tail call not allowed if stack is used for passing parameters");
10820
10821 // Work out the address of the stack slot.
10822 if (!StackPtr.getNode())
10823 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10825 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10827
10828 // Emit the store.
10829 MemOpChains.push_back(
10830 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
10831 }
10832 }
10833
10834 // Join the stores, which are independent of one another.
10835 if (!MemOpChains.empty())
10836 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
10837
10838 SDValue Glue;
10839
10840 // Build a sequence of copy-to-reg nodes, chained and glued together.
10841 for (auto &Reg : RegsToPass) {
10842 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
10843 Glue = Chain.getValue(1);
10844 }
10845
10846 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
10847 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
10848 // split it and then direct call can be matched by PseudoCALL_SMALL.
10850 const GlobalValue *GV = S->getGlobal();
10851 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
10854 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
10855 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
10856 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
10859 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
10860 }
10861
10862 // The first call operand is the chain and the second is the target address.
10864 Ops.push_back(Chain);
10865 Ops.push_back(Callee);
10866
10867 // Add argument registers to the end of the list so that they are
10868 // known live into the call.
10869 for (auto &Reg : RegsToPass)
10870 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
10871
10872 if (!IsTailCall) {
10873 // Add a register mask operand representing the call-preserved registers.
10874 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
10875 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
10876 assert(Mask && "Missing call preserved mask for calling convention");
10877 Ops.push_back(DAG.getRegisterMask(Mask));
10878 }
10879
10880 // Glue the call to the argument copies, if any.
10881 if (Glue.getNode())
10882 Ops.push_back(Glue);
10883
10884 // Emit the call.
10885 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
10886 unsigned Op;
10887 switch (DAG.getTarget().getCodeModel()) {
10888 default:
10889 report_fatal_error("Unsupported code model");
10890 case CodeModel::Small:
10891 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
10892 break;
10893 case CodeModel::Medium:
10894 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
10895 break;
10896 case CodeModel::Large:
10897 assert(Subtarget.is64Bit() && "Large code model requires LA64");
10898 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
10899 break;
10900 }
10901
10902 if (IsTailCall) {
10904 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
10905 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
10906 return Ret;
10907 }
10908
10909 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
10910 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
10911 Glue = Chain.getValue(1);
10912
10913 // Mark the end of the call, which is glued to the call itself.
10914 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
10915 Glue = Chain.getValue(1);
10916
10917 // Assign locations to each value returned by this call.
10919 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
10920 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
10921
10922 // Copy all of the result registers out of their specified physreg.
10923 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
10924 auto &VA = RVLocs[i];
10925 // Copy the value out.
10926 SDValue RetValue =
10927 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
10928 // Glue the RetValue to the end of the call sequence.
10929 Chain = RetValue.getValue(1);
10930 Glue = RetValue.getValue(2);
10931
10932 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10933 assert(VA.needsCustom());
10934 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
10935 MVT::i32, Glue);
10936 Chain = RetValue2.getValue(1);
10937 Glue = RetValue2.getValue(2);
10938 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
10939 RetValue, RetValue2);
10940 } else
10941 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
10942
10943 InVals.push_back(RetValue);
10944 }
10945
10946 return Chain;
10947}
10948
10950 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
10951 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
10952 const Type *RetTy) const {
10954 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
10955
10956 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10957 LoongArchABI::ABI ABI =
10958 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10959 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
10960 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
10961 return false;
10962 }
10963 return true;
10964}
10965
10967 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10969 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
10970 SelectionDAG &DAG) const {
10971 // Stores the assignment of the return value to a location.
10973
10974 // Info about the registers and stack slot.
10975 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
10976 *DAG.getContext());
10977
10978 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
10979 nullptr, CC_LoongArch);
10980 if (CallConv == CallingConv::GHC && !RVLocs.empty())
10981 report_fatal_error("GHC functions return void only");
10982 SDValue Glue;
10983 SmallVector<SDValue, 4> RetOps(1, Chain);
10984
10985 // Copy the result values into the output registers.
10986 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
10987 SDValue Val = OutVals[OutIdx];
10988 CCValAssign &VA = RVLocs[i];
10989 assert(VA.isRegLoc() && "Can only return in registers!");
10990
10991 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10992 // Handle returning f64 on LA32D with a soft float ABI.
10993 assert(VA.isRegLoc() && "Expected return via registers");
10994 assert(VA.needsCustom());
10995 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10996 DAG.getVTList(MVT::i32, MVT::i32), Val);
10997 SDValue Lo = SplitF64.getValue(0);
10998 SDValue Hi = SplitF64.getValue(1);
10999 Register RegLo = VA.getLocReg();
11000 Register RegHi = RVLocs[++i].getLocReg();
11001
11002 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
11003 Glue = Chain.getValue(1);
11004 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
11005 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
11006 Glue = Chain.getValue(1);
11007 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
11008 } else {
11009 // Handle a 'normal' return.
11010 Val = convertValVTToLocVT(DAG, Val, VA, DL);
11011 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
11012
11013 // Guarantee that all emitted copies are stuck together.
11014 Glue = Chain.getValue(1);
11015 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
11016 }
11017 }
11018
11019 RetOps[0] = Chain; // Update chain.
11020
11021 // Add the glue node if we have it.
11022 if (Glue.getNode())
11023 RetOps.push_back(Glue);
11024
11025 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
11026}
11027
11028// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
11029// Note: The following prefixes are excluded:
11030// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
11031// as they can be represented using [x]vrepli.[whb]
11033 const APInt &SplatValue, const unsigned SplatBitSize) const {
11034 uint64_t RequiredImm = 0;
11035 uint64_t V = SplatValue.getZExtValue();
11036 if (SplatBitSize == 16 && !(V & 0x00FF)) {
11037 // 4'b0101
11038 RequiredImm = (0b10101 << 8) | (V >> 8);
11039 return {true, RequiredImm};
11040 } else if (SplatBitSize == 32) {
11041 // 4'b0001
11042 if (!(V & 0xFFFF00FF)) {
11043 RequiredImm = (0b10001 << 8) | (V >> 8);
11044 return {true, RequiredImm};
11045 }
11046 // 4'b0010
11047 if (!(V & 0xFF00FFFF)) {
11048 RequiredImm = (0b10010 << 8) | (V >> 16);
11049 return {true, RequiredImm};
11050 }
11051 // 4'b0011
11052 if (!(V & 0x00FFFFFF)) {
11053 RequiredImm = (0b10011 << 8) | (V >> 24);
11054 return {true, RequiredImm};
11055 }
11056 // 4'b0110
11057 if ((V & 0xFFFF00FF) == 0xFF) {
11058 RequiredImm = (0b10110 << 8) | (V >> 8);
11059 return {true, RequiredImm};
11060 }
11061 // 4'b0111
11062 if ((V & 0xFF00FFFF) == 0xFFFF) {
11063 RequiredImm = (0b10111 << 8) | (V >> 16);
11064 return {true, RequiredImm};
11065 }
11066 // 4'b1010
11067 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
11068 RequiredImm =
11069 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11070 return {true, RequiredImm};
11071 }
11072 } else if (SplatBitSize == 64) {
11073 // 4'b1011
11074 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
11075 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
11076 RequiredImm =
11077 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11078 return {true, RequiredImm};
11079 }
11080 // 4'b1100
11081 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
11082 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
11083 RequiredImm =
11084 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
11085 return {true, RequiredImm};
11086 }
11087 // 4'b1001
11088 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
11089 uint8_t res = 0;
11090 for (int i = 0; i < 8; ++i) {
11091 uint8_t byte = x & 0xFF;
11092 if (byte == 0 || byte == 0xFF)
11093 res |= ((byte & 1) << i);
11094 else
11095 return {false, 0};
11096 x >>= 8;
11097 }
11098 return {true, res};
11099 };
11100 auto [IsSame, Suffix] = sameBitsPreByte(V);
11101 if (IsSame) {
11102 RequiredImm = (0b11001 << 8) | Suffix;
11103 return {true, RequiredImm};
11104 }
11105 }
11106 return {false, RequiredImm};
11107}
11108
11110 EVT VT) const {
11111 if (!Subtarget.hasExtLSX())
11112 return false;
11113
11114 if (VT == MVT::f32) {
11115 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
11116 return (masked == 0x3e000000 || masked == 0x40000000);
11117 }
11118
11119 if (VT == MVT::f64) {
11120 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
11121 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
11122 }
11123
11124 return false;
11125}
11126
11127// Only form FP_TO_SINT_SAT from clamp/NaN-guard idioms when it will be lowered
11128// to a single [X]VFTINTRZ/FTINTRZ, otherwise the generic expansion is worse
11129// than the original sequence.
11130bool LoongArchTargetLowering::shouldConvertFpToSat(unsigned Op, EVT FPVT,
11131 EVT VT) const {
11132 if (!isOperationLegalOrCustom(Op, VT))
11133 return false;
11134 if (VT.isVector())
11135 return FPVT.getScalarSizeInBits() == VT.getScalarSizeInBits();
11136 if (FPVT == MVT::f32)
11137 return VT.getSizeInBits() == 32 || Subtarget.hasBasicD();
11138 return FPVT == MVT::f64 && Subtarget.hasBasicD();
11139}
11140
11142LoongArchTargetLowering::getFPImmAction(const APFloat &Imm, EVT VT,
11143 bool ForCodeSize) const {
11144 // TODO: Maybe need more checks here after vector extension is supported.
11145 if (VT == MVT::f32 && !Subtarget.hasBasicF())
11147 if (VT == MVT::f64 && !Subtarget.hasBasicD())
11149 if (Imm.isZero() || isFPImmVLDILegal(Imm, VT))
11150 return FPImmAction::Legal;
11151
11152 // Immediates the size of a GPR are built from their bits. Others are built in
11153 // lowerConstantFP.
11154 if (VT.getSizeInBits() == Subtarget.getGRLen() && isFPImmCheapInGPR(Imm, VT))
11155 return FPImmAction::Bitcast;
11157}
11158
11160 EVT VT) const {
11161 // Count the instructions to generate the bits and move them to a float
11162 // register.
11163 auto Seq =
11164 LoongArchMatInt::generateInstSeq(Imm.bitcastToAPInt().getSExtValue());
11165 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
11166 return InsNum <= MaterializeFPImmInsNum || Imm.isOne();
11167}
11168
11170 return true;
11171}
11172
11174 return true;
11175}
11176
11177bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
11178 const Instruction *I) const {
11179 if (!Subtarget.is64Bit())
11180 return isa<LoadInst>(I) || isa<StoreInst>(I);
11181
11182 if (isa<LoadInst>(I))
11183 return true;
11184
11185 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
11186 // require fences beacuse we can use amswap_db.[w/d].
11187 Type *Ty = I->getOperand(0)->getType();
11188 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
11189 unsigned Size = Ty->getIntegerBitWidth();
11190 return (Size == 8 || Size == 16);
11191 }
11192
11193 return false;
11194}
11195
11197 LLVMContext &Context,
11198 EVT VT) const {
11199 if (!VT.isVector())
11200 return getPointerTy(DL);
11202}
11203
11205 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
11206 // Do not merge to float value size (128 or 256 bits) if no implicit
11207 // float attribute is set.
11208 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
11209 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
11210 if (NoFloat)
11211 return MemVT.getSizeInBits() <= MaxIntSize;
11212
11213 // Make sure we don't merge greater than our maximum supported vector width.
11214 if (Subtarget.hasExtLASX())
11215 MaxIntSize = 256;
11216 else if (Subtarget.hasExtLSX())
11217 MaxIntSize = 128;
11218
11219 return MemVT.getSizeInBits() <= MaxIntSize;
11220}
11221
11223 EVT VT = Y.getValueType();
11224
11225 if (VT.isVector())
11226 return Subtarget.hasExtLSX() && VT.isInteger();
11227
11228 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
11229}
11230
11233 MachineFunction &MF, unsigned Intrinsic) const {
11234 switch (Intrinsic) {
11235 default:
11236 return;
11237 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
11238 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
11239 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
11240 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
11241 IntrinsicInfo Info;
11243 Info.memVT = MVT::i32;
11244 Info.ptrVal = I.getArgOperand(0);
11245 Info.offset = 0;
11246 Info.align = Align(4);
11249 Infos.push_back(Info);
11250 return;
11251 // TODO: Add more Intrinsics later.
11252 }
11253 }
11254}
11255
11256// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
11257// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
11258// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
11259// regression, we need to implement it manually.
11262
11264 Op == AtomicRMWInst::And) &&
11265 "Unable to expand");
11266 unsigned MinWordSize = 4;
11267
11268 IRBuilder<> Builder(AI);
11269 LLVMContext &Ctx = Builder.getContext();
11270 const DataLayout &DL = AI->getDataLayout();
11271 Type *ValueType = AI->getType();
11272 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
11273
11274 Value *Addr = AI->getPointerOperand();
11275 PointerType *PtrTy = cast<PointerType>(Addr->getType());
11276 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
11277
11278 Value *AlignedAddr = Builder.CreateIntrinsic(
11279 Intrinsic::ptrmask, {PtrTy, IntTy},
11280 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
11281 "AlignedAddr");
11282
11283 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
11284 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
11285 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
11286 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
11287 Value *Mask = Builder.CreateShl(
11288 ConstantInt::get(WordType,
11289 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
11290 ShiftAmt, "Mask");
11291 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
11292 Value *ValOperand_Shifted =
11293 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
11294 ShiftAmt, "ValOperand_Shifted");
11295 Value *NewOperand;
11296 if (Op == AtomicRMWInst::And)
11297 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
11298 else
11299 NewOperand = ValOperand_Shifted;
11300
11301 AtomicRMWInst *NewAI =
11302 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
11303 AI->getOrdering(), AI->getSyncScopeID());
11304
11305 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
11306 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
11307 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
11308 AI->replaceAllUsesWith(FinalOldResult);
11309 AI->eraseFromParent();
11310}
11311
11314 const AtomicRMWInst *AI) const {
11315 // TODO: Add more AtomicRMWInst that needs to be extended.
11316
11317 // Since floating-point operation requires a non-trivial set of data
11318 // operations, use CmpXChg to expand.
11319 if (AI->isFloatingPointOperation() ||
11325
11326 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
11329 AI->getOperation() == AtomicRMWInst::Sub)) {
11331 }
11332
11333 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
11334 if (Subtarget.hasLAMCAS()) {
11335 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
11339 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
11341 }
11342
11343 if (Size == 8 || Size == 16)
11346}
11347
11348static Intrinsic::ID
11350 AtomicRMWInst::BinOp BinOp) {
11351 if (GRLen == 64) {
11352 switch (BinOp) {
11353 default:
11354 llvm_unreachable("Unexpected AtomicRMW BinOp");
11356 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
11357 case AtomicRMWInst::Add:
11358 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
11359 case AtomicRMWInst::Sub:
11360 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
11362 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
11364 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
11366 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
11367 case AtomicRMWInst::Max:
11368 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
11369 case AtomicRMWInst::Min:
11370 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11371 // TODO: support other AtomicRMWInst.
11372 }
11373 }
11374
11375 if (GRLen == 32) {
11376 switch (BinOp) {
11377 default:
11378 llvm_unreachable("Unexpected AtomicRMW BinOp");
11380 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11381 case AtomicRMWInst::Add:
11382 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11383 case AtomicRMWInst::Sub:
11384 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11386 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11388 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11390 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11391 case AtomicRMWInst::Max:
11392 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11393 case AtomicRMWInst::Min:
11394 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11395 // TODO: support other AtomicRMWInst.
11396 }
11397 }
11398
11399 llvm_unreachable("Unexpected GRLen\n");
11400}
11401
11404 const AtomicCmpXchgInst *CI) const {
11405
11406 if (Subtarget.hasLAMCAS())
11408
11410 if (Size == 8 || Size == 16)
11413}
11414
11416 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11417 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11418 unsigned GRLen = Subtarget.getGRLen();
11419 AtomicOrdering FailOrd = CI->getFailureOrdering();
11420 Value *FailureOrdering =
11421 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11422 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11423 if (GRLen == 64) {
11424 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11425 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11426 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11427 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11428 }
11429 Type *Tys[] = {AlignedAddr->getType()};
11430 Value *Result = Builder.CreateIntrinsic(
11431 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11432 if (GRLen == 64)
11433 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11434 return Result;
11435}
11436
11438 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11439 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11440 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11441 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11442 // mask, as this produces better code than the LL/SC loop emitted by
11443 // int_loongarch_masked_atomicrmw_xchg.
11444 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11447 if (CVal->isZero())
11448 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11449 Builder.CreateNot(Mask, "Inv_Mask"),
11450 AI->getAlign(), Ord);
11451 if (CVal->isMinusOne())
11452 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11453 AI->getAlign(), Ord);
11454 }
11455
11456 unsigned GRLen = Subtarget.getGRLen();
11457 Value *Ordering =
11458 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11459 Type *Tys[] = {AlignedAddr->getType()};
11461 AI->getModule(),
11463
11464 if (GRLen == 64) {
11465 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11466 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11467 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11468 }
11469
11470 Value *Result;
11471
11472 // Must pass the shift amount needed to sign extend the loaded value prior
11473 // to performing a signed comparison for min/max. ShiftAmt is the number of
11474 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11475 // is the number of bits to left+right shift the value in order to
11476 // sign-extend.
11477 if (AI->getOperation() == AtomicRMWInst::Min ||
11479 const DataLayout &DL = AI->getDataLayout();
11480 unsigned ValWidth =
11481 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11482 Value *SextShamt =
11483 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11484 Result = Builder.CreateCall(LlwOpScwLoop,
11485 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11486 } else {
11487 Result =
11488 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11489 }
11490
11491 if (GRLen == 64)
11492 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11493 return Result;
11494}
11495
11497 const MachineFunction &MF, EVT VT) const {
11498 VT = VT.getScalarType();
11499
11500 if (!VT.isSimple())
11501 return false;
11502
11503 switch (VT.getSimpleVT().SimpleTy) {
11504 case MVT::f32:
11505 case MVT::f64:
11506 return true;
11507 default:
11508 break;
11509 }
11510
11511 return false;
11512}
11513
11515 ExceptionHandling EH, const Constant *PersonalityFn) const {
11516 return LoongArch::R4;
11517}
11518
11520 ExceptionHandling EH, const Constant *PersonalityFn) const {
11521 return LoongArch::R5;
11522}
11523
11524//===----------------------------------------------------------------------===//
11525// Target Optimization Hooks
11526//===----------------------------------------------------------------------===//
11527
11529 const LoongArchSubtarget &Subtarget) {
11530 // Feature FRECIPE instructions relative accuracy is 2^-14.
11531 // IEEE float has 23 digits and double has 52 digits.
11532 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11533 return RefinementSteps;
11534}
11535
11536static bool
11538 assert(Subtarget.hasFrecipe() &&
11539 "Reciprocal estimate queried on unsupported target");
11540
11541 if (!VT.isSimple())
11542 return false;
11543
11544 switch (VT.getSimpleVT().SimpleTy) {
11545 case MVT::f32:
11546 // f32 is the base type for reciprocal estimate instructions.
11547 return true;
11548
11549 case MVT::f64:
11550 return Subtarget.hasBasicD();
11551
11552 case MVT::v4f32:
11553 case MVT::v2f64:
11554 return Subtarget.hasExtLSX();
11555
11556 case MVT::v8f32:
11557 case MVT::v4f64:
11558 return Subtarget.hasExtLASX();
11559
11560 default:
11561 return false;
11562 }
11563}
11564
11566 SelectionDAG &DAG, int Enabled,
11567 int &RefinementSteps,
11568 bool &UseOneConstNR,
11569 bool Reciprocal) const {
11571 "Enabled should never be Disabled here");
11572
11573 if (!Subtarget.hasFrecipe())
11574 return SDValue();
11575
11576 SDLoc DL(Operand);
11577 EVT VT = Operand.getValueType();
11578
11579 // Check supported types.
11580 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11581 return SDValue();
11582
11583 // Handle refinement steps.
11584 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11585 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11586
11587 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
11588 UseOneConstNR = false;
11589 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
11590
11591 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
11592 // are needed (which rely on the reciprocal form), return the raw reciprocal
11593 // estimate.
11594 if (Reciprocal || RefinementSteps > 0)
11595 return Rsqrt;
11596
11597 // Otherwise, return sqrt(x) by multiplying with the operand.
11598 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
11599}
11600
11602 SelectionDAG &DAG,
11603 int Enabled,
11604 int &RefinementSteps) const {
11606 "Enabled should never be Disabled here");
11607
11608 if (!Subtarget.hasFrecipe())
11609 return SDValue();
11610
11611 SDLoc DL(Operand);
11612 EVT VT = Operand.getValueType();
11613
11614 // Check supported types.
11615 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11616 return SDValue();
11617
11618 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11619 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11620
11621 // FRECIPE computes 1.0 / x.
11622 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
11623}
11624
11625//===----------------------------------------------------------------------===//
11626// LoongArch Inline Assembly Support
11627//===----------------------------------------------------------------------===//
11628
11630LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
11631 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
11632 //
11633 // 'f': A floating-point register (if available).
11634 // 'k': A memory operand whose address is formed by a base register and
11635 // (optionally scaled) index register.
11636 // 'l': A signed 16-bit constant.
11637 // 'm': A memory operand whose address is formed by a base register and
11638 // offset that is suitable for use in instructions with the same
11639 // addressing mode as st.w and ld.w.
11640 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
11641 // instruction)
11642 // 'I': A signed 12-bit constant (for arithmetic instructions).
11643 // 'J': Integer zero.
11644 // 'K': An unsigned 12-bit constant (for logic instructions).
11645 // "ZB": An address that is held in a general-purpose register. The offset is
11646 // zero.
11647 // "ZC": A memory operand whose address is formed by a base register and
11648 // offset that is suitable for use in instructions with the same
11649 // addressing mode as ll.w and sc.w.
11650 if (Constraint.size() == 1) {
11651 switch (Constraint[0]) {
11652 default:
11653 break;
11654 case 'f':
11655 case 'q':
11656 return C_RegisterClass;
11657 case 'l':
11658 case 'I':
11659 case 'J':
11660 case 'K':
11661 return C_Immediate;
11662 case 'k':
11663 return C_Memory;
11664 }
11665 }
11666
11667 if (Constraint == "ZC" || Constraint == "ZB")
11668 return C_Memory;
11669
11670 // 'm' is handled here.
11671 return TargetLowering::getConstraintType(Constraint);
11672}
11673
11674InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
11675 StringRef ConstraintCode) const {
11676 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
11680 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
11681}
11682
11683std::pair<unsigned, const TargetRegisterClass *>
11684LoongArchTargetLowering::getRegForInlineAsmConstraint(
11685 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
11686 // First, see if this is a constraint that directly corresponds to a LoongArch
11687 // register class.
11688 if (Constraint.size() == 1) {
11689 switch (Constraint[0]) {
11690 case 'r':
11691 // TODO: Support fixed vectors up to GRLen?
11692 if (VT.isVector())
11693 break;
11694 return std::make_pair(0U, &LoongArch::GPRRegClass);
11695 case 'q':
11696 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
11697 case 'f':
11698 if (Subtarget.hasBasicF() && VT == MVT::f32)
11699 return std::make_pair(0U, &LoongArch::FPR32RegClass);
11700 if (Subtarget.hasBasicD() && VT == MVT::f64)
11701 return std::make_pair(0U, &LoongArch::FPR64RegClass);
11702 if (Subtarget.hasExtLSX() &&
11703 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
11704 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11705 if (Subtarget.hasExtLSX() && VT == MVT::i128)
11706 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11707 if (Subtarget.hasExtLASX() &&
11708 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
11709 return std::make_pair(0U, &LoongArch::LASX256RegClass);
11710 break;
11711 default:
11712 break;
11713 }
11714 }
11715
11716 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
11717 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
11718 // constraints while the official register name is prefixed with a '$'. So we
11719 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
11720 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
11721 // case insensitive, so no need to convert the constraint to upper case here.
11722 //
11723 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
11724 // decode the usage of register name aliases into their official names. And
11725 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
11726 // official register names.
11727 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
11728 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
11729 bool IsFP = Constraint[2] == 'f';
11730 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
11731 std::pair<unsigned, const TargetRegisterClass *> R;
11733 TRI, join_items("", Temp.first, Temp.second), VT);
11734 // Match those names to the widest floating point register type available.
11735 if (IsFP) {
11736 unsigned RegNo = R.first;
11737 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
11738 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
11739 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
11740 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
11741 }
11742 }
11743 }
11744 return R;
11745 }
11746
11747 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
11748}
11749
11750void LoongArchTargetLowering::LowerAsmOperandForConstraint(
11751 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
11752 SelectionDAG &DAG) const {
11753 // Currently only support length 1 constraints.
11754 if (Constraint.size() == 1) {
11755 switch (Constraint[0]) {
11756 case 'l':
11757 // Validate & create a 16-bit signed immediate operand.
11758 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11759 uint64_t CVal = C->getSExtValue();
11760 if (isInt<16>(CVal))
11761 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11762 Subtarget.getGRLenVT()));
11763 }
11764 return;
11765 case 'I':
11766 // Validate & create a 12-bit signed immediate operand.
11767 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11768 uint64_t CVal = C->getSExtValue();
11769 if (isInt<12>(CVal))
11770 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11771 Subtarget.getGRLenVT()));
11772 }
11773 return;
11774 case 'J':
11775 // Validate & create an integer zero operand.
11776 if (auto *C = dyn_cast<ConstantSDNode>(Op))
11777 if (C->getZExtValue() == 0)
11778 Ops.push_back(
11779 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
11780 return;
11781 case 'K':
11782 // Validate & create a 12-bit unsigned immediate operand.
11783 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11784 uint64_t CVal = C->getZExtValue();
11785 if (isUInt<12>(CVal))
11786 Ops.push_back(
11787 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
11788 }
11789 return;
11790 default:
11791 break;
11792 }
11793 }
11795}
11796
11797#define GET_REGISTER_MATCHER
11798#include "LoongArchGenAsmMatcher.inc"
11799
11802 const MachineFunction &MF) const {
11803 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
11804 std::string NewRegName = Name.second.str();
11805 Register Reg = MatchRegisterAltName(NewRegName);
11806 if (!Reg)
11807 Reg = MatchRegisterName(NewRegName);
11808 if (!Reg)
11809 return Reg;
11810 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
11811 if (!ReservedRegs.test(Reg))
11812 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
11813 StringRef(RegName) + "\"."));
11814 return Reg;
11815}
11816
11818 EVT VT, SDValue C) const {
11819 // TODO: Support vectors.
11820 if (!VT.isScalarInteger())
11821 return false;
11822
11823 // Omit the optimization if the data size exceeds GRLen.
11824 if (VT.getSizeInBits() > Subtarget.getGRLen())
11825 return false;
11826
11827 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
11828 const APInt &Imm = ConstNode->getAPIntValue();
11829 // Break MUL into (SLLI + ADD/SUB) or ALSL.
11830 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
11831 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
11832 return true;
11833 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
11834 if (ConstNode->hasOneUse() &&
11835 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
11836 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
11837 return true;
11838 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
11839 // in which the immediate has two set bits. Or Break (MUL x, imm)
11840 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
11841 // equals to (1 << s0) - (1 << s1).
11842 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
11843 unsigned Shifts = Imm.countr_zero();
11844 // Reject immediates which can be composed via a single LUI.
11845 if (Shifts >= 12)
11846 return false;
11847 // Reject multiplications can be optimized to
11848 // (SLLI (ALSL x, x, 1/2/3/4), s).
11849 APInt ImmPop = Imm.ashr(Shifts);
11850 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
11851 return false;
11852 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
11853 // since it needs one more instruction than other 3 cases.
11854 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
11855 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
11856 (ImmSmall - Imm).isPowerOf2())
11857 return true;
11858 }
11859 }
11860
11861 return false;
11862}
11863
11865 const AddrMode &AM,
11866 Type *Ty, unsigned AS,
11867 Instruction *I) const {
11868 // LoongArch has four basic addressing modes:
11869 // 1. reg
11870 // 2. reg + 12-bit signed offset
11871 // 3. reg + 14-bit signed offset left-shifted by 2
11872 // 4. reg1 + reg2
11873 // TODO: Add more checks after support vector extension.
11874
11875 // No global is ever allowed as a base.
11876 if (AM.BaseGV)
11877 return false;
11878
11879 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
11880 // with `UAL` feature.
11881 if (!isInt<12>(AM.BaseOffs) &&
11882 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
11883 return false;
11884
11885 switch (AM.Scale) {
11886 case 0:
11887 // "r+i" or just "i", depending on HasBaseReg.
11888 break;
11889 case 1:
11890 // "r+r+i" is not allowed.
11891 if (AM.HasBaseReg && AM.BaseOffs)
11892 return false;
11893 // Otherwise we have "r+r" or "r+i".
11894 break;
11895 case 2:
11896 // "2*r+r" or "2*r+i" is not allowed.
11897 if (AM.HasBaseReg || AM.BaseOffs)
11898 return false;
11899 // Allow "2*r" as "r+r".
11900 break;
11901 default:
11902 return false;
11903 }
11904
11905 return true;
11906}
11907
11909 return isInt<12>(Imm);
11910}
11911
11913 return isInt<12>(Imm);
11914}
11915
11917 // Zexts are free if they can be combined with a load.
11918 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
11919 // poorly with type legalization of compares preferring sext.
11920 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
11921 EVT MemVT = LD->getMemoryVT();
11922 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
11923 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
11924 LD->getExtensionType() == ISD::ZEXTLOAD))
11925 return true;
11926 }
11927
11928 return TargetLowering::isZExtFree(Val, VT2);
11929}
11930
11932 EVT DstVT) const {
11933 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
11934}
11935
11937 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
11938}
11939
11941 // TODO: Support vectors.
11942 if (Y.getValueType().isVector())
11943 return false;
11944
11945 return !isa<ConstantSDNode>(Y);
11946}
11947
11949 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
11950 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
11951}
11952
11954 Type *Ty, bool IsSigned) const {
11955 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
11956 return true;
11957
11958 return IsSigned;
11959}
11960
11962 // Return false to suppress the unnecessary extensions if the LibCall
11963 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
11964 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
11965 Type.getSizeInBits() < Subtarget.getGRLen()))
11966 return false;
11967 return true;
11968}
11969
11970// memcpy, and other memory intrinsics, typically tries to use wider load/store
11971// if the source/dest is aligned and the copy size is large enough. We therefore
11972// want to align such objects passed to memory intrinsics.
11974 unsigned &MinSize,
11975 Align &PrefAlign) const {
11976 if (!isa<MemIntrinsic>(CI))
11977 return false;
11978
11979 if (Subtarget.is64Bit()) {
11980 MinSize = 8;
11981 PrefAlign = Align(8);
11982 } else {
11983 MinSize = 4;
11984 PrefAlign = Align(4);
11985 }
11986
11987 return true;
11988}
11989
11992 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
11993 VT.getVectorElementType() != MVT::i1)
11994 return TypeWidenVector;
11995
11997}
11998
11999bool LoongArchTargetLowering::splitValueIntoRegisterParts(
12000 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
12001 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
12002 bool IsABIRegCopy = CC.has_value();
12003 EVT ValueVT = Val.getValueType();
12004
12005 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
12006 PartVT == MVT::f32) {
12007 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
12008 // nan, and cast to f32.
12009 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
12010 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
12011 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
12012 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
12013 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
12014 Parts[0] = Val;
12015 return true;
12016 }
12017
12018 return false;
12019}
12020
12021SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
12022 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
12023 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
12024 bool IsABIRegCopy = CC.has_value();
12025
12026 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
12027 PartVT == MVT::f32) {
12028 SDValue Val = Parts[0];
12029
12030 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
12031 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
12032 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
12033 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
12034 return Val;
12035 }
12036
12037 return SDValue();
12038}
12039
12040MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
12042 EVT VT) const {
12043 // Use f32 to pass f16.
12044 if (VT == MVT::f16 && Subtarget.hasBasicF())
12045 return MVT::f32;
12046
12048}
12049
12050unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
12052 // Use f32 to pass f16.
12053 if (VT == MVT::f16 && Subtarget.hasBasicF())
12054 return 1;
12055
12057}
12058
12060 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
12061 const SelectionDAG &DAG, unsigned Depth) const {
12062 unsigned Opc = Op.getOpcode();
12063 Known.resetAll();
12064 switch (Opc) {
12065 default:
12066 break;
12067 case LoongArchISD::VANYNONZERO:
12068 case LoongArchISD::VALLZERO: {
12069 // MOVCF2GR zero-extend the i1 cond to GPR.
12070 Known.Zero.setBitsFrom(1);
12071 break;
12072 }
12073 case LoongArchISD::VALL_ZERO:
12074 case LoongArchISD::VANY_ZERO:
12075 case LoongArchISD::VALL_NONZERO:
12076 case LoongArchISD::VANY_NONZERO: {
12077 // Materialized as literal 0/1 by the Pseudo{,X}VB{Z,NZ}_[BHWD]'s custom
12078 // inserter, emitVecCondBranchPseudo().
12079 Known.Zero.setBitsFrom(1);
12080 break;
12081 }
12082 case LoongArchISD::VPICK_ZEXT_ELT: {
12083 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
12084 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
12085 unsigned VTBits = VT.getScalarSizeInBits();
12086 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
12087 Known.Zero.setBitsFrom(VTBits);
12088 break;
12089 }
12090 case LoongArchISD::BSTRINS: {
12091 // BSTRINS X, Y, msb, lsb: replace X[msb:lsb] with Y[msb-lsb:0].
12092 unsigned Msb = Op.getConstantOperandVal(2);
12093 unsigned Lsb = Op.getConstantOperandVal(3);
12094 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12095 KnownBits Known2 = DAG.computeKnownBits(Op.getOperand(1), Depth + 1);
12096 Known.insertBits(Known2.trunc(Msb - Lsb + 1), Lsb);
12097 break;
12098 }
12099 case LoongArchISD::BSTRPICK: {
12100 // BSTRPICK X, msb, lsb: zero-extend X[msb:lsb].
12101 unsigned BitWidth = Known.getBitWidth();
12102 unsigned Msb = Op.getConstantOperandVal(1);
12103 unsigned Lsb = Op.getConstantOperandVal(2);
12104 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12105 Known = Known.extractBits(Msb - Lsb + 1, Lsb).zext(BitWidth);
12106 break;
12107 }
12108 }
12109}
12110
12112 SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
12113 unsigned Depth) const {
12114 switch (Op.getOpcode()) {
12115 default:
12116 break;
12117 case LoongArchISD::BSTRINS: {
12118 unsigned BitWidth = Op.getScalarValueSizeInBits();
12119 unsigned Msb = Op.getConstantOperandVal(2);
12120 unsigned Lsb = Op.getConstantOperandVal(3);
12121 // The bits above msb come from X.
12122 if (Msb != BitWidth - 1) {
12123 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1);
12124 return std::min(Tmp, BitWidth - 1 - Msb);
12125 }
12126 // The high bits come from Y shifted left by lsb.
12127 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(1), Depth + 1);
12128 return Tmp > Lsb ? Tmp - Lsb : 1;
12129 }
12130 }
12131 return 1;
12132}
12133
12135 SDValue Op, const APInt &OriginalDemandedBits,
12136 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
12137 unsigned Depth) const {
12138 EVT VT = Op.getValueType();
12139 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
12140 unsigned Opc = Op.getOpcode();
12141 switch (Opc) {
12142 default:
12143 break;
12144 case LoongArchISD::CRC_W_B_W:
12145 case LoongArchISD::CRC_W_H_W:
12146 case LoongArchISD::CRCC_W_B_W:
12147 case LoongArchISD::CRCC_W_H_W: {
12148 KnownBits KnownSrc;
12149 APInt DemandedSrcBits =
12150 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
12151 Opc == LoongArchISD::CRCC_W_B_W)
12152 ? 8
12153 : 16);
12154 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
12155 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
12156 }
12157 case LoongArchISD::VMSKLTZ:
12158 case LoongArchISD::XVMSKLTZ: {
12159 SDValue Src = Op.getOperand(0);
12160 MVT SrcVT = Src.getSimpleValueType();
12161 unsigned SrcBits = SrcVT.getScalarSizeInBits();
12162 unsigned NumElts = SrcVT.getVectorNumElements();
12163
12164 // If we don't need the sign bits at all just return zero.
12165 if (OriginalDemandedBits.countr_zero() >= NumElts)
12166 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
12167
12168 // Only demand the vector elements of the sign bits we need.
12169 APInt KnownUndef, KnownZero;
12170 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
12171 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
12172 TLO, Depth + 1))
12173 return true;
12174
12175 Known.Zero = KnownZero.zext(BitWidth);
12176 Known.Zero.setHighBits(BitWidth - NumElts);
12177
12178 // [X]VMSKLTZ only uses the MSB from each vector element.
12179 KnownBits KnownSrc;
12180 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
12181 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
12182 Depth + 1))
12183 return true;
12184
12185 if (KnownSrc.One[SrcBits - 1])
12186 Known.One.setLowBits(NumElts);
12187 else if (KnownSrc.Zero[SrcBits - 1])
12188 Known.Zero.setLowBits(NumElts);
12189
12190 // Attempt to avoid multi-use ops if we don't need anything from it.
12192 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
12193 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
12194 return false;
12195 }
12196 }
12197
12199 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
12200}
12201
12203 unsigned Opc = VecOp.getOpcode();
12204
12205 // Assume target opcodes can't be scalarized.
12206 // TODO - do we have any exceptions?
12207 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
12208 return false;
12209
12210 // If the vector op is not supported, try to convert to scalar.
12211 EVT VecVT = VecOp.getValueType();
12213 return true;
12214
12215 // If the vector op is supported, but the scalar op is not, the transform may
12216 // not be worthwhile.
12217 EVT ScalarVT = VecVT.getScalarType();
12218 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
12219}
12220
12223 unsigned Index) const {
12226
12227 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
12228 if (Index == 0)
12231}
12232
12234 unsigned Index) const {
12235 EVT EltVT = VT.getScalarType();
12236
12237 // Extract a scalar FP value from index 0 of a vector is free.
12238 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
12239}
12240
12242 const MachineFunction &MF) const {
12243
12244 // If the function specifically requests inline stack probes, emit them.
12245 if (MF.getFunction().hasFnAttribute("probe-stack"))
12246 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
12247 "inline-asm";
12248
12249 return false;
12250}
12251
12253 Align StackAlign) const {
12254 // The default stack probe size is 4096 if the function has no
12255 // stack-probe-size attribute.
12256 const Function &Fn = MF.getFunction();
12257 unsigned StackProbeSize =
12258 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
12259 // Round down to the stack alignment.
12260 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
12261 return StackProbeSize ? StackProbeSize : StackAlign.value();
12262}
12263
12264SDValue
12265LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
12266 SelectionDAG &DAG) const {
12268 if (!hasInlineStackProbe(MF))
12269 return SDValue();
12270
12271 const MVT GRLenVT = Subtarget.getGRLenVT();
12272 // Get the inputs.
12273 SDValue Chain = Op.getOperand(0);
12274 SDValue Size = Op.getOperand(1);
12275
12276 const MaybeAlign Align =
12277 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
12278 const SDLoc dl(Op);
12279 const EVT VT = Op.getValueType();
12280
12281 // Construct the new SP value in a GPR.
12282 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
12283 Chain = SP.getValue(1);
12284 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
12285 if (Align)
12286 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
12287 DAG.getSignedConstant(-Align->value(), dl, VT));
12288
12289 // Set the real SP to the new value with a probing loop.
12290 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
12291 return DAG.getMergeValues({SP, Chain}, dl);
12292}
12293
12296 MachineBasicBlock *MBB) const {
12297 MachineFunction &MF = *MBB->getParent();
12298 MachineBasicBlock::iterator MBBI = MI.getIterator();
12299 DebugLoc DL = MBB->findDebugLoc(MBBI);
12300 const Register TargetReg = MI.getOperand(0).getReg();
12301
12302 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
12303 const bool IsLA64 = Subtarget.is64Bit();
12304 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
12305 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
12306 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
12307
12308 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
12309 MachineBasicBlock *const LoopTestMBB =
12310 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12311 MF.insert(MBBInsertPoint, LoopTestMBB);
12312 MachineBasicBlock *const ExitMBB =
12313 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12314 MF.insert(MBBInsertPoint, ExitMBB);
12315 const Register SPReg = LoongArch::R3;
12316 const Register ScratchReg =
12317 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
12318
12319 // ScratchReg = ProbeSize
12320 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
12321
12322 // LoopTest:
12323 // sub.{w/d} $sp, $sp, ScratchReg
12324 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12325 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
12326 .addReg(SPReg)
12327 .addReg(ScratchReg);
12328
12329 // st.{w/d} $zero, $sp, 0
12330 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12331 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
12332 .addReg(LoongArch::R0)
12333 .addReg(SPReg)
12334 .addImm(0);
12335
12336 // bltu TargetReg, $sp, LoopTest
12337 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
12338 .addReg(TargetReg)
12339 .addReg(SPReg)
12340 .addMBB(LoopTestMBB);
12341
12342 // move $sp, TargetReg
12343 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
12344 .addReg(TargetReg)
12345 .addReg(LoongArch::R0);
12346
12347 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
12349
12350 LoopTestMBB->addSuccessor(ExitMBB);
12351 LoopTestMBB->addSuccessor(LoopTestMBB);
12352 MBB->addSuccessor(LoopTestMBB);
12353
12354 MI.eraseFromParent();
12355 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
12356 return ExitMBB->begin()->getParent();
12357}
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:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static MachineBasicBlock * emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode)
static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static bool isSigned(unsigned Opcode)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RegName(no)
static SDValue performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
const MCPhysReg ArgFPR32s[]
static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 128-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
const MCPhysReg ArgVRs[]
static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKEV (if possible).
static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
static SDValue unpackF64OnLA32DSoftABI(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const CCValAssign &HiVA, const SDLoc &DL)
static bool fitsRegularPattern(typename SmallVectorImpl< ValType >::const_iterator Begin, unsigned CheckStride, typename SmallVectorImpl< ValType >::const_iterator End, ValType ExpectedIndex, unsigned ExpectedIndexStride)
Determine whether a range fits a regular pattern of values.
static SDValue lowerVECTOR_SHUFFLE_IsReverse(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE whose result is the reversed source vector.
static SDValue PromoteMaskArithmetic(SDValue N, const SDLoc &DL, EVT VT, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned Depth)
static SDValue performUINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performHorizWideningCombine(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static std::pair< SDValue, EVT > stripSignExtendInReg(SDValue V)
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static SDValue lowerVECTOR_SHUFFLE_XVPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF.
static int getEstimateRefinementSteps(EVT VT, const LoongArchSubtarget &Subtarget)
static bool isSupportedReciprocalEstimateType(EVT VT, const LoongArchSubtarget &Subtarget)
static void emitErrorAndReplaceIntrinsicResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, StringRef ErrorMsg, bool WithChain=true)
static SDValue lowerVECTOR_SHUFFLEAsByteRotate(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE as byte rotate (if possible).
static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVINSVE0(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
static SDValue performMOVFR2GR_SCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVH (if possible).
static SDValue performDemandedBitsCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
static std::tuple< unsigned, SDValue, EVT > matchBinOpWithSharedOperand(SDValue BinV, SDValue X)
static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static SDValue performSPLIT_PAIR_F64Combine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performBITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static MachineBasicBlock * emitSplitPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG)
static SDValue performSETCC_BITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
@ NoMaterializeFPImm
@ MaterializeFPImm2Ins
@ MaterializeFPImm5Ins
@ MaterializeFPImm6Ins
@ MaterializeFPImm3Ins
@ MaterializeFPImm4Ins
static SDValue performEXTENDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
static bool buildVPERMIInfo(ArrayRef< int > Mask, SDValue V1, SDValue V2, SmallVectorImpl< SDValue > &SrcVec, unsigned &MaskImm)
static std::optional< bool > matchSetCC(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue Val)
static SDValue combineAndNotIntoVANDN(SDNode *N, const SDLoc &DL, SelectionDAG &DAG)
Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
static SDValue lowerBUILD_VECTORAsBroadCastLoad(BuildVectorSDNode *BVOp, const SDLoc &DL, SelectionDAG &DAG)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG)
static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size, unsigned Depth)
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
static SDValue lowerVECTOR_SHUFFLEAsShift(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as shift (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, Type *OrigTy, CCState &State)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVECTOR_SHUFFLE_VEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG)
static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKEV (if possible).
static MachineBasicBlock * emitPseudoVMSKCOND(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performVANDNCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
Do target-specific dag combines on LoongArchISD::VANDN nodes.
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVPERMIQ(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
static cl::opt< MaterializeFPImm > MaterializeFPImmInsNum("loongarch-materialize-float-imm", cl::Hidden, cl::desc("Maximum number of instructions used (including code sequence " "to generate the value and moving the value to FPR) when " "materializing floating-point immediates (default = 3)"), cl::init(MaterializeFPImm3Ins), cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"), clEnumValN(MaterializeFPImm2Ins, "2", "Materialize FP immediate within 2 instructions"), clEnumValN(MaterializeFPImm3Ins, "3", "Materialize FP immediate within 3 instructions"), clEnumValN(MaterializeFPImm4Ins, "4", "Materialize FP immediate within 4 instructions"), clEnumValN(MaterializeFPImm5Ins, "5", "Materialize FP immediate within 5 instructions"), clEnumValN(MaterializeFPImm6Ins, "6", "Materialize FP immediate within 6 instructions " "(behaves same as 5 on loongarch64)")))
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
const MCPhysReg ArgXRs[]
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
static unsigned getLoongArchWOpcode(unsigned Opcode)
const MCPhysReg ArgFPR64s[]
static MachineBasicBlock * emitPseudoCTPOP(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performMOVGR2FR_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKOD (if possible).
static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL)
static SDValue isNOT(SDValue V, SelectionDAG &DAG)
static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 256-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
const MCPhysReg PreserveNoneArgGPRs[]
static void fillVector(ArrayRef< SDValue > Ops, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, SDValue &Vector, EVT ResTy)
static SDValue fillSubVectorFromBuildVector(BuildVectorSDNode *Node, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, EVT ResTy, unsigned first)
static bool isSelectPseudo(MachineInstr &MI)
static SDValue foldVMskZeroTest(SDValue LHS, SDValue RHS, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue foldBinOpIntoSelectIfProfitable(SDNode *BO, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
const MCPhysReg ArgGPRs[]
static SDValue lowerVECTOR_SHUFFLE_XVPERM(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERM (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVL (if possible).
static SDValue performFP_TO_INTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, unsigned ExtOpc=ISD::ANY_EXTEND)
static void replaceVecCondBranchResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
#define ASRT_LE_GT_CASE(NAME)
static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex)
static SDValue performBR_CCCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static void computeZeroableShuffleElements(ArrayRef< int > Mask, SDValue V1, SDValue V2, APInt &KnownUndef, APInt &KnownZero)
Compute whether each element of a shuffle is zeroable.
static SDValue combineFP_ROUND(SDValue N, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue performCONCAT_VECTORSCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue widenShuffleMask(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
static 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
MachineBasicBlock * Folded
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
MachineInstr *& Lo
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue, bool AllowSymbol=false)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool isSequentialOrUndefInRange(ArrayRef< int > Mask, unsigned Pos, unsigned Size, int Low, int Step=1)
Return true if every element in Mask, beginning from position Pos and ending in Pos + Size,...
Value * RHS
Value * LHS
bool isZero() const
Definition APFloat.h:1579
APInt bitcastToAPInt() const
Definition APFloat.h:1475
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1350
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:367
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1659
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:431
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1261
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
Definition APInt.h:282
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition Argument.h:50
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
An instruction that atomically checks whether a specified value is in a memory location,...
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ UDecWrap
Decrement one until a minimum value or zero.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
bool isFloatingPointOperation() const
BinOp getOperation() const
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool test(unsigned Idx) const
Returns true if bit Idx is set.
Definition BitVector.h:482
size_type count() const
Returns the number of bits which are set.
Definition BitVector.h:181
A "pseudo-class" with methods for operating on BUILD_VECTORs.
CCState - This class holds information needed while lowering arguments and return values.
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
LLVM_ABI void AnalyzeCallOperands(const SmallVectorImpl< ISD::OutputArg > &Outs, CCAssignFn Fn)
AnalyzeCallOperands - Analyze the outgoing arguments to a call, incorporating info about the passed v...
uint64_t getStackSize() const
Returns the size of the currently allocated portion of the stack.
LLVM_ABI void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
CCValAssign - Represent assignment of one arg/retval to a location.
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP, bool IsCustom=false)
static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP)
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool needsCustom() const
int64_t getLocMemOffset() const
unsigned getValNo() const
static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
const APFloat & getValueAPF() const
This is the shared class of boolean and integer constants.
Definition Constants.h:87
bool isMinusOne() const
This function will return true iff every bit in this constant is set to true.
Definition Constants.h:231
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition Constants.h:219
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
Definition DataLayout.h:501
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
A debug info location.
Definition DebugLoc.h:126
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
iterator_range< arg_iterator > args()
Definition Function.h:877
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:766
uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const
For a string attribute Kind, parse attribute as an integer.
Definition Function.cpp:778
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Argument * getArg(unsigned i) const
Definition Function.h:871
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
bool isDSOLocal() const
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h: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.
unsigned ComputeNumSignBitsForTargetNode(SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
This method can be implemented by targets that want to expose additional information about sign bits ...
bool isLegalICmpImmediate(int64_t Imm) const override
Return true if the specified immediate is legal icmp immediate, that is the target has icmp instructi...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
bool isFPImmCheapInGPR(const APFloat &Imm, EVT VT) const
Returns true if building Imm in a GPR and moving it to a float register is cheaper than loading it fr...
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< bool, uint64_t > isImmVLDILegalForMode1(const APInt &SplatValue, const unsigned SplatBitSize) const
Check if a constant splat can be generated using [x]vldi, where imm[12] is 1.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this function.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
Register getExceptionSelectorRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
bool isExtractVecEltCheap(EVT VT, unsigned Index) const override
Return true if extraction of a scalar element from the given vector type at the given index is cheap.
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override
Return true if sign-extension from FromTy to ToTy is cheaper than zero-extension.
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const override
Determine if the target supports unaligned memory accesses.
bool isCheapToSpeculateCtlz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic ctlz.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
bool shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, Align &PrefAlign) const override
Return true if the pointer arguments to CI should be aligned by aligning the object whose address is ...
Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override
Perform a masked atomicrmw using a target-specific intrinsic.
bool isZExtFree(SDValue Val, EVT VT2) const override
Return true if zero-extending the specific node Val to type VT2 is free (either because it's implicit...
void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
Determine which of the bits specified in Mask are known to be either zero or one and return them in t...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, unsigned Index) const override
Return the cost of extracting a subvector of type ResVT from a vector of type SrcVT,...
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
bool isLegalAddImmediate(int64_t Imm) const override
Return true if the specified immediate is legal add immediate, that is the target has add instruction...
bool isCheapToSpeculateCttz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic cttz.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
MachineBasicBlock * emitDynamicProbedAlloc(MachineInstr &MI, MachineBasicBlock *MBB) const
bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override
Returns true if arguments should be sign-extended in lib calls.
bool shouldScalarizeBinop(SDValue VecOp) const override
Try to convert an extract element of a vector binary operation into an extract element followed by a ...
bool isFPImmVLDILegal(const APFloat &Imm, EVT VT) const
bool shouldExtendTypeInLibCall(EVT Type) const override
Returns true if arguments should be extended in lib calls.
Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override
Return the register ID of the name passed in.
bool hasAndNot(SDValue Y) const override
Return true if the target has a bitwise and-not operation: X = ~A & B This can be used to simplify se...
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override
Return true if folding a constant offset with the given GlobalAddress is legal.
unsigned getStackProbeSize(const MachineFunction &MF, Align StackAlign) const
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const override
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
void emitExpandAtomicRMW(AtomicRMWInst *AI) const override
Perform a atomicrmw expansion using a target-specific way.
ISD::NodeType getExtendForAtomicCmpSwapArg() const override
Returns how the platform's atomic compare and swap expects its comparison value to be extended (ZERO_...
LoongArchTargetLowering(const TargetMachine &TM, const LoongArchSubtarget &STI)
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
bool hasAndNotCompare(SDValue Y) const override
Return true if the target should transform: (X & Y) == Y ---> (~X & Y) == 0 (X & Y) !...
SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps) const override
Return a reciprocal estimate value for the input operand.
bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const override
Returns if it's reasonable to merge stores to MemVT size.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context, const Type *RetTy) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
bool mayBeEmittedAsTailCall(const CallInst *CI) const override
Return true if the target may be able emit the call instruction as a tail call.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
bool hasFeature(unsigned Feature) const
Machine Value Type.
static MVT getFloatingPointVT(unsigned BitWidth)
bool is128BitVector() const
Return true if this is a 128-bit vector type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool is256BitVector() const
Return true if this is a 256-bit vector type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
MVT getDoubleNumVectorElementsVT() const
MVT getHalfNumVectorElementsVT() const
Return a VT for a vector type with the same element type but half the number of elements.
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
MVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
void push_back(MachineInstr *MI)
void setCallFrameSize(unsigned N)
Set the call frame size on entry to this basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
LLVM_ABI void collectDebugValues(SmallVectorImpl< MachineInstr * > &DbgValues)
Scan instructions immediately following MI and collect any matching DBG_VALUEs.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Align getAlign() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const MachinePointerInfo & getPointerInfo() const
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
Class to represent pointers.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
LLVM_ABI bool isOnlyUserOf(const SDNode *N) const
Return true if this node is the only use of N.
size_t use_size() const
Return the number of uses of this node.
MVT getSimpleValueType(unsigned ResNo) const
Return the type of a specified result as a simple type.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
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.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
bool isOperationLegalOrCustom(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
LegalizeTypeAction getTypeAction(LLVMContext &Context, EVT VT) const
Return how we should legalize values of this type, either it is already legal (return 'Legal') or we ...
std::vector< ArgListEntry > ArgListTy
bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
bool SimplifyDemandedVectorElts(SDValue Op, const APInt &DemandedEltMask, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Vector Op.
virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const
SDValue SimplifyMultipleUseDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth=0) const
More limited version of SimplifyDemandedBits that can be used to "lookthrough" ops that don't contrib...
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
std::pair< SDValue, SDValue > LowerCallTo(CallLoweringInfo &CLI) const
This function lowers an abstract call to a function into an actual call.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Op.
virtual bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0) const
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
TargetLowering(const TargetLowering &)=delete
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::LibcallImpl LibcallImpl, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
Primary interface to the complete machine description for the target machine.
bool useTLSDESC() const
Returns true if this target uses TLS Descriptors.
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
bool shouldAssumeDSOLocal(const GlobalValue *GV) const
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
This class is used to represent EVT's, which are used to parameterize some operations.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp: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:546
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
LLVM_ABI bool widenShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Try to transform a shuffle mask by replacing elements with the scaled index for an equivalent mask of...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Other
Any other memory.
Definition ModRef.h:68
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:183
constexpr unsigned BitWidth
std::string join_items(Sep Separator, Args &&... Items)
Joins the strings in the parameter pack Items, adding Separator between the elements....
ExceptionHandling
Definition CodeGen.h:54
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isOneConstant(SDValue V)
Returns true if V is a constant integer one.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
LLVM_ABI bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Extended Value Type.
Definition ValueTypes.h:35
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition ValueTypes.h:90
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition ValueTypes.h: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...
KnownBits trunc(unsigned BitWidth) const
Return known bits for a truncation of the value we're tracking.
Definition KnownBits.h:165
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
This structure contains all information that is necessary for lowering calls.
SmallVector< ISD::InputArg, 32 > Ins
SmallVector< ISD::OutputArg, 32 > Outs
LLVM_ABI SDValue CombineTo(SDNode *N, ArrayRef< SDValue > To, bool AddTo=true)
This structure is used to pass arguments to makeLibCall function.
MakeLibCallOptions & setTypeListBeforeSoften(ArrayRef< EVT > OpsVT, EVT RetVT)
A convenience struct that encapsulates a DAG, and two SDValues for returning information from TargetL...