LLVM 23.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
116
119 GRLenVT, Custom);
120
122
127
129 setOperationAction(ISD::TRAP, MVT::Other, Legal);
130
134
136
137 // BITREV/REVB requires the 32S feature.
138 if (STI.has32S()) {
139 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
140 // we get to know which of sll and revb.2h is faster.
143
144 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
145 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
146 // and i32 could still be byte-swapped relatively cheaply.
148 } else {
156 }
157
164
167
168 // Set operations for LA64 only.
169
170 if (Subtarget.is64Bit()) {
188
192 Custom);
194 }
195
196 // Set operations for LA32 only.
197
198 if (!Subtarget.is64Bit()) {
204 if (Subtarget.hasBasicD())
206 }
207
209
210 static const ISD::CondCode FPCCToExpand[] = {
213
214 // Set operations for 'F' feature.
215
216 if (Subtarget.hasBasicF()) {
217 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
218 setTruncStoreAction(MVT::f32, MVT::f16, Expand);
219 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::bf16, Expand);
220 setTruncStoreAction(MVT::f32, MVT::bf16, Expand);
221 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
222
241 Subtarget.isSoftFPABI() ? LibCall : Custom);
243 Subtarget.isSoftFPABI() ? LibCall : Custom);
246 Subtarget.isSoftFPABI() ? LibCall : Custom);
249
250 if (Subtarget.is64Bit())
252
253 if (!Subtarget.hasBasicD()) {
255 if (Subtarget.is64Bit()) {
258 }
259 }
260 }
261
262 // Set operations for 'D' feature.
263
264 if (Subtarget.hasBasicD()) {
265 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
266 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
267 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::bf16, Expand);
268 setTruncStoreAction(MVT::f64, MVT::bf16, Expand);
269 setTruncStoreAction(MVT::f64, MVT::f16, Expand);
270 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
271 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
272
292 Subtarget.isSoftFPABI() ? LibCall : Custom);
295 Subtarget.isSoftFPABI() ? LibCall : Custom);
296
297 if (Subtarget.is64Bit())
299 }
300
301 // Set operations for 'LSX' feature.
302
303 if (Subtarget.hasExtLSX()) {
305 // Expand all truncating stores and extending loads.
306 for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
307 setTruncStoreAction(VT, InnerVT, Expand);
310 setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
311 }
312 // By default everything must be expanded. Then we will selectively turn
313 // on ones that can be effectively codegen'd.
314 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
316 }
317
318 for (MVT VT : LSXVTs) {
322
326
331 }
332 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
335 Legal);
337 VT, Legal);
344 Expand);
359 }
360 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
362 for (MVT VT : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
364 for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
367 }
369 for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
377 VT, Expand);
385 }
387 setOperationAction(ISD::FCEIL, {MVT::f32, MVT::f64}, Legal);
388 setOperationAction(ISD::FFLOOR, {MVT::f32, MVT::f64}, Legal);
389 setOperationAction(ISD::FTRUNC, {MVT::f32, MVT::f64}, Legal);
390 setOperationAction(ISD::FROUNDEVEN, {MVT::f32, MVT::f64}, Legal);
391
392 for (MVT VT :
393 {MVT::v16i8, MVT::v8i8, MVT::v4i8, MVT::v2i8, MVT::v8i16, MVT::v4i16,
394 MVT::v2i16, MVT::v4i32, MVT::v2i32, MVT::v2i64}) {
404 }
407 // We want to legalize this to an f64 load rather than an i64 load.
408 setOperationAction(ISD::LOAD, MVT::v2f32, Custom);
409 for (MVT VT : {MVT::v2i64, MVT::v4i32, MVT::v8i16})
411 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v16i32, MVT::v8i64,
412 MVT::v16i64})
414 }
415
416 // Set operations for 'LASX' feature.
417
418 if (Subtarget.hasExtLASX()) {
419 for (MVT VT : LASXVTs) {
423
429
433 }
434 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
437 Legal);
439 VT, Legal);
446 Expand);
462 }
463 for (MVT VT : {MVT::v32i8, MVT::v16i16, MVT::v8i32})
465 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64})
467 for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
471 }
472 for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
480 VT, Expand);
488 }
491 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
495 }
496 for (MVT VT :
497 {MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
500 }
501 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
503 }
504
505 // Set DAG combine for LA32 and LA64.
506 if (Subtarget.hasBasicF()) {
508 }
509
514
515 // Set DAG combine for 'LSX' feature.
516
517 if (Subtarget.hasExtLSX()) {
529 }
530
531 // Set DAG combine for 'LASX' feature.
532 if (Subtarget.hasExtLASX()) {
535 }
536
537 // Compute derived properties from the register classes.
538 computeRegisterProperties(Subtarget.getRegisterInfo());
539
541
544
545 setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
546
548
549 // Function alignments.
551 // Set preferred alignments.
552 setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
553 setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
554 setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
555
556 // cmpxchg sizes down to 8 bits become legal if LAMCAS is available.
557 if (Subtarget.hasLAMCAS())
559
560 if (Subtarget.hasSCQ()) {
563 }
564
565 // Disable strict node mutation.
566 IsStrictFPEnabled = true;
567}
568
570 const GlobalAddressSDNode *GA) const {
571 // In order to maximise the opportunity for common subexpression elimination,
572 // keep a separate ADD node for the global address offset instead of folding
573 // it in the global address node. Later peephole optimisations may choose to
574 // fold it back in when profitable.
575 return false;
576}
577
579 SelectionDAG &DAG) const {
580 switch (Op.getOpcode()) {
582 return lowerATOMIC_FENCE(Op, DAG);
584 return lowerEH_DWARF_CFA(Op, DAG);
586 return lowerGlobalAddress(Op, DAG);
588 return lowerGlobalTLSAddress(Op, DAG);
590 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
592 return lowerINTRINSIC_W_CHAIN(Op, DAG);
594 return lowerINTRINSIC_VOID(Op, DAG);
596 return lowerBlockAddress(Op, DAG);
597 case ISD::JumpTable:
598 return lowerJumpTable(Op, DAG);
599 case ISD::SHL_PARTS:
600 return lowerShiftLeftParts(Op, DAG);
601 case ISD::SRA_PARTS:
602 return lowerShiftRightParts(Op, DAG, true);
603 case ISD::SRL_PARTS:
604 return lowerShiftRightParts(Op, DAG, false);
606 return lowerConstantPool(Op, DAG);
607 case ISD::FP_TO_SINT:
608 return lowerFP_TO_SINT(Op, DAG);
609 case ISD::FP_TO_UINT:
610 return lowerFP_TO_UINT(Op, DAG);
611 case ISD::BITCAST:
612 return lowerBITCAST(Op, DAG);
613 case ISD::UINT_TO_FP:
614 return lowerUINT_TO_FP(Op, DAG);
615 case ISD::SINT_TO_FP:
616 return lowerSINT_TO_FP(Op, DAG);
617 case ISD::VASTART:
618 return lowerVASTART(Op, DAG);
619 case ISD::FRAMEADDR:
620 return lowerFRAMEADDR(Op, DAG);
621 case ISD::RETURNADDR:
622 return lowerRETURNADDR(Op, DAG);
624 return lowerSET_ROUNDING(Op, DAG);
626 return lowerGET_ROUNDING(Op, DAG);
628 return lowerWRITE_REGISTER(Op, DAG);
630 return lowerINSERT_VECTOR_ELT(Op, DAG);
632 return lowerEXTRACT_VECTOR_ELT(Op, DAG);
634 return lowerBUILD_VECTOR(Op, DAG);
636 return lowerCONCAT_VECTORS(Op, DAG);
638 return lowerVECTOR_SHUFFLE(Op, DAG);
639 case ISD::BITREVERSE:
640 return lowerBITREVERSE(Op, DAG);
642 return lowerSCALAR_TO_VECTOR(Op, DAG);
643 case ISD::PREFETCH:
644 return lowerPREFETCH(Op, DAG);
645 case ISD::SELECT:
646 return lowerSELECT(Op, DAG);
647 case ISD::BRCOND:
648 return lowerBRCOND(Op, DAG);
649 case ISD::FP_TO_FP16:
650 return lowerFP_TO_FP16(Op, DAG);
651 case ISD::FP16_TO_FP:
652 return lowerFP16_TO_FP(Op, DAG);
653 case ISD::FP_TO_BF16:
654 return lowerFP_TO_BF16(Op, DAG);
655 case ISD::BF16_TO_FP:
656 return lowerBF16_TO_FP(Op, DAG);
658 return lowerVECREDUCE_ADD(Op, DAG);
659 case ISD::ROTL:
660 case ISD::ROTR:
661 return lowerRotate(Op, DAG);
669 return lowerVECREDUCE(Op, DAG);
670 case ISD::ConstantFP:
671 return lowerConstantFP(Op, DAG);
672 case ISD::SETCC:
673 return lowerSETCC(Op, DAG);
674 case ISD::FP_ROUND:
675 return lowerFP_ROUND(Op, DAG);
676 case ISD::FP_EXTEND:
677 return lowerFP_EXTEND(Op, DAG);
679 return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
681 return lowerDYNAMIC_STACKALLOC(Op, DAG);
682 case ISD::ANY_EXTEND:
683 return lowerANY_EXTEND(Op, DAG);
684 }
685 return SDValue();
686}
687
688// Helper to attempt to return a cheaper, bit-inverted version of \p V.
690 // TODO: don't always ignore oneuse constraints.
691 V = peekThroughBitcasts(V);
692 EVT VT = V.getValueType();
693
694 // Match not(xor X, -1) -> X.
695 if (V.getOpcode() == ISD::XOR &&
696 (ISD::isBuildVectorAllOnes(V.getOperand(1).getNode()) ||
697 isAllOnesConstant(V.getOperand(1))))
698 return V.getOperand(0);
699
700 // Match not(extract_subvector(not(X)) -> extract_subvector(X).
701 if (V.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
702 (isNullConstant(V.getOperand(1)) || V.getOperand(0).hasOneUse())) {
703 if (SDValue Not = isNOT(V.getOperand(0), DAG)) {
704 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
705 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(Not), VT, Not,
706 V.getOperand(1));
707 }
708 }
709
710 // Match not(SplatVector(not(X)) -> SplatVector(X).
711 if (V.getOpcode() == ISD::BUILD_VECTOR) {
712 if (SDValue SplatValue =
713 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
714 if (!V->isOnlyUserOf(SplatValue.getNode()))
715 return SDValue();
716
717 if (SDValue Not = isNOT(SplatValue, DAG)) {
718 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
719 return DAG.getSplat(VT, SDLoc(Not), Not);
720 }
721 }
722 }
723
724 // Match not(or(not(X),not(Y))) -> and(X, Y).
725 if (V.getOpcode() == ISD::OR && DAG.getTargetLoweringInfo().isTypeLegal(VT) &&
726 V.getOperand(0).hasOneUse() && V.getOperand(1).hasOneUse()) {
727 // TODO: Handle cases with single NOT operand -> VANDN
728 if (SDValue Op1 = isNOT(V.getOperand(1), DAG))
729 if (SDValue Op0 = isNOT(V.getOperand(0), DAG))
730 return DAG.getNode(ISD::AND, SDLoc(V), VT, DAG.getBitcast(VT, Op0),
731 DAG.getBitcast(VT, Op1));
732 }
733
734 // TODO: Add more matching patterns. Such as,
735 // not(concat_vectors(not(X), not(Y))) -> concat_vectors(X, Y).
736 // not(slt(C, X)) -> slt(X - 1, C)
737 return SDValue();
738}
739
740// Combine two ISD::FP_ROUND / LoongArchISD::VFCVT nodes with same type to
741// LoongArchISD::VFCVT. For example:
742// x1 = fp_round x, 0
743// y1 = fp_round y, 0
744// z = concat_vectors x1, y1
745// Or
746// x1 = LoongArch::VFCVT undef, x
747// y1 = LoongArch::VFCVT undef, y
748// z = LoongArchISD::VPACKEV y1, x1; or LoongArchISD::VPERMI y1, x1, 68
749// can be combined to:
750// z = LoongArch::VFCVT y, x
752 const LoongArchSubtarget &Subtarget) {
753 assert(((N->getOpcode() == ISD::CONCAT_VECTORS && N->getNumOperands() == 2) ||
754 (N->getOpcode() == LoongArchISD::VPACKEV) ||
755 (N->getOpcode() == LoongArchISD::VPERMI)) &&
756 "Invalid Node");
757
758 SDValue Op0 = peekThroughBitcasts(N->getOperand(0));
759 SDValue Op1 = peekThroughBitcasts(N->getOperand(1));
760 unsigned Opcode0 = Op0.getOpcode();
761 unsigned Opcode1 = Op1.getOpcode();
762 if (Opcode0 != Opcode1)
763 return SDValue();
764
765 if (Opcode0 != ISD::FP_ROUND && Opcode0 != LoongArchISD::VFCVT)
766 return SDValue();
767
768 // Check if two nodes have only one use.
769 if (!Op0.hasOneUse() || !Op1.hasOneUse())
770 return SDValue();
771
772 EVT VT = N.getValueType();
773 EVT SVT0 = Op0.getValueType();
774 EVT SVT1 = Op1.getValueType();
775 // Check if two nodes have the same result type.
776 if (SVT0 != SVT1)
777 return SDValue();
778
779 // Check if two nodes have the same operand type.
780 EVT SSVT0 = Op0.getOperand(0).getValueType();
781 EVT SSVT1 = Op1.getOperand(0).getValueType();
782 if (SSVT0 != SSVT1)
783 return SDValue();
784
785 if (N->getOpcode() == ISD::CONCAT_VECTORS && Opcode0 == ISD::FP_ROUND) {
786 if (Subtarget.hasExtLASX() && VT.is256BitVector() && SVT0 == MVT::v4f32 &&
787 SSVT0 == MVT::v4f64) {
788 // A vector_shuffle is required in the final step, as xvfcvt instruction
789 // operates on each 128-bit segament as a lane.
790 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v8f32,
791 Op1.getOperand(0), Op0.getOperand(0));
792 SDValue Undef = DAG.getUNDEF(Res.getValueType());
793 // After VFCVT, the high part of Res comes from the high parts of Op0 and
794 // Op1, and the low part comes from the low parts of Op0 and Op1. However,
795 // the desired order requires Op0 to fully occupy the lower half and Op1
796 // the upper half of Res. The Mask reorders the elements of Res to achieve
797 // this:
798 // - The first four elements (0, 1, 4, 5) come from Op0.
799 // - The next four elements (2, 3, 6, 7) come from Op1.
800 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
801 Res = DAG.getVectorShuffle(Res.getValueType(), DL, Res, Undef, Mask);
802 return DAG.getBitcast(VT, Res);
803 }
804 }
805
806 if ((N->getOpcode() == LoongArchISD::VPACKEV ||
807 N->getOpcode() == LoongArchISD::VPERMI) &&
808 Opcode0 == LoongArchISD::VFCVT) {
809 // For VPACKEV or VPERMI, check if the first operation of VFCVT is undef.
810 if (!Op0.getOperand(0).isUndef() || !Op1.getOperand(0).isUndef())
811 return SDValue();
812
813 if (!Subtarget.hasExtLSX() || SVT0 != MVT::v4f32 || SSVT0 != MVT::v2f64)
814 return SDValue();
815
816 if (N->getOpcode() == LoongArchISD::VPACKEV &&
817 (VT == MVT::v2i64 || VT == MVT::v2f64)) {
818 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32,
819 Op0.getOperand(1), Op1.getOperand(1));
820 return DAG.getBitcast(VT, Res);
821 }
822
823 if (N->getOpcode() == LoongArchISD::VPERMI && VT == MVT::v4f32) {
824 int64_t Imm = cast<ConstantSDNode>(N->getOperand(2))->getSExtValue();
825 if (Imm != 68)
826 return SDValue();
827 return DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Op0.getOperand(1),
828 Op1.getOperand(1));
829 }
830 }
831
832 return SDValue();
833}
834
835SDValue LoongArchTargetLowering::lowerFP_ROUND(SDValue Op,
836 SelectionDAG &DAG) const {
837 SDLoc DL(Op);
838 SDValue In = Op.getOperand(0);
839 MVT VT = Op.getSimpleValueType();
840 MVT SVT = In.getSimpleValueType();
841
842 if (VT == MVT::v4f32 && SVT == MVT::v4f64) {
843 SDValue Lo, Hi;
844 std::tie(Lo, Hi) = DAG.SplitVector(In, DL);
845 return DAG.getNode(LoongArchISD::VFCVT, DL, VT, Hi, Lo);
846 }
847
848 return SDValue();
849}
850
851SDValue LoongArchTargetLowering::lowerFP_EXTEND(SDValue Op,
852 SelectionDAG &DAG) const {
853
854 SDLoc DL(Op);
855 EVT VT = Op.getValueType();
856 SDValue Src = Op->getOperand(0);
857 EVT SVT = Src.getValueType();
858
859 bool V2F32ToV2F64 =
860 VT == MVT::v2f64 && SVT == MVT::v2f32 && Subtarget.hasExtLSX();
861 bool V4F32ToV4F64 =
862 VT == MVT::v4f64 && SVT == MVT::v4f32 && Subtarget.hasExtLASX();
863 if (!V2F32ToV2F64 && !V4F32ToV4F64)
864 return SDValue();
865
866 // Check if Op is the high part of vector.
867 auto CheckVecHighPart = [](SDValue Op) {
869 if (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
870 SDValue SOp = Op.getOperand(0);
871 EVT SVT = SOp.getValueType();
872 if (!SVT.isVector() || (SVT.getVectorNumElements() % 2 != 0))
873 return SDValue();
874
875 const uint64_t Imm = Op.getConstantOperandVal(1);
876 if (Imm == SVT.getVectorNumElements() / 2)
877 return SOp;
878 return SDValue();
879 }
880 return SDValue();
881 };
882
883 unsigned Opcode;
884 SDValue VFCVTOp;
885 EVT WideOpVT = SVT.getSimpleVT().getDoubleNumVectorElementsVT();
886 SDValue ZeroIdx = DAG.getVectorIdxConstant(0, DL);
887
888 // If the operand of ISD::FP_EXTEND comes from the high part of vector,
889 // generate LoongArchISD::VFCVTH, otherwise LoongArchISD::VFCVTL.
890 if (SDValue V = CheckVecHighPart(Src)) {
891 assert(V.getValueSizeInBits() == WideOpVT.getSizeInBits() &&
892 "Unexpected wide vector");
893 Opcode = LoongArchISD::VFCVTH;
894 VFCVTOp = DAG.getBitcast(WideOpVT, V);
895 } else {
896 Opcode = LoongArchISD::VFCVTL;
897 VFCVTOp = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideOpVT,
898 DAG.getUNDEF(WideOpVT), Src, ZeroIdx);
899 }
900
901 // v2f64 = fp_extend v2f32
902 if (V2F32ToV2F64)
903 return DAG.getNode(Opcode, DL, VT, VFCVTOp);
904
905 // v4f64 = fp_extend v4f32
906 if (V4F32ToV4F64) {
907 // XVFCVT instruction operates on each 128-bit segment as a lane, so a
908 // vector_shuffle is required firstly.
909 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
910 SDValue Res = DAG.getVectorShuffle(WideOpVT, DL, VFCVTOp,
911 DAG.getUNDEF(WideOpVT), Mask);
912 Res = DAG.getNode(Opcode, DL, VT, Res);
913 return Res;
914 }
915
916 return SDValue();
917}
918
919SDValue LoongArchTargetLowering::lowerConstantFP(SDValue Op,
920 SelectionDAG &DAG) const {
921 EVT VT = Op.getValueType();
922 ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
923 const APFloat &FPVal = CFP->getValueAPF();
924 SDLoc DL(CFP);
925
926 assert((VT == MVT::f32 && Subtarget.hasBasicF()) ||
927 (VT == MVT::f64 && Subtarget.hasBasicD()));
928
929 // If value is 0.0 or -0.0, just ignore it.
930 if (FPVal.isZero())
931 return SDValue();
932
933 // If lsx enabled, use cheaper 'vldi' instruction if possible.
934 if (isFPImmVLDILegal(FPVal, VT))
935 return SDValue();
936
937 // Construct as integer, and move to float register.
938 APInt INTVal = FPVal.bitcastToAPInt();
939
940 // If more than MaterializeFPImmInsNum instructions will be used to
941 // generate the INTVal and move it to float register, fallback to
942 // use floating point load from the constant pool.
944 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
945 if (InsNum > MaterializeFPImmInsNum && !FPVal.isOne())
946 return SDValue();
947
948 switch (VT.getSimpleVT().SimpleTy) {
949 default:
950 llvm_unreachable("Unexpected floating point type!");
951 break;
952 case MVT::f32: {
953 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i32);
954 if (Subtarget.is64Bit())
955 NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, NewVal);
956 return DAG.getNode(Subtarget.is64Bit() ? LoongArchISD::MOVGR2FR_W_LA64
957 : LoongArchISD::MOVGR2FR_W,
958 DL, VT, NewVal);
959 }
960 case MVT::f64: {
961 if (Subtarget.is64Bit()) {
962 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i64);
963 return DAG.getNode(LoongArchISD::MOVGR2FR_D, DL, VT, NewVal);
964 }
965 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
966 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
967 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
968 }
969 }
970
971 return SDValue();
972}
973
974// Ensure SETCC result and operand have the same bit width; isel does not
975// support mismatched widths.
976SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
977 SelectionDAG &DAG) const {
978 SDLoc DL(Op);
979 EVT ResultVT = Op.getValueType();
980 EVT OperandVT = Op.getOperand(0).getValueType();
981
982 EVT SetCCResultVT =
983 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
984
985 if (ResultVT == SetCCResultVT)
986 return Op;
987
988 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
989 "SETCC operands must have the same type!");
990
991 SDValue SetCCNode =
992 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
993 Op.getOperand(1), Op.getOperand(2));
994
995 if (ResultVT.bitsGT(SetCCResultVT))
996 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
997 else if (ResultVT.bitsLT(SetCCResultVT))
998 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
999
1000 return SetCCNode;
1001}
1002
1003// Lower sext_invec using vslti instructions.
1004// For example:
1005// %b = sext <4 x i16> %a to <4 x i32>
1006// can be lowered to:
1007// VSLTI_H vr2, vr1, 0
1008// VILVL.H vr1, vr2, vr1
1009SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1010 SDValue Op, SelectionDAG &DAG) const {
1011 SDLoc DL(Op);
1012 SDValue Src = Op.getOperand(0);
1013 MVT SrcVT = Src.getSimpleValueType();
1014 MVT DstVT = Op.getSimpleValueType();
1015
1016 if (!SrcVT.is128BitVector())
1017 return SDValue();
1018
1019 // lower to VSLTI + VILVL if extend could be done in single step.
1020 if (DstVT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits() == 2) {
1021 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
1022 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Src, Zero,
1023 DAG.getCondCode(ISD::SETLT));
1024 SDValue LoInterleaved =
1025 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Src);
1026
1027 return DAG.getBitcast(DstVT, LoInterleaved);
1028 }
1029
1030 return SDValue();
1031}
1032
1033// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1034SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1035 SelectionDAG &DAG) const {
1036 assert(Subtarget.hasExtLASX());
1037 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1038 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1039 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1040 Op.getOperand(0));
1041}
1042
1043// Lower vecreduce_add using vhaddw instructions.
1044// For Example:
1045// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1046// can be lowered to:
1047// VHADDW_D_W vr0, vr0, vr0
1048// VHADDW_Q_D vr0, vr0, vr0
1049// VPICKVE2GR_D a0, vr0, 0
1050// ADDI_W a0, a0, 0
1051SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1052 SelectionDAG &DAG) const {
1053
1054 SDLoc DL(Op);
1055 MVT OpVT = Op.getSimpleValueType();
1056 SDValue Val = Op.getOperand(0);
1057
1058 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1059 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1060 unsigned ResBits = OpVT.getScalarSizeInBits();
1061
1062 unsigned LegalVecSize = 128;
1063 bool isLASX256Vector =
1064 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1065
1066 // Ensure operand type legal or enable it legal.
1067 while (!isTypeLegal(Val.getSimpleValueType())) {
1068 Val = DAG.WidenVector(Val, DL);
1069 }
1070
1071 // NumEles is designed for iterations count, v4i32 for LSX
1072 // and v8i32 for LASX should have the same count.
1073 if (isLASX256Vector) {
1074 NumEles /= 2;
1075 LegalVecSize = 256;
1076 }
1077
1078 EleBits *= 2;
1079 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1080 EleBits = std::min(EleBits, 64u);
1081 MVT IntTy = MVT::getIntegerVT(EleBits);
1082 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1083 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1084 }
1085
1086 if (isLASX256Vector) {
1087 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1088 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1089 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1090 }
1091
1092 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1093 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1094 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1095}
1096
1097// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1098// For Example:
1099// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1100// can be lowered to:
1101// VBSRL_V vr1, vr0, 8
1102// VMAX_W vr0, vr1, vr0
1103// VBSRL_V vr1, vr0, 4
1104// VMAX_W vr0, vr1, vr0
1105// VPICKVE2GR_W a0, vr0, 0
1106// For 256 bit vector, it is illegal and will be spilt into
1107// two 128 bit vector by default then processed by this.
1108SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1109 SelectionDAG &DAG) const {
1110 SDLoc DL(Op);
1111
1112 MVT OpVT = Op.getSimpleValueType();
1113 SDValue Val = Op.getOperand(0);
1114
1115 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1116 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1117
1118 // Ensure operand type legal or enable it legal.
1119 while (!isTypeLegal(Val.getSimpleValueType())) {
1120 Val = DAG.WidenVector(Val, DL);
1121 }
1122
1123 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1124 MVT VecTy = Val.getSimpleValueType();
1125 MVT GRLenVT = Subtarget.getGRLenVT();
1126
1127 for (int i = NumEles; i > 1; i /= 2) {
1128 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1129 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1130 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1131 }
1132
1133 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1134 DAG.getConstant(0, DL, GRLenVT));
1135}
1136
1137SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1138 SelectionDAG &DAG) const {
1139 unsigned IsData = Op.getConstantOperandVal(4);
1140
1141 // We don't support non-data prefetch.
1142 // Just preserve the chain.
1143 if (!IsData)
1144 return Op.getOperand(0);
1145
1146 return Op;
1147}
1148
1149SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1150 SelectionDAG &DAG) const {
1151 MVT VT = Op.getSimpleValueType();
1152 assert(VT.isVector() && "Unexpected type");
1153
1154 SDLoc DL(Op);
1155 SDValue R = Op.getOperand(0);
1156 SDValue Amt = Op.getOperand(1);
1157 unsigned Opcode = Op.getOpcode();
1158 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1159
1160 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1161 if (V.getOpcode() != ISD::BUILD_VECTOR)
1162 return false;
1163 if (SDValue SplatValue =
1164 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1165 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1166 CstSplatValue = C->getAPIntValue();
1167 return true;
1168 }
1169 }
1170 return false;
1171 };
1172
1173 // Check for constant splat rotation amount.
1174 APInt CstSplatValue;
1175 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1176 bool isROTL = Opcode == ISD::ROTL;
1177
1178 // Check for splat rotate by zero.
1179 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1180 return R;
1181
1182 // LoongArch targets always prefer ISD::ROTR.
1183 if (isROTL) {
1184 SDValue Zero = DAG.getConstant(0, DL, VT);
1185 return DAG.getNode(ISD::ROTR, DL, VT, R,
1186 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1187 }
1188
1189 // Rotate by a immediate.
1190 if (IsCstSplat) {
1191 // ISD::ROTR: Attemp to rotate by a positive immediate.
1192 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1193 if (SDValue Urem =
1194 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1195 return DAG.getNode(Opcode, DL, VT, R, Urem);
1196 }
1197
1198 return Op;
1199}
1200
1201// Return true if Val is equal to (setcc LHS, RHS, CC).
1202// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1203// Otherwise, return std::nullopt.
1204static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1205 ISD::CondCode CC, SDValue Val) {
1206 assert(Val->getOpcode() == ISD::SETCC);
1207 SDValue LHS2 = Val.getOperand(0);
1208 SDValue RHS2 = Val.getOperand(1);
1209 ISD::CondCode CC2 = cast<CondCodeSDNode>(Val.getOperand(2))->get();
1210
1211 if (LHS == LHS2 && RHS == RHS2) {
1212 if (CC == CC2)
1213 return true;
1214 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1215 return false;
1216 } else if (LHS == RHS2 && RHS == LHS2) {
1218 if (CC == CC2)
1219 return true;
1220 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1221 return false;
1222 }
1223
1224 return std::nullopt;
1225}
1226
1228 const LoongArchSubtarget &Subtarget) {
1229 SDValue CondV = N->getOperand(0);
1230 SDValue TrueV = N->getOperand(1);
1231 SDValue FalseV = N->getOperand(2);
1232 MVT VT = N->getSimpleValueType(0);
1233 SDLoc DL(N);
1234
1235 // (select c, -1, y) -> -c | y
1236 if (isAllOnesConstant(TrueV)) {
1237 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1238 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1239 }
1240 // (select c, y, -1) -> (c-1) | y
1241 if (isAllOnesConstant(FalseV)) {
1242 SDValue Neg =
1243 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1244 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1245 }
1246
1247 // (select c, 0, y) -> (c-1) & y
1248 if (isNullConstant(TrueV)) {
1249 SDValue Neg =
1250 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1251 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1252 }
1253 // (select c, y, 0) -> -c & y
1254 if (isNullConstant(FalseV)) {
1255 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1256 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1257 }
1258
1259 // select c, ~x, x --> xor -c, x
1260 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1261 const APInt &TrueVal = TrueV->getAsAPIntVal();
1262 const APInt &FalseVal = FalseV->getAsAPIntVal();
1263 if (~TrueVal == FalseVal) {
1264 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1265 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1266 }
1267 }
1268
1269 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1270 // when both truev and falsev are also setcc.
1271 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1272 FalseV.getOpcode() == ISD::SETCC) {
1273 SDValue LHS = CondV.getOperand(0);
1274 SDValue RHS = CondV.getOperand(1);
1275 ISD::CondCode CC = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1276
1277 // (select x, x, y) -> x | y
1278 // (select !x, x, y) -> x & y
1279 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1280 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1281 DAG.getFreeze(FalseV));
1282 }
1283 // (select x, y, x) -> x & y
1284 // (select !x, y, x) -> x | y
1285 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1286 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1287 DAG.getFreeze(TrueV), FalseV);
1288 }
1289 }
1290
1291 return SDValue();
1292}
1293
1294// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1295// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1296// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1297// being `0` or `-1`. In such cases we can replace `select` with `and`.
1298// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1299// than `c0`?
1300static SDValue
1302 const LoongArchSubtarget &Subtarget) {
1303 unsigned SelOpNo = 0;
1304 SDValue Sel = BO->getOperand(0);
1305 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1306 SelOpNo = 1;
1307 Sel = BO->getOperand(1);
1308 }
1309
1310 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1311 return SDValue();
1312
1313 unsigned ConstSelOpNo = 1;
1314 unsigned OtherSelOpNo = 2;
1315 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1316 ConstSelOpNo = 2;
1317 OtherSelOpNo = 1;
1318 }
1319 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1320 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1321 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1322 return SDValue();
1323
1324 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1325 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1326 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1327 return SDValue();
1328
1329 SDLoc DL(Sel);
1330 EVT VT = BO->getValueType(0);
1331
1332 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1333 if (SelOpNo == 1)
1334 std::swap(NewConstOps[0], NewConstOps[1]);
1335
1336 SDValue NewConstOp =
1337 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1338 if (!NewConstOp)
1339 return SDValue();
1340
1341 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1342 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1343 return SDValue();
1344
1345 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1346 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1347 if (SelOpNo == 1)
1348 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1349 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1350
1351 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1352 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1353 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1354}
1355
1356// Changes the condition code and swaps operands if necessary, so the SetCC
1357// operation matches one of the comparisons supported directly by branches
1358// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1359// compare with 1/-1.
1361 ISD::CondCode &CC, SelectionDAG &DAG) {
1362 // If this is a single bit test that can't be handled by ANDI, shift the
1363 // bit to be tested to the MSB and perform a signed compare with 0.
1364 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1365 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1366 isa<ConstantSDNode>(LHS.getOperand(1))) {
1367 uint64_t Mask = LHS.getConstantOperandVal(1);
1368 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1369 unsigned ShAmt = 0;
1370 if (isPowerOf2_64(Mask)) {
1371 CC = CC == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
1372 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1373 } else {
1374 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1375 }
1376
1377 LHS = LHS.getOperand(0);
1378 if (ShAmt != 0)
1379 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1380 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1381 return;
1382 }
1383 }
1384
1385 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1386 int64_t C = RHSC->getSExtValue();
1387 switch (CC) {
1388 default:
1389 break;
1390 case ISD::SETGT:
1391 // Convert X > -1 to X >= 0.
1392 if (C == -1) {
1393 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1394 CC = ISD::SETGE;
1395 return;
1396 }
1397 break;
1398 case ISD::SETLT:
1399 // Convert X < 1 to 0 >= X.
1400 if (C == 1) {
1401 RHS = LHS;
1402 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1403 CC = ISD::SETGE;
1404 return;
1405 }
1406 break;
1407 }
1408 }
1409
1410 switch (CC) {
1411 default:
1412 break;
1413 case ISD::SETGT:
1414 case ISD::SETLE:
1415 case ISD::SETUGT:
1416 case ISD::SETULE:
1418 std::swap(LHS, RHS);
1419 break;
1420 }
1421}
1422
1423SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1424 SelectionDAG &DAG) const {
1425 SDValue CondV = Op.getOperand(0);
1426 SDValue TrueV = Op.getOperand(1);
1427 SDValue FalseV = Op.getOperand(2);
1428 SDLoc DL(Op);
1429 MVT VT = Op.getSimpleValueType();
1430 MVT GRLenVT = Subtarget.getGRLenVT();
1431
1432 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1433 return V;
1434
1435 if (Op.hasOneUse()) {
1436 unsigned UseOpc = Op->user_begin()->getOpcode();
1437 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1438 SDNode *BinOp = *Op->user_begin();
1439 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1440 DAG, Subtarget)) {
1441 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1442 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1443 // may return a constant node and cause crash in lowerSELECT.
1444 if (NewSel.getOpcode() == ISD::SELECT)
1445 return lowerSELECT(NewSel, DAG);
1446 return NewSel;
1447 }
1448 }
1449 }
1450
1451 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1452 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1453 // (select condv, truev, falsev)
1454 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1455 if (CondV.getOpcode() != ISD::SETCC ||
1456 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1457 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1458 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1459
1460 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1461
1462 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1463 }
1464
1465 // If the CondV is the output of a SETCC node which operates on GRLenVT
1466 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1467 // to take advantage of the integer compare+branch instructions. i.e.: (select
1468 // (setcc lhs, rhs, cc), truev, falsev)
1469 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1470 SDValue LHS = CondV.getOperand(0);
1471 SDValue RHS = CondV.getOperand(1);
1472 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1473
1474 // Special case for a select of 2 constants that have a difference of 1.
1475 // Normally this is done by DAGCombine, but if the select is introduced by
1476 // type legalization or op legalization, we miss it. Restricting to SETLT
1477 // case for now because that is what signed saturating add/sub need.
1478 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1479 // but we would probably want to swap the true/false values if the condition
1480 // is SETGE/SETLE to avoid an XORI.
1481 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1482 CCVal == ISD::SETLT) {
1483 const APInt &TrueVal = TrueV->getAsAPIntVal();
1484 const APInt &FalseVal = FalseV->getAsAPIntVal();
1485 if (TrueVal - 1 == FalseVal)
1486 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1487 if (TrueVal + 1 == FalseVal)
1488 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1489 }
1490
1491 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1492 // 1 < x ? x : 1 -> 0 < x ? x : 1
1493 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1494 RHS == TrueV && LHS == FalseV) {
1495 LHS = DAG.getConstant(0, DL, VT);
1496 // 0 <u x is the same as x != 0.
1497 if (CCVal == ISD::SETULT) {
1498 std::swap(LHS, RHS);
1499 CCVal = ISD::SETNE;
1500 }
1501 }
1502
1503 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1504 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1505 RHS == FalseV) {
1506 RHS = DAG.getConstant(0, DL, VT);
1507 }
1508
1509 SDValue TargetCC = DAG.getCondCode(CCVal);
1510
1511 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1512 // (select (setcc lhs, rhs, CC), constant, falsev)
1513 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1514 std::swap(TrueV, FalseV);
1515 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1516 }
1517
1518 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1519 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1520}
1521
1522SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1523 SelectionDAG &DAG) const {
1524 SDValue CondV = Op.getOperand(1);
1525 SDLoc DL(Op);
1526 MVT GRLenVT = Subtarget.getGRLenVT();
1527
1528 if (CondV.getOpcode() == ISD::SETCC) {
1529 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1530 SDValue LHS = CondV.getOperand(0);
1531 SDValue RHS = CondV.getOperand(1);
1532 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1533
1534 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1535
1536 SDValue TargetCC = DAG.getCondCode(CCVal);
1537 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1538 Op.getOperand(0), LHS, RHS, TargetCC,
1539 Op.getOperand(2));
1540 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1541 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1542 Op.getOperand(0), CondV, Op.getOperand(2));
1543 }
1544 }
1545
1546 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1547 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1548 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1549}
1550
1551SDValue
1552LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1553 SelectionDAG &DAG) const {
1554 SDLoc DL(Op);
1555 MVT OpVT = Op.getSimpleValueType();
1556
1557 SDValue Vector = DAG.getUNDEF(OpVT);
1558 SDValue Val = Op.getOperand(0);
1559 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1560
1561 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1562}
1563
1564SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1565 SelectionDAG &DAG) const {
1566 EVT ResTy = Op->getValueType(0);
1567 SDValue Src = Op->getOperand(0);
1568 SDLoc DL(Op);
1569
1570 // LoongArchISD::BITREV_8B is not supported on LA32.
1571 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1572 return SDValue();
1573
1574 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1575 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1576 unsigned int NewEltNum = NewVT.getVectorNumElements();
1577
1578 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1579
1581 for (unsigned int i = 0; i < NewEltNum; i++) {
1582 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1583 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1584 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1585 ? (unsigned)LoongArchISD::BITREV_8B
1586 : (unsigned)ISD::BITREVERSE;
1587 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1588 }
1589 SDValue Res =
1590 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1591
1592 switch (ResTy.getSimpleVT().SimpleTy) {
1593 default:
1594 return SDValue();
1595 case MVT::v16i8:
1596 case MVT::v32i8:
1597 return Res;
1598 case MVT::v8i16:
1599 case MVT::v16i16:
1600 case MVT::v4i32:
1601 case MVT::v8i32: {
1603 for (unsigned int i = 0; i < NewEltNum; i++)
1604 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1605 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1606 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1607 }
1608 }
1609}
1610
1611// Widen element type to get a new mask value (if possible).
1612// For example:
1613// shufflevector <4 x i32> %a, <4 x i32> %b,
1614// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1615// is equivalent to:
1616// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1617// can be lowered to:
1618// VPACKOD_D vr0, vr0, vr1
1620 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1621 unsigned EltBits = VT.getScalarSizeInBits();
1622
1623 if (EltBits > 32 || EltBits == 1)
1624 return SDValue();
1625
1626 SmallVector<int, 8> NewMask;
1627 if (widenShuffleMaskElts(Mask, NewMask)) {
1628 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1629 : MVT::getIntegerVT(EltBits * 2);
1630 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1631 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1632 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1633 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1634 return DAG.getBitcast(
1635 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1636 }
1637 }
1638
1639 return SDValue();
1640}
1641
1642/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1643/// instruction.
1644// The funciton matches elements from one of the input vector shuffled to the
1645// left or right with zeroable elements 'shifted in'. It handles both the
1646// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1647// lane.
1648// Mostly copied from X86.
1649static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1650 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1651 int MaskOffset, const APInt &Zeroable) {
1652 int Size = Mask.size();
1653 unsigned SizeInBits = Size * ScalarSizeInBits;
1654
1655 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1656 for (int i = 0; i < Size; i += Scale)
1657 for (int j = 0; j < Shift; ++j)
1658 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1659 return false;
1660
1661 return true;
1662 };
1663
1664 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1665 int Step = 1) {
1666 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1667 if (!(Mask[i] == -1 || Mask[i] == Low))
1668 return false;
1669 return true;
1670 };
1671
1672 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1673 for (int i = 0; i != Size; i += Scale) {
1674 unsigned Pos = Left ? i + Shift : i;
1675 unsigned Low = Left ? i : i + Shift;
1676 unsigned Len = Scale - Shift;
1677 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1678 return -1;
1679 }
1680
1681 int ShiftEltBits = ScalarSizeInBits * Scale;
1682 bool ByteShift = ShiftEltBits > 64;
1683 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1684 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1685 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1686
1687 // Normalize the scale for byte shifts to still produce an i64 element
1688 // type.
1689 Scale = ByteShift ? Scale / 2 : Scale;
1690
1691 // We need to round trip through the appropriate type for the shift.
1692 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1693 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1694 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1695 return (int)ShiftAmt;
1696 };
1697
1698 unsigned MaxWidth = 128;
1699 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1700 for (int Shift = 1; Shift != Scale; ++Shift)
1701 for (bool Left : {true, false})
1702 if (CheckZeros(Shift, Scale, Left)) {
1703 int ShiftAmt = MatchShift(Shift, Scale, Left);
1704 if (0 < ShiftAmt)
1705 return ShiftAmt;
1706 }
1707
1708 // no match
1709 return -1;
1710}
1711
1712/// Lower VECTOR_SHUFFLE as shift (if possible).
1713///
1714/// For example:
1715/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1716/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1717/// is lowered to:
1718/// (VBSLL_V $v0, $v0, 4)
1719///
1720/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1721/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1722/// is lowered to:
1723/// (VSLLI_D $v0, $v0, 32)
1725 MVT VT, SDValue V1, SDValue V2,
1726 SelectionDAG &DAG,
1727 const LoongArchSubtarget &Subtarget,
1728 const APInt &Zeroable) {
1729 int Size = Mask.size();
1730 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1731
1732 MVT ShiftVT;
1733 SDValue V = V1;
1734 unsigned Opcode;
1735
1736 // Try to match shuffle against V1 shift.
1737 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1738 Mask, 0, Zeroable);
1739
1740 // If V1 failed, try to match shuffle against V2 shift.
1741 if (ShiftAmt < 0) {
1742 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1743 Mask, Size, Zeroable);
1744 V = V2;
1745 }
1746
1747 if (ShiftAmt < 0)
1748 return SDValue();
1749
1750 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1751 "Illegal integer vector type");
1752 V = DAG.getBitcast(ShiftVT, V);
1753 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1754 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1755 return DAG.getBitcast(VT, V);
1756}
1757
1758/// Determine whether a range fits a regular pattern of values.
1759/// This function accounts for the possibility of jumping over the End iterator.
1760template <typename ValType>
1761static bool
1763 unsigned CheckStride,
1765 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1766 auto &I = Begin;
1767
1768 while (I != End) {
1769 if (*I != -1 && *I != ExpectedIndex)
1770 return false;
1771 ExpectedIndex += ExpectedIndexStride;
1772
1773 // Incrementing past End is undefined behaviour so we must increment one
1774 // step at a time and check for End at each step.
1775 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1776 ; // Empty loop body.
1777 }
1778 return true;
1779}
1780
1781/// Compute whether each element of a shuffle is zeroable.
1782///
1783/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1785 SDValue V2, APInt &KnownUndef,
1786 APInt &KnownZero) {
1787 int Size = Mask.size();
1788 KnownUndef = KnownZero = APInt::getZero(Size);
1789
1791 V2 = peekThroughBitcasts(V2);
1792
1793 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1794 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1795
1796 int VectorSizeInBits = V1.getValueSizeInBits();
1797 int ScalarSizeInBits = VectorSizeInBits / Size;
1798 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1799 (void)ScalarSizeInBits;
1800
1801 for (int i = 0; i < Size; ++i) {
1802 int M = Mask[i];
1803 if (M < 0) {
1804 KnownUndef.setBit(i);
1805 continue;
1806 }
1807 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1808 KnownZero.setBit(i);
1809 continue;
1810 }
1811 }
1812}
1813
1814/// Test whether a shuffle mask is equivalent within each sub-lane.
1815///
1816/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1817/// non-trivial to compute in the face of undef lanes. The representation is
1818/// suitable for use with existing 128-bit shuffles as entries from the second
1819/// vector have been remapped to [LaneSize, 2*LaneSize).
1820static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1821 ArrayRef<int> Mask,
1822 SmallVectorImpl<int> &RepeatedMask) {
1823 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1824 RepeatedMask.assign(LaneSize, -1);
1825 int Size = Mask.size();
1826 for (int i = 0; i < Size; ++i) {
1827 assert(Mask[i] == -1 || Mask[i] >= 0);
1828 if (Mask[i] < 0)
1829 continue;
1830 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1831 // This entry crosses lanes, so there is no way to model this shuffle.
1832 return false;
1833
1834 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1835 // Adjust second vector indices to start at LaneSize instead of Size.
1836 int LocalM =
1837 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1838 if (RepeatedMask[i % LaneSize] < 0)
1839 // This is the first non-undef entry in this slot of a 128-bit lane.
1840 RepeatedMask[i % LaneSize] = LocalM;
1841 else if (RepeatedMask[i % LaneSize] != LocalM)
1842 // Found a mismatch with the repeated mask.
1843 return false;
1844 }
1845 return true;
1846}
1847
1848/// Attempts to match vector shuffle as byte rotation.
1850 ArrayRef<int> Mask) {
1851
1852 SDValue Lo, Hi;
1853 SmallVector<int, 16> RepeatedMask;
1854
1855 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1856 return -1;
1857
1858 int NumElts = RepeatedMask.size();
1859 int Rotation = 0;
1860 int Scale = 16 / NumElts;
1861
1862 for (int i = 0; i < NumElts; ++i) {
1863 int M = RepeatedMask[i];
1864 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1865 "Unexpected mask index.");
1866 if (M < 0)
1867 continue;
1868
1869 // Determine where a rotated vector would have started.
1870 int StartIdx = i - (M % NumElts);
1871 if (StartIdx == 0)
1872 return -1;
1873
1874 // If we found the tail of a vector the rotation must be the missing
1875 // front. If we found the head of a vector, it must be how much of the
1876 // head.
1877 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1878
1879 if (Rotation == 0)
1880 Rotation = CandidateRotation;
1881 else if (Rotation != CandidateRotation)
1882 return -1;
1883
1884 // Compute which value this mask is pointing at.
1885 SDValue MaskV = M < NumElts ? V1 : V2;
1886
1887 // Compute which of the two target values this index should be assigned
1888 // to. This reflects whether the high elements are remaining or the low
1889 // elements are remaining.
1890 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1891
1892 // Either set up this value if we've not encountered it before, or check
1893 // that it remains consistent.
1894 if (!TargetV)
1895 TargetV = MaskV;
1896 else if (TargetV != MaskV)
1897 return -1;
1898 }
1899
1900 // Check that we successfully analyzed the mask, and normalize the results.
1901 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1902 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1903 if (!Lo)
1904 Lo = Hi;
1905 else if (!Hi)
1906 Hi = Lo;
1907
1908 V1 = Lo;
1909 V2 = Hi;
1910
1911 return Rotation * Scale;
1912}
1913
1914/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
1915///
1916/// For example:
1917/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
1918/// <2 x i32> <i32 3, i32 0>
1919/// is lowered to:
1920/// (VBSRL_V $v1, $v1, 8)
1921/// (VBSLL_V $v0, $v0, 8)
1922/// (VOR_V $v0, $V0, $v1)
1923static SDValue
1925 SDValue V1, SDValue V2, SelectionDAG &DAG,
1926 const LoongArchSubtarget &Subtarget) {
1927
1928 SDValue Lo = V1, Hi = V2;
1929 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
1930 if (ByteRotation <= 0)
1931 return SDValue();
1932
1933 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
1934 Lo = DAG.getBitcast(ByteVT, Lo);
1935 Hi = DAG.getBitcast(ByteVT, Hi);
1936
1937 int LoByteShift = 16 - ByteRotation;
1938 int HiByteShift = ByteRotation;
1939 MVT GRLenVT = Subtarget.getGRLenVT();
1940
1941 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
1942 DAG.getConstant(LoByteShift, DL, GRLenVT));
1943 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
1944 DAG.getConstant(HiByteShift, DL, GRLenVT));
1945 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
1946}
1947
1948/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
1949///
1950/// For example:
1951/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1952/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
1953/// %3 = bitcast <4 x i32> %2 to <2 x i64>
1954/// is lowered to:
1955/// (VREPLI $v1, 0)
1956/// (VILVL $v0, $v1, $v0)
1958 ArrayRef<int> Mask, MVT VT,
1959 SDValue V1, SDValue V2,
1960 SelectionDAG &DAG,
1961 const APInt &Zeroable) {
1962 int Bits = VT.getSizeInBits();
1963 int EltBits = VT.getScalarSizeInBits();
1964 int NumElements = VT.getVectorNumElements();
1965
1966 if (Zeroable.isAllOnes())
1967 return DAG.getConstant(0, DL, VT);
1968
1969 // Define a helper function to check a particular ext-scale and lower to it if
1970 // valid.
1971 auto Lower = [&](int Scale) -> SDValue {
1972 SDValue InputV;
1973 bool AnyExt = true;
1974 int Offset = 0;
1975 for (int i = 0; i < NumElements; i++) {
1976 int M = Mask[i];
1977 if (M < 0)
1978 continue;
1979 if (i % Scale != 0) {
1980 // Each of the extended elements need to be zeroable.
1981 if (!Zeroable[i])
1982 return SDValue();
1983
1984 AnyExt = false;
1985 continue;
1986 }
1987
1988 // Each of the base elements needs to be consecutive indices into the
1989 // same input vector.
1990 SDValue V = M < NumElements ? V1 : V2;
1991 M = M % NumElements;
1992 if (!InputV) {
1993 InputV = V;
1994 Offset = M - (i / Scale);
1995
1996 // These offset can't be handled
1997 if (Offset % (NumElements / Scale))
1998 return SDValue();
1999 } else if (InputV != V)
2000 return SDValue();
2001
2002 if (M != (Offset + (i / Scale)))
2003 return SDValue(); // Non-consecutive strided elements.
2004 }
2005
2006 // If we fail to find an input, we have a zero-shuffle which should always
2007 // have already been handled.
2008 if (!InputV)
2009 return SDValue();
2010
2011 do {
2012 unsigned VilVLoHi = LoongArchISD::VILVL;
2013 if (Offset >= (NumElements / 2)) {
2014 VilVLoHi = LoongArchISD::VILVH;
2015 Offset -= (NumElements / 2);
2016 }
2017
2018 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2019 SDValue Ext =
2020 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2021 InputV = DAG.getBitcast(InputVT, InputV);
2022 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2023 Scale /= 2;
2024 EltBits *= 2;
2025 NumElements /= 2;
2026 } while (Scale > 1);
2027 return DAG.getBitcast(VT, InputV);
2028 };
2029
2030 // Each iteration, try extending the elements half as much, but into twice as
2031 // many elements.
2032 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2033 NumExtElements *= 2) {
2034 if (SDValue V = Lower(NumElements / NumExtElements))
2035 return V;
2036 }
2037 return SDValue();
2038}
2039
2040/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2041///
2042/// VREPLVEI performs vector broadcast based on an element specified by an
2043/// integer immediate, with its mask being similar to:
2044/// <x, x, x, ...>
2045/// where x is any valid index.
2046///
2047/// When undef's appear in the mask they are treated as if they were whatever
2048/// value is necessary in order to fit the above form.
2049static SDValue
2051 SDValue V1, SelectionDAG &DAG,
2052 const LoongArchSubtarget &Subtarget) {
2053 int SplatIndex = -1;
2054 for (const auto &M : Mask) {
2055 if (M != -1) {
2056 SplatIndex = M;
2057 break;
2058 }
2059 }
2060
2061 if (SplatIndex == -1)
2062 return DAG.getUNDEF(VT);
2063
2064 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2065 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2066 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2067 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2068 }
2069
2070 return SDValue();
2071}
2072
2073/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2074///
2075/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2076/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2077///
2078/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2079/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2080/// When undef's appear they are treated as if they were whatever value is
2081/// necessary in order to fit the above forms.
2082///
2083/// For example:
2084/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2085/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2086/// i32 7, i32 6, i32 5, i32 4>
2087/// is lowered to:
2088/// (VSHUF4I_H $v0, $v1, 27)
2089/// where the 27 comes from:
2090/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2091static SDValue
2093 SDValue V1, SDValue V2, SelectionDAG &DAG,
2094 const LoongArchSubtarget &Subtarget) {
2095
2096 unsigned SubVecSize = 4;
2097 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2098 SubVecSize = 2;
2099
2100 int SubMask[4] = {-1, -1, -1, -1};
2101 for (unsigned i = 0; i < SubVecSize; ++i) {
2102 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2103 int M = Mask[j];
2104
2105 // Convert from vector index to 4-element subvector index
2106 // If an index refers to an element outside of the subvector then give up
2107 if (M != -1) {
2108 M -= 4 * (j / SubVecSize);
2109 if (M < 0 || M >= 4)
2110 return SDValue();
2111 }
2112
2113 // If the mask has an undef, replace it with the current index.
2114 // Note that it might still be undef if the current index is also undef
2115 if (SubMask[i] == -1)
2116 SubMask[i] = M;
2117 // Check that non-undef values are the same as in the mask. If they
2118 // aren't then give up
2119 else if (M != -1 && M != SubMask[i])
2120 return SDValue();
2121 }
2122 }
2123
2124 // Calculate the immediate. Replace any remaining undefs with zero
2125 int Imm = 0;
2126 for (int i = SubVecSize - 1; i >= 0; --i) {
2127 int M = SubMask[i];
2128
2129 if (M == -1)
2130 M = 0;
2131
2132 Imm <<= 2;
2133 Imm |= M & 0x3;
2134 }
2135
2136 MVT GRLenVT = Subtarget.getGRLenVT();
2137
2138 // Return vshuf4i.d
2139 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2140 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2141 DAG.getConstant(Imm, DL, GRLenVT));
2142
2143 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2144 DAG.getConstant(Imm, DL, GRLenVT));
2145}
2146
2147/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2148///
2149/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2150/// reverse whose mask likes:
2151/// <7, 6, 5, 4, 3, 2, 1, 0>
2152///
2153/// When undef's appear in the mask they are treated as if they were whatever
2154/// value is necessary in order to fit the above forms.
2155static SDValue
2157 SDValue V1, SelectionDAG &DAG,
2158 const LoongArchSubtarget &Subtarget) {
2159 // Only vectors with i8/i16 elements which cannot match other patterns
2160 // directly needs to do this.
2161 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2162 VT != MVT::v16i16)
2163 return SDValue();
2164
2165 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2166 return SDValue();
2167
2168 int WidenNumElts = VT.getVectorNumElements() / 4;
2169 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2170 for (int i = 0; i < WidenNumElts; ++i)
2171 WidenMask[i] = WidenNumElts - 1 - i;
2172
2173 MVT WidenVT = MVT::getVectorVT(
2174 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2175 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2176 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2177 DAG.getUNDEF(WidenVT), WidenMask);
2178
2179 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2180 DAG.getBitcast(VT, WidenRev),
2181 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2182}
2183
2184/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2185///
2186/// VPACKEV interleaves the even elements from each vector.
2187///
2188/// It is possible to lower into VPACKEV when the mask consists of two of the
2189/// following forms interleaved:
2190/// <0, 2, 4, ...>
2191/// <n, n+2, n+4, ...>
2192/// where n is the number of elements in the vector.
2193/// For example:
2194/// <0, 0, 2, 2, 4, 4, ...>
2195/// <0, n, 2, n+2, 4, n+4, ...>
2196///
2197/// When undef's appear in the mask they are treated as if they were whatever
2198/// value is necessary in order to fit the above forms.
2200 MVT VT, SDValue V1, SDValue V2,
2201 SelectionDAG &DAG) {
2202
2203 const auto &Begin = Mask.begin();
2204 const auto &End = Mask.end();
2205 SDValue OriV1 = V1, OriV2 = V2;
2206
2207 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2208 V1 = OriV1;
2209 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2210 V1 = OriV2;
2211 else
2212 return SDValue();
2213
2214 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2215 V2 = OriV1;
2216 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2217 V2 = OriV2;
2218 else
2219 return SDValue();
2220
2221 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2222}
2223
2224/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2225///
2226/// VPACKOD interleaves the odd elements from each vector.
2227///
2228/// It is possible to lower into VPACKOD when the mask consists of two of the
2229/// following forms interleaved:
2230/// <1, 3, 5, ...>
2231/// <n+1, n+3, n+5, ...>
2232/// where n is the number of elements in the vector.
2233/// For example:
2234/// <1, 1, 3, 3, 5, 5, ...>
2235/// <1, n+1, 3, n+3, 5, n+5, ...>
2236///
2237/// When undef's appear in the mask they are treated as if they were whatever
2238/// value is necessary in order to fit the above forms.
2240 MVT VT, SDValue V1, SDValue V2,
2241 SelectionDAG &DAG) {
2242
2243 const auto &Begin = Mask.begin();
2244 const auto &End = Mask.end();
2245 SDValue OriV1 = V1, OriV2 = V2;
2246
2247 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2248 V1 = OriV1;
2249 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2250 V1 = OriV2;
2251 else
2252 return SDValue();
2253
2254 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2255 V2 = OriV1;
2256 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2257 V2 = OriV2;
2258 else
2259 return SDValue();
2260
2261 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2262}
2263
2264/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2265///
2266/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2267/// of each vector.
2268///
2269/// It is possible to lower into VILVH when the mask consists of two of the
2270/// following forms interleaved:
2271/// <x, x+1, x+2, ...>
2272/// <n+x, n+x+1, n+x+2, ...>
2273/// where n is the number of elements in the vector and x is half n.
2274/// For example:
2275/// <x, x, x+1, x+1, x+2, x+2, ...>
2276/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2277///
2278/// When undef's appear in the mask they are treated as if they were whatever
2279/// value is necessary in order to fit the above forms.
2281 MVT VT, SDValue V1, SDValue V2,
2282 SelectionDAG &DAG) {
2283
2284 const auto &Begin = Mask.begin();
2285 const auto &End = Mask.end();
2286 unsigned HalfSize = Mask.size() / 2;
2287 SDValue OriV1 = V1, OriV2 = V2;
2288
2289 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2290 V1 = OriV1;
2291 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2292 V1 = OriV2;
2293 else
2294 return SDValue();
2295
2296 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2297 V2 = OriV1;
2298 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2299 1))
2300 V2 = OriV2;
2301 else
2302 return SDValue();
2303
2304 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2305}
2306
2307/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2308///
2309/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2310/// of each vector.
2311///
2312/// It is possible to lower into VILVL when the mask consists of two of the
2313/// following forms interleaved:
2314/// <0, 1, 2, ...>
2315/// <n, n+1, n+2, ...>
2316/// where n is the number of elements in the vector.
2317/// For example:
2318/// <0, 0, 1, 1, 2, 2, ...>
2319/// <0, n, 1, n+1, 2, n+2, ...>
2320///
2321/// When undef's appear in the mask they are treated as if they were whatever
2322/// value is necessary in order to fit the above forms.
2324 MVT VT, SDValue V1, SDValue V2,
2325 SelectionDAG &DAG) {
2326
2327 const auto &Begin = Mask.begin();
2328 const auto &End = Mask.end();
2329 SDValue OriV1 = V1, OriV2 = V2;
2330
2331 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2332 V1 = OriV1;
2333 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2334 V1 = OriV2;
2335 else
2336 return SDValue();
2337
2338 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2339 V2 = OriV1;
2340 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2341 V2 = OriV2;
2342 else
2343 return SDValue();
2344
2345 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2346}
2347
2348/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2349///
2350/// VPICKEV copies the even elements of each vector into the result vector.
2351///
2352/// It is possible to lower into VPICKEV when the mask consists of two of the
2353/// following forms concatenated:
2354/// <0, 2, 4, ...>
2355/// <n, n+2, n+4, ...>
2356/// where n is the number of elements in the vector.
2357/// For example:
2358/// <0, 2, 4, ..., 0, 2, 4, ...>
2359/// <0, 2, 4, ..., n, n+2, n+4, ...>
2360///
2361/// When undef's appear in the mask they are treated as if they were whatever
2362/// value is necessary in order to fit the above forms.
2364 MVT VT, SDValue V1, SDValue V2,
2365 SelectionDAG &DAG) {
2366
2367 const auto &Begin = Mask.begin();
2368 const auto &Mid = Mask.begin() + Mask.size() / 2;
2369 const auto &End = Mask.end();
2370 SDValue OriV1 = V1, OriV2 = V2;
2371
2372 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2373 V1 = OriV1;
2374 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2375 V1 = OriV2;
2376 else
2377 return SDValue();
2378
2379 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2380 V2 = OriV1;
2381 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2382 V2 = OriV2;
2383
2384 else
2385 return SDValue();
2386
2387 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2388}
2389
2390/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2391///
2392/// VPICKOD copies the odd elements of each vector into the result vector.
2393///
2394/// It is possible to lower into VPICKOD when the mask consists of two of the
2395/// following forms concatenated:
2396/// <1, 3, 5, ...>
2397/// <n+1, n+3, n+5, ...>
2398/// where n is the number of elements in the vector.
2399/// For example:
2400/// <1, 3, 5, ..., 1, 3, 5, ...>
2401/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2402///
2403/// When undef's appear in the mask they are treated as if they were whatever
2404/// value is necessary in order to fit the above forms.
2406 MVT VT, SDValue V1, SDValue V2,
2407 SelectionDAG &DAG) {
2408
2409 const auto &Begin = Mask.begin();
2410 const auto &Mid = Mask.begin() + Mask.size() / 2;
2411 const auto &End = Mask.end();
2412 SDValue OriV1 = V1, OriV2 = V2;
2413
2414 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2415 V1 = OriV1;
2416 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2417 V1 = OriV2;
2418 else
2419 return SDValue();
2420
2421 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2422 V2 = OriV1;
2423 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2424 V2 = OriV2;
2425 else
2426 return SDValue();
2427
2428 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2429}
2430
2431/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2432///
2433/// VEXTRINS copies one element of a vector into any place of the result
2434/// vector and makes no change to the rest elements of the result vector.
2435///
2436/// It is possible to lower into VEXTRINS when the mask takes the form:
2437/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2438/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2439/// where n is the number of elements in the vector and i is in [0, n).
2440/// For example:
2441/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2442/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2443///
2444/// When undef's appear in the mask they are treated as if they were whatever
2445/// value is necessary in order to fit the above forms.
2446static SDValue
2448 SDValue V1, SDValue V2, SelectionDAG &DAG,
2449 const LoongArchSubtarget &Subtarget) {
2450 unsigned NumElts = VT.getVectorNumElements();
2451 MVT EltVT = VT.getVectorElementType();
2452 MVT GRLenVT = Subtarget.getGRLenVT();
2453
2454 if (Mask.size() != NumElts)
2455 return SDValue();
2456
2457 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2458 int DiffCount = 0;
2459 int DiffPos = -1;
2460 for (unsigned i = 0; i < NumElts; ++i) {
2461 if (Mask[i] == -1)
2462 continue;
2463 if (Mask[i] != int(Base + i)) {
2464 ++DiffCount;
2465 DiffPos = int(i);
2466 if (DiffCount > 1)
2467 return SDValue();
2468 }
2469 }
2470
2471 // Need exactly one differing element to lower into VEXTRINS.
2472 if (DiffCount != 1)
2473 return SDValue();
2474
2475 // DiffMask must be in [0, 2N).
2476 int DiffMask = Mask[DiffPos];
2477 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2478 return SDValue();
2479
2480 // Determine source vector and source index.
2481 SDValue SrcVec;
2482 unsigned SrcIdx;
2483 if (unsigned(DiffMask) < NumElts) {
2484 SrcVec = V1;
2485 SrcIdx = unsigned(DiffMask);
2486 } else {
2487 SrcVec = V2;
2488 SrcIdx = unsigned(DiffMask) - NumElts;
2489 }
2490
2491 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2492 // patterns of VEXTRINS in tablegen.
2493 SDValue Extracted = DAG.getNode(
2494 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2495 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2496 SDValue Result =
2497 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2498 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2499
2500 return Result;
2501 };
2502
2503 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2504 if (SDValue Result = tryLowerToExtrAndIns(0))
2505 return Result;
2506 return tryLowerToExtrAndIns(NumElts);
2507}
2508
2509// Check the Mask and then build SrcVec and MaskImm infos which will
2510// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2511// On success, return true. Otherwise, return false.
2514 unsigned &MaskImm) {
2515 unsigned MaskSize = Mask.size();
2516
2517 auto isValid = [&](int M, int Off) {
2518 return (M == -1) || (M >= Off && M < Off + 4);
2519 };
2520
2521 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2522 auto immPart = [&](int M, unsigned Off) {
2523 return (M == -1 ? 0 : (M - Off)) & 0x3;
2524 };
2525 MaskImm |= immPart(MLo, Off) << (I * 2);
2526 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2527 };
2528
2529 for (unsigned i = 0; i < 4; i += 2) {
2530 int MLo = Mask[i];
2531 int MHi = Mask[i + 1];
2532
2533 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2534 auto isValid2 = [&](int &M, int M2) {
2535 // If high half index is undef, it's always valid.
2536 if (M2 == -1)
2537 return true;
2538 if (M == -1) {
2539 // If low half index is undef, use index from high half,
2540 // remapped to low half.
2541 if ((M2 % MaskSize) < 4)
2542 return false;
2543 M = M2 - 4;
2544 return true;
2545 }
2546 // Index in low half must be same as index in high half.
2547 return M2 == M + 4;
2548 };
2549 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2550 return false;
2551 }
2552
2553 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2554 SrcVec.push_back(V1);
2555 buildImm(MLo, MHi, 0, i);
2556 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2557 SrcVec.push_back(V2);
2558 buildImm(MLo, MHi, MaskSize, i);
2559 } else {
2560 return false;
2561 }
2562 }
2563
2564 return true;
2565}
2566
2567/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2568///
2569/// VPERMI selects two elements from each of the two vectors based on the
2570/// mask and places them in the corresponding positions of the result vector
2571/// in order. Only v4i32 and v4f32 types are allowed.
2572///
2573/// It is possible to lower into VPERMI when the mask consists of two of the
2574/// following forms concatenated:
2575/// <i, j, u, v>
2576/// <u, v, i, j>
2577/// where i,j are in [0,4) and u,v are in [4, 8).
2578/// For example:
2579/// <2, 3, 4, 5>
2580/// <5, 7, 0, 2>
2581///
2582/// When undef's appear in the mask they are treated as if they were whatever
2583/// value is necessary in order to fit the above forms.
2585 MVT VT, SDValue V1, SDValue V2,
2586 SelectionDAG &DAG,
2587 const LoongArchSubtarget &Subtarget) {
2588 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2589 Mask.size() != VT.getVectorNumElements())
2590 return SDValue();
2591
2593 unsigned MaskImm = 0;
2594 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2595 return SDValue();
2596
2597 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2598 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2599}
2600
2601/// Lower VECTOR_SHUFFLE into VSHUF.
2602///
2603/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2604/// adding it as an operand to the resulting VSHUF.
2606 MVT VT, SDValue V1, SDValue V2,
2607 SelectionDAG &DAG,
2608 const LoongArchSubtarget &Subtarget) {
2609
2611 for (auto M : Mask)
2612 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2613
2614 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2615 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2616
2617 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2618 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2619 // VSHF concatenates the vectors in a bitwise fashion:
2620 // <0b00, 0b01> + <0b10, 0b11> ->
2621 // 0b0100 + 0b1110 -> 0b01001110
2622 // <0b10, 0b11, 0b00, 0b01>
2623 // We must therefore swap the operands to get the correct result.
2624 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2625}
2626
2627/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2628///
2629/// This routine breaks down the specific type of 128-bit shuffle and
2630/// dispatches to the lowering routines accordingly.
2632 SDValue V1, SDValue V2, SelectionDAG &DAG,
2633 const LoongArchSubtarget &Subtarget) {
2634 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2635 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2636 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2637 "Vector type is unsupported for lsx!");
2638 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2639 "Two operands have different types!");
2640 assert(VT.getVectorNumElements() == Mask.size() &&
2641 "Unexpected mask size for shuffle!");
2642 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2643
2644 APInt KnownUndef, KnownZero;
2645 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2646 APInt Zeroable = KnownUndef | KnownZero;
2647
2648 SDValue Result;
2649 // TODO: Add more comparison patterns.
2650 if (V2.isUndef()) {
2651 if ((Result =
2652 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2653 return Result;
2654 if ((Result =
2655 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2656 return Result;
2657 if ((Result =
2658 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2659 return Result;
2660
2661 // TODO: This comment may be enabled in the future to better match the
2662 // pattern for instruction selection.
2663 /* V2 = V1; */
2664 }
2665
2666 // It is recommended not to change the pattern comparison order for better
2667 // performance.
2668 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2669 return Result;
2670 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2671 return Result;
2672 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2673 return Result;
2674 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2675 return Result;
2676 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2677 return Result;
2678 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2679 return Result;
2680 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2681 (Result =
2682 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2683 return Result;
2684 if ((Result =
2685 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2686 return Result;
2687 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2688 Zeroable)))
2689 return Result;
2690 if ((Result =
2691 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2692 return Result;
2693 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2694 Zeroable)))
2695 return Result;
2696 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2697 Subtarget)))
2698 return Result;
2699 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2700 return NewShuffle;
2701 if ((Result =
2702 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2703 return Result;
2704 return SDValue();
2705}
2706
2707/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2708///
2709/// It is a XVREPLVEI when the mask is:
2710/// <x, x, x, ..., x+n, x+n, x+n, ...>
2711/// where the number of x is equal to n and n is half the length of vector.
2712///
2713/// When undef's appear in the mask they are treated as if they were whatever
2714/// value is necessary in order to fit the above form.
2715static SDValue
2717 SDValue V1, SelectionDAG &DAG,
2718 const LoongArchSubtarget &Subtarget) {
2719 int SplatIndex = -1;
2720 for (const auto &M : Mask) {
2721 if (M != -1) {
2722 SplatIndex = M;
2723 break;
2724 }
2725 }
2726
2727 if (SplatIndex == -1)
2728 return DAG.getUNDEF(VT);
2729
2730 const auto &Begin = Mask.begin();
2731 const auto &End = Mask.end();
2732 int HalfSize = Mask.size() / 2;
2733
2734 if (SplatIndex >= HalfSize)
2735 return SDValue();
2736
2737 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2738 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2739 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2740 0)) {
2741 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2742 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2743 }
2744
2745 return SDValue();
2746}
2747
2748/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2749static SDValue
2751 SDValue V1, SDValue V2, SelectionDAG &DAG,
2752 const LoongArchSubtarget &Subtarget) {
2753 // XVSHUF4I_D must be handled separately because it is different from other
2754 // types of [X]VSHUF4I instructions.
2755 if (Mask.size() == 4) {
2756 unsigned MaskImm = 0;
2757 for (int i = 1; i >= 0; --i) {
2758 int MLo = Mask[i];
2759 int MHi = Mask[i + 2];
2760 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2761 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2762 return SDValue();
2763 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2764 return SDValue();
2765
2766 MaskImm <<= 2;
2767 if (MLo != -1)
2768 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2769 else if (MHi != -1)
2770 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2771 }
2772
2773 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2774 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2775 }
2776
2777 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2778}
2779
2780/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2781static SDValue
2783 SDValue V1, SDValue V2, SelectionDAG &DAG,
2784 const LoongArchSubtarget &Subtarget) {
2785 MVT GRLenVT = Subtarget.getGRLenVT();
2786 unsigned MaskSize = Mask.size();
2787 if (MaskSize != VT.getVectorNumElements())
2788 return SDValue();
2789
2790 // Consider XVPERMI_W.
2791 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2793 unsigned MaskImm = 0;
2794 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2795 return SDValue();
2796
2797 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2798 DAG.getConstant(MaskImm, DL, GRLenVT));
2799 }
2800
2801 // Consider XVPERMI_D.
2802 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2803 unsigned MaskImm = 0;
2804 for (unsigned i = 0; i < MaskSize; ++i) {
2805 if (Mask[i] == -1)
2806 continue;
2807 if (Mask[i] >= (int)MaskSize)
2808 return SDValue();
2809 MaskImm |= Mask[i] << (i * 2);
2810 }
2811
2812 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2813 DAG.getConstant(MaskImm, DL, GRLenVT));
2814 }
2815
2816 return SDValue();
2817}
2818
2819/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2821 MVT VT, SDValue V1, SelectionDAG &DAG,
2822 const LoongArchSubtarget &Subtarget) {
2823 // LoongArch LASX only have XVPERM_W.
2824 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2825 return SDValue();
2826
2827 unsigned NumElts = VT.getVectorNumElements();
2828 unsigned HalfSize = NumElts / 2;
2829 bool FrontLo = true, FrontHi = true;
2830 bool BackLo = true, BackHi = true;
2831
2832 auto inRange = [](int val, int low, int high) {
2833 return (val == -1) || (val >= low && val < high);
2834 };
2835
2836 for (unsigned i = 0; i < HalfSize; ++i) {
2837 int Fronti = Mask[i];
2838 int Backi = Mask[i + HalfSize];
2839
2840 FrontLo &= inRange(Fronti, 0, HalfSize);
2841 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2842 BackLo &= inRange(Backi, 0, HalfSize);
2843 BackHi &= inRange(Backi, HalfSize, NumElts);
2844 }
2845
2846 // If both the lower and upper 128-bit parts access only one half of the
2847 // vector (either lower or upper), avoid using xvperm.w. The latency of
2848 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2849 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2850 return SDValue();
2851
2853 MVT GRLenVT = Subtarget.getGRLenVT();
2854 for (unsigned i = 0; i < NumElts; ++i)
2855 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2856 : DAG.getConstant(Mask[i], DL, GRLenVT));
2857 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2858
2859 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2860}
2861
2862/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2864 MVT VT, SDValue V1, SDValue V2,
2865 SelectionDAG &DAG) {
2866 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2867}
2868
2869/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2871 MVT VT, SDValue V1, SDValue V2,
2872 SelectionDAG &DAG) {
2873 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2874}
2875
2876/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2878 MVT VT, SDValue V1, SDValue V2,
2879 SelectionDAG &DAG) {
2880
2881 const auto &Begin = Mask.begin();
2882 const auto &End = Mask.end();
2883 unsigned HalfSize = Mask.size() / 2;
2884 unsigned LeftSize = HalfSize / 2;
2885 SDValue OriV1 = V1, OriV2 = V2;
2886
2887 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2888 1) &&
2889 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2890 V1 = OriV1;
2891 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2892 Mask.size() + HalfSize - LeftSize, 1) &&
2893 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2894 Mask.size() + HalfSize + LeftSize, 1))
2895 V1 = OriV2;
2896 else
2897 return SDValue();
2898
2899 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
2900 1) &&
2901 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
2902 1))
2903 V2 = OriV1;
2904 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
2905 Mask.size() + HalfSize - LeftSize, 1) &&
2906 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2907 Mask.size() + HalfSize + LeftSize, 1))
2908 V2 = OriV2;
2909 else
2910 return SDValue();
2911
2912 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2913}
2914
2915/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
2917 MVT VT, SDValue V1, SDValue V2,
2918 SelectionDAG &DAG) {
2919
2920 const auto &Begin = Mask.begin();
2921 const auto &End = Mask.end();
2922 unsigned HalfSize = Mask.size() / 2;
2923 SDValue OriV1 = V1, OriV2 = V2;
2924
2925 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
2926 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
2927 V1 = OriV1;
2928 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
2929 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2930 Mask.size() + HalfSize, 1))
2931 V1 = OriV2;
2932 else
2933 return SDValue();
2934
2935 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
2936 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
2937 V2 = OriV1;
2938 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
2939 1) &&
2940 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2941 Mask.size() + HalfSize, 1))
2942 V2 = OriV2;
2943 else
2944 return SDValue();
2945
2946 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2947}
2948
2949/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
2951 MVT VT, SDValue V1, SDValue V2,
2952 SelectionDAG &DAG) {
2953
2954 const auto &Begin = Mask.begin();
2955 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
2956 const auto &Mid = Mask.begin() + Mask.size() / 2;
2957 const auto &RightMid = Mask.end() - Mask.size() / 4;
2958 const auto &End = Mask.end();
2959 unsigned HalfSize = Mask.size() / 2;
2960 SDValue OriV1 = V1, OriV2 = V2;
2961
2962 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
2963 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
2964 V1 = OriV1;
2965 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
2966 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
2967 V1 = OriV2;
2968 else
2969 return SDValue();
2970
2971 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
2972 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
2973 V2 = OriV1;
2974 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
2975 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
2976 V2 = OriV2;
2977
2978 else
2979 return SDValue();
2980
2981 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2982}
2983
2984/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
2986 MVT VT, SDValue V1, SDValue V2,
2987 SelectionDAG &DAG) {
2988
2989 const auto &Begin = Mask.begin();
2990 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
2991 const auto &Mid = Mask.begin() + Mask.size() / 2;
2992 const auto &RightMid = Mask.end() - Mask.size() / 4;
2993 const auto &End = Mask.end();
2994 unsigned HalfSize = Mask.size() / 2;
2995 SDValue OriV1 = V1, OriV2 = V2;
2996
2997 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
2998 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
2999 V1 = OriV1;
3000 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3001 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3002 2))
3003 V1 = OriV2;
3004 else
3005 return SDValue();
3006
3007 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3008 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3009 V2 = OriV1;
3010 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3011 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3012 2))
3013 V2 = OriV2;
3014 else
3015 return SDValue();
3016
3017 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3018}
3019
3020/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3021static SDValue
3023 SDValue V1, SDValue V2, SelectionDAG &DAG,
3024 const LoongArchSubtarget &Subtarget) {
3025 int NumElts = VT.getVectorNumElements();
3026 int HalfSize = NumElts / 2;
3027 MVT EltVT = VT.getVectorElementType();
3028 MVT GRLenVT = Subtarget.getGRLenVT();
3029
3030 if ((int)Mask.size() != NumElts)
3031 return SDValue();
3032
3033 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3034 SmallVector<int> DiffPos;
3035 for (int i = 0; i < NumElts; ++i) {
3036 if (Mask[i] == -1)
3037 continue;
3038 if (Mask[i] != Base + i) {
3039 DiffPos.push_back(i);
3040 if (DiffPos.size() > 2)
3041 return SDValue();
3042 }
3043 }
3044
3045 // Need exactly two differing element to lower into XVEXTRINS.
3046 // If only one differing element, the element at a distance of
3047 // HalfSize from it must be undef.
3048 if (DiffPos.size() == 1) {
3049 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3050 DiffPos.push_back(DiffPos[0] + HalfSize);
3051 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3052 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3053 else
3054 return SDValue();
3055 }
3056 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3057 return SDValue();
3058
3059 // DiffMask must be in its low or high part.
3060 int DiffMaskLo = Mask[DiffPos[0]];
3061 int DiffMaskHi = Mask[DiffPos[1]];
3062 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3063 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3064 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3065 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3066 return SDValue();
3067 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3068 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3069 return SDValue();
3070 if (DiffMaskHi != DiffMaskLo + HalfSize)
3071 return SDValue();
3072
3073 // Determine source vector and source index.
3074 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3075 int SrcIdxLo =
3076 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3077 bool IsEltFP = EltVT.isFloatingPoint();
3078
3079 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3080 // the patterns of XVEXTRINS in tablegen.
3081 SDValue BaseVec = (Base == 0) ? V1 : V2;
3082 SDValue EltLo =
3083 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3084 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3085 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3086 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3087 SDValue EltHi =
3088 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3089 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3090 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3091 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3092
3093 return Result;
3094 };
3095
3096 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3097 if (SDValue Result = tryLowerToExtrAndIns(0))
3098 return Result;
3099 return tryLowerToExtrAndIns(NumElts);
3100}
3101
3102/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3103static SDValue
3105 SDValue V1, SDValue V2, SelectionDAG &DAG,
3106 const LoongArchSubtarget &Subtarget) {
3107 // LoongArch LASX only supports xvinsve0.{w/d}.
3108 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3109 VT != MVT::v4f64)
3110 return SDValue();
3111
3112 MVT GRLenVT = Subtarget.getGRLenVT();
3113 int MaskSize = Mask.size();
3114 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3115
3116 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3117 // all other elements are either 'Base + i' or undef (-1). On success, return
3118 // the index of the replaced element. Otherwise, just return -1.
3119 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3120 int Idx = -1;
3121 for (int i = 0; i < MaskSize; ++i) {
3122 if (Mask[i] == Base + i || Mask[i] == -1)
3123 continue;
3124 if (Mask[i] != Replaced)
3125 return -1;
3126 if (Idx == -1)
3127 Idx = i;
3128 else
3129 return -1;
3130 }
3131 return Idx;
3132 };
3133
3134 // Case 1: the lowest element of V2 replaces one element in V1.
3135 int Idx = checkReplaceOne(0, MaskSize);
3136 if (Idx != -1)
3137 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3138 DAG.getConstant(Idx, DL, GRLenVT));
3139
3140 // Case 2: the lowest element of V1 replaces one element in V2.
3141 Idx = checkReplaceOne(MaskSize, 0);
3142 if (Idx != -1)
3143 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3144 DAG.getConstant(Idx, DL, GRLenVT));
3145
3146 return SDValue();
3147}
3148
3149/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3151 MVT VT, SDValue V1, SDValue V2,
3152 SelectionDAG &DAG) {
3153
3154 int MaskSize = Mask.size();
3155 int HalfSize = Mask.size() / 2;
3156 const auto &Begin = Mask.begin();
3157 const auto &Mid = Mask.begin() + HalfSize;
3158 const auto &End = Mask.end();
3159
3160 // VECTOR_SHUFFLE concatenates the vectors:
3161 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3162 // shuffling ->
3163 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3164 //
3165 // XVSHUF concatenates the vectors:
3166 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3167 // shuffling ->
3168 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3169 SmallVector<SDValue, 8> MaskAlloc;
3170 for (auto it = Begin; it < Mid; it++) {
3171 if (*it < 0) // UNDEF
3172 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3173 else if ((*it >= 0 && *it < HalfSize) ||
3174 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3175 int M = *it < HalfSize ? *it : *it - HalfSize;
3176 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3177 } else
3178 return SDValue();
3179 }
3180 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3181
3182 for (auto it = Mid; it < End; it++) {
3183 if (*it < 0) // UNDEF
3184 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3185 else if ((*it >= HalfSize && *it < MaskSize) ||
3186 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3187 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3188 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3189 } else
3190 return SDValue();
3191 }
3192 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3193
3194 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3195 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3196 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3197}
3198
3199/// Shuffle vectors by lane to generate more optimized instructions.
3200/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3201///
3202/// Therefore, except for the following four cases, other cases are regarded
3203/// as cross-lane shuffles, where optimization is relatively limited.
3204///
3205/// - Shuffle high, low lanes of two inputs vector
3206/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3207/// - Shuffle low, high lanes of two inputs vector
3208/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3209/// - Shuffle low, low lanes of two inputs vector
3210/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3211/// - Shuffle high, high lanes of two inputs vector
3212/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3213///
3214/// The first case is the closest to LoongArch instructions and the other
3215/// cases need to be converted to it for processing.
3216///
3217/// This function will return true for the last three cases above and will
3218/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3219/// cross-lane shuffle cases.
3221 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3222 SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
3223
3224 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3225
3226 int MaskSize = Mask.size();
3227 int HalfSize = Mask.size() / 2;
3228 MVT GRLenVT = Subtarget.getGRLenVT();
3229
3230 HalfMaskType preMask = None, postMask = None;
3231
3232 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3233 return M < 0 || (M >= 0 && M < HalfSize) ||
3234 (M >= MaskSize && M < MaskSize + HalfSize);
3235 }))
3236 preMask = HighLaneTy;
3237 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3238 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3239 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3240 }))
3241 preMask = LowLaneTy;
3242
3243 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3244 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3245 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3246 }))
3247 postMask = LowLaneTy;
3248 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3249 return M < 0 || (M >= 0 && M < HalfSize) ||
3250 (M >= MaskSize && M < MaskSize + HalfSize);
3251 }))
3252 postMask = HighLaneTy;
3253
3254 // The pre-half of mask is high lane type, and the post-half of mask
3255 // is low lane type, which is closest to the LoongArch instructions.
3256 //
3257 // Note: In the LoongArch architecture, the high lane of mask corresponds
3258 // to the lower 128-bit of vector register, and the low lane of mask
3259 // corresponds the higher 128-bit of vector register.
3260 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3261 return false;
3262 }
3263 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3264 V1 = DAG.getBitcast(MVT::v4i64, V1);
3265 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3266 DAG.getConstant(0b01001110, DL, GRLenVT));
3267 V1 = DAG.getBitcast(VT, V1);
3268
3269 if (!V2.isUndef()) {
3270 V2 = DAG.getBitcast(MVT::v4i64, V2);
3271 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3272 DAG.getConstant(0b01001110, DL, GRLenVT));
3273 V2 = DAG.getBitcast(VT, V2);
3274 }
3275
3276 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3277 *it = *it < 0 ? *it : *it - HalfSize;
3278 }
3279 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3280 *it = *it < 0 ? *it : *it + HalfSize;
3281 }
3282 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3283 V1 = DAG.getBitcast(MVT::v4i64, V1);
3284 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3285 DAG.getConstant(0b11101110, DL, GRLenVT));
3286 V1 = DAG.getBitcast(VT, V1);
3287
3288 if (!V2.isUndef()) {
3289 V2 = DAG.getBitcast(MVT::v4i64, V2);
3290 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3291 DAG.getConstant(0b11101110, DL, GRLenVT));
3292 V2 = DAG.getBitcast(VT, V2);
3293 }
3294
3295 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3296 *it = *it < 0 ? *it : *it - HalfSize;
3297 }
3298 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3299 V1 = DAG.getBitcast(MVT::v4i64, V1);
3300 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3301 DAG.getConstant(0b01000100, DL, GRLenVT));
3302 V1 = DAG.getBitcast(VT, V1);
3303
3304 if (!V2.isUndef()) {
3305 V2 = DAG.getBitcast(MVT::v4i64, V2);
3306 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3307 DAG.getConstant(0b01000100, DL, GRLenVT));
3308 V2 = DAG.getBitcast(VT, V2);
3309 }
3310
3311 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3312 *it = *it < 0 ? *it : *it + HalfSize;
3313 }
3314 } else { // cross-lane
3315 return false;
3316 }
3317
3318 return true;
3319}
3320
3321/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3322/// Only for 256-bit vector.
3323///
3324/// For example:
3325/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3326/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3327/// is lowerded to:
3328/// (XVPERMI $xr2, $xr0, 78)
3329/// (XVSHUF $xr1, $xr2, $xr0)
3330/// (XVORI $xr0, $xr1, 0)
3332 ArrayRef<int> Mask,
3333 MVT VT, SDValue V1,
3334 SDValue V2,
3335 SelectionDAG &DAG) {
3336 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3337 int Size = Mask.size();
3338 int LaneSize = Size / 2;
3339
3340 bool LaneCrossing[2] = {false, false};
3341 for (int i = 0; i < Size; ++i)
3342 if (Mask[i] >= 0 && ((Mask[i] % Size) / LaneSize) != (i / LaneSize))
3343 LaneCrossing[(Mask[i] % Size) / LaneSize] = true;
3344
3345 // Ensure that all lanes ared involved.
3346 if (!LaneCrossing[0] && !LaneCrossing[1])
3347 return SDValue();
3348
3349 SmallVector<int> InLaneMask;
3350 InLaneMask.assign(Mask.begin(), Mask.end());
3351 for (int i = 0; i < Size; ++i) {
3352 int &M = InLaneMask[i];
3353 if (M < 0)
3354 continue;
3355 if (((M % Size) / LaneSize) != (i / LaneSize))
3356 M = (M % LaneSize) + ((i / LaneSize) * LaneSize) + Size;
3357 }
3358
3359 SDValue Flipped = DAG.getBitcast(MVT::v4i64, V1);
3360 Flipped = DAG.getVectorShuffle(MVT::v4i64, DL, Flipped,
3361 DAG.getUNDEF(MVT::v4i64), {2, 3, 0, 1});
3362 Flipped = DAG.getBitcast(VT, Flipped);
3363 return DAG.getVectorShuffle(VT, DL, V1, Flipped, InLaneMask);
3364}
3365
3366/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3367///
3368/// This routine breaks down the specific type of 256-bit shuffle and
3369/// dispatches to the lowering routines accordingly.
3371 SDValue V1, SDValue V2, SelectionDAG &DAG,
3372 const LoongArchSubtarget &Subtarget) {
3373 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3374 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3375 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3376 "Vector type is unsupported for lasx!");
3377 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3378 "Two operands have different types!");
3379 assert(VT.getVectorNumElements() == Mask.size() &&
3380 "Unexpected mask size for shuffle!");
3381 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3382 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3383
3384 APInt KnownUndef, KnownZero;
3385 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3386 APInt Zeroable = KnownUndef | KnownZero;
3387
3388 SDValue Result;
3389 // TODO: Add more comparison patterns.
3390 if (V2.isUndef()) {
3391 if ((Result =
3392 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3393 return Result;
3394 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3395 Subtarget)))
3396 return Result;
3397 // Try to widen vectors to gain more optimization opportunities.
3398 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3399 return NewShuffle;
3400 if ((Result =
3401 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3402 return Result;
3403 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3404 return Result;
3405 if ((Result =
3406 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3407 return Result;
3408
3409 // TODO: This comment may be enabled in the future to better match the
3410 // pattern for instruction selection.
3411 /* V2 = V1; */
3412 }
3413
3414 // It is recommended not to change the pattern comparison order for better
3415 // performance.
3416 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3417 return Result;
3418 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3419 return Result;
3420 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3421 return Result;
3422 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3423 return Result;
3424 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3425 return Result;
3426 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3427 return Result;
3428 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3429 (Result =
3430 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3431 return Result;
3432 if ((Result =
3433 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3434 return Result;
3435 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3436 Zeroable)))
3437 return Result;
3438 if ((Result =
3439 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3440 return Result;
3441 if ((Result =
3442 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3443 return Result;
3444 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3445 Subtarget)))
3446 return Result;
3447
3448 // canonicalize non cross-lane shuffle vector
3449 SmallVector<int> NewMask(Mask);
3450 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3451 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3452
3453 // FIXME: Handling the remaining cases earlier can degrade performance
3454 // in some situations. Further analysis is required to enable more
3455 // effective optimizations.
3456 if (V2.isUndef()) {
3457 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT,
3458 V1, V2, DAG)))
3459 return Result;
3460 }
3461
3462 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3463 return NewShuffle;
3464 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3465 return Result;
3466
3467 return SDValue();
3468}
3469
3470SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3471 SelectionDAG &DAG) const {
3472 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3473 ArrayRef<int> OrigMask = SVOp->getMask();
3474 SDValue V1 = Op.getOperand(0);
3475 SDValue V2 = Op.getOperand(1);
3476 MVT VT = Op.getSimpleValueType();
3477 int NumElements = VT.getVectorNumElements();
3478 SDLoc DL(Op);
3479
3480 bool V1IsUndef = V1.isUndef();
3481 bool V2IsUndef = V2.isUndef();
3482 if (V1IsUndef && V2IsUndef)
3483 return DAG.getUNDEF(VT);
3484
3485 // When we create a shuffle node we put the UNDEF node to second operand,
3486 // but in some cases the first operand may be transformed to UNDEF.
3487 // In this case we should just commute the node.
3488 if (V1IsUndef)
3489 return DAG.getCommutedVectorShuffle(*SVOp);
3490
3491 // Check for non-undef masks pointing at an undef vector and make the masks
3492 // undef as well. This makes it easier to match the shuffle based solely on
3493 // the mask.
3494 if (V2IsUndef &&
3495 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3496 SmallVector<int, 8> NewMask(OrigMask);
3497 for (int &M : NewMask)
3498 if (M >= NumElements)
3499 M = -1;
3500 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3501 }
3502
3503 // Check for illegal shuffle mask element index values.
3504 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3505 (void)MaskUpperLimit;
3506 assert(llvm::all_of(OrigMask,
3507 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3508 "Out of bounds shuffle index");
3509
3510 // For each vector width, delegate to a specialized lowering routine.
3511 if (VT.is128BitVector())
3512 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3513
3514 if (VT.is256BitVector())
3515 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3516
3517 return SDValue();
3518}
3519
3520SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3521 SelectionDAG &DAG) const {
3522 // Custom lower to ensure the libcall return is passed in an FPR on hard
3523 // float ABIs.
3524 SDLoc DL(Op);
3525 MakeLibCallOptions CallOptions;
3526 SDValue Op0 = Op.getOperand(0);
3527 SDValue Chain = SDValue();
3528 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3529 SDValue Res;
3530 std::tie(Res, Chain) =
3531 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3532 if (Subtarget.is64Bit())
3533 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3534 return DAG.getBitcast(MVT::i32, Res);
3535}
3536
3537SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3538 SelectionDAG &DAG) const {
3539 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3540 // float ABIs.
3541 SDLoc DL(Op);
3542 MakeLibCallOptions CallOptions;
3543 SDValue Op0 = Op.getOperand(0);
3544 SDValue Chain = SDValue();
3545 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3546 DL, MVT::f32, Op0)
3547 : DAG.getBitcast(MVT::f32, Op0);
3548 SDValue Res;
3549 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3550 CallOptions, DL, Chain);
3551 return Res;
3552}
3553
3554SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3555 SelectionDAG &DAG) const {
3556 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3557 SDLoc DL(Op);
3558 MakeLibCallOptions CallOptions;
3559 RTLIB::Libcall LC =
3560 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3561 SDValue Res =
3562 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3563 if (Subtarget.is64Bit())
3564 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3565 return DAG.getBitcast(MVT::i32, Res);
3566}
3567
3568SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3569 SelectionDAG &DAG) const {
3570 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3571 MVT VT = Op.getSimpleValueType();
3572 SDLoc DL(Op);
3573 Op = DAG.getNode(
3574 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3575 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3576 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3577 DL, MVT::f32, Op)
3578 : DAG.getBitcast(MVT::f32, Op);
3579 if (VT != MVT::f32)
3580 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3581 return Res;
3582}
3583
3584// Lower BUILD_VECTOR as broadcast load (if possible).
3585// For example:
3586// %a = load i8, ptr %ptr
3587// %b = build_vector %a, %a, %a, %a
3588// is lowered to :
3589// (VLDREPL_B $a0, 0)
3591 const SDLoc &DL,
3592 SelectionDAG &DAG) {
3593 MVT VT = BVOp->getSimpleValueType(0);
3594 int NumOps = BVOp->getNumOperands();
3595
3596 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3597 "Unsupported vector type for broadcast.");
3598
3599 SDValue IdentitySrc;
3600 bool IsIdeneity = true;
3601
3602 for (int i = 0; i != NumOps; i++) {
3603 SDValue Op = BVOp->getOperand(i);
3604 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3605 IsIdeneity = false;
3606 break;
3607 }
3608 IdentitySrc = BVOp->getOperand(0);
3609 }
3610
3611 // make sure that this load is valid and only has one user.
3612 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3613 return SDValue();
3614
3615 auto *LN = cast<LoadSDNode>(IdentitySrc);
3616 auto ExtType = LN->getExtensionType();
3617
3618 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3619 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3620 // Indexed loads and stores are not supported on LoongArch.
3621 assert(LN->isUnindexed() && "Unexpected indexed load.");
3622
3623 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3624 // The offset operand of unindexed load is always undefined, so there is
3625 // no need to pass it to VLDREPL.
3626 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3627 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3628 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3629 return BCast;
3630 }
3631 return SDValue();
3632}
3633
3634// Sequentially insert elements from Ops into Vector, from low to high indices.
3635// Note: Ops can have fewer elements than Vector.
3637 const LoongArchSubtarget &Subtarget, SDValue &Vector,
3638 EVT ResTy) {
3639 assert(Ops.size() <= ResTy.getVectorNumElements());
3640
3641 SDValue Op0 = Ops[0];
3642 if (!Op0.isUndef())
3643 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3644 for (unsigned i = 1; i < Ops.size(); ++i) {
3645 SDValue Opi = Ops[i];
3646 if (Opi.isUndef())
3647 continue;
3648 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3649 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3650 }
3651}
3652
3653// Build a ResTy subvector from Node, taking NumElts elements starting at index
3654// 'first'.
3656 SelectionDAG &DAG, SDLoc DL,
3657 const LoongArchSubtarget &Subtarget,
3658 EVT ResTy, unsigned first) {
3659 unsigned NumElts = ResTy.getVectorNumElements();
3660
3661 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3662
3663 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3664 Node->op_begin() + first + NumElts);
3665 SDValue Vector = DAG.getUNDEF(ResTy);
3666 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3667 return Vector;
3668}
3669
3670SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3671 SelectionDAG &DAG) const {
3672 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3673 MVT VT = Node->getSimpleValueType(0);
3674 EVT ResTy = Op->getValueType(0);
3675 unsigned NumElts = ResTy.getVectorNumElements();
3676 SDLoc DL(Op);
3677 APInt SplatValue, SplatUndef;
3678 unsigned SplatBitSize;
3679 bool HasAnyUndefs;
3680 bool IsConstant = false;
3681 bool UseSameConstant = true;
3682 SDValue ConstantValue;
3683 bool Is128Vec = ResTy.is128BitVector();
3684 bool Is256Vec = ResTy.is256BitVector();
3685
3686 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3687 (!Subtarget.hasExtLASX() || !Is256Vec))
3688 return SDValue();
3689
3690 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3691 return Result;
3692
3693 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3694 /*MinSplatBits=*/8) &&
3695 SplatBitSize <= 64) {
3696 // We can only cope with 8, 16, 32, or 64-bit elements.
3697 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3698 SplatBitSize != 64)
3699 return SDValue();
3700
3701 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3702 // We can only handle 64-bit elements that are within
3703 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3704 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3705 if (!SplatValue.isSignedIntN(10) &&
3706 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3707 return SDValue();
3708 if ((Is128Vec && ResTy == MVT::v4i32) ||
3709 (Is256Vec && ResTy == MVT::v8i32))
3710 return Op;
3711 }
3712
3713 EVT ViaVecTy;
3714
3715 switch (SplatBitSize) {
3716 default:
3717 return SDValue();
3718 case 8:
3719 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3720 break;
3721 case 16:
3722 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3723 break;
3724 case 32:
3725 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3726 break;
3727 case 64:
3728 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3729 break;
3730 }
3731
3732 // SelectionDAG::getConstant will promote SplatValue appropriately.
3733 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3734
3735 // Bitcast to the type we originally wanted.
3736 if (ViaVecTy != ResTy)
3737 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3738
3739 return Result;
3740 }
3741
3742 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3743 return Op;
3744
3745 for (unsigned i = 0; i < NumElts; ++i) {
3746 SDValue Opi = Node->getOperand(i);
3747 if (isIntOrFPConstant(Opi)) {
3748 IsConstant = true;
3749 if (!ConstantValue.getNode())
3750 ConstantValue = Opi;
3751 else if (ConstantValue != Opi)
3752 UseSameConstant = false;
3753 }
3754 }
3755
3756 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3757 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3758 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3759 for (unsigned i = 0; i < NumElts; ++i) {
3760 SDValue Opi = Node->getOperand(i);
3761 if (!isIntOrFPConstant(Opi))
3762 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3763 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3764 }
3765 return Result;
3766 }
3767
3768 if (!IsConstant) {
3769 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3770 // the sub-sequence of the vector and then broadcast the sub-sequence.
3771 //
3772 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3773 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3774 // generates worse code in some cases. This could be further optimized
3775 // with more consideration.
3777 BitVector UndefElements;
3778 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3779 UndefElements.count() == 0) {
3780 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3781 // because the high part can be simply treated as undef.
3782 SDValue Vector = DAG.getUNDEF(ResTy);
3783 EVT FillTy = Is256Vec
3785 : ResTy;
3786 SDValue FillVec =
3787 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3788
3789 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3790
3791 unsigned SeqLen = Sequence.size();
3792 unsigned SplatLen = NumElts / SeqLen;
3793 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3794 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3795
3796 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3797 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3798 if (SplatEltTy == MVT::i128)
3799 SplatTy = MVT::v4i64;
3800
3801 SDValue SplatVec;
3802 SDValue SrcVec = DAG.getBitcast(
3803 SplatTy,
3804 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3805 if (Is256Vec) {
3806 SplatVec =
3807 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3808 : LoongArchISD::XVREPLVE0,
3809 DL, SplatTy, SrcVec);
3810 } else {
3811 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3812 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3813 }
3814
3815 return DAG.getBitcast(ResTy, SplatVec);
3816 }
3817
3818 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3819 // using memory operations is much lower.
3820 //
3821 // For 256-bit vectors, normally split into two halves and concatenate.
3822 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
3823 // one non-undef element, skip spliting to avoid a worse result.
3824 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
3825 ResTy == MVT::v4f64) {
3826 unsigned NonUndefCount = 0;
3827 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
3828 if (!Node->getOperand(i).isUndef()) {
3829 ++NonUndefCount;
3830 if (NonUndefCount > 1)
3831 break;
3832 }
3833 }
3834 if (NonUndefCount == 1)
3835 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
3836 }
3837
3838 EVT VecTy =
3839 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
3840 SDValue Vector =
3841 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
3842
3843 if (Is128Vec)
3844 return Vector;
3845
3846 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
3847 VecTy, NumElts / 2);
3848
3849 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
3850 }
3851
3852 return SDValue();
3853}
3854
3855SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
3856 SelectionDAG &DAG) const {
3857 SDLoc DL(Op);
3858 MVT ResVT = Op.getSimpleValueType();
3859 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
3860
3861 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
3862 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
3863 return Op;
3864
3865 unsigned NumOperands = Op.getNumOperands();
3866 unsigned NumFreezeUndef = 0;
3867 unsigned NumZero = 0;
3868 unsigned NumNonZero = 0;
3869 unsigned NonZeros = 0;
3870 SmallSet<SDValue, 4> Undefs;
3871 for (unsigned i = 0; i != NumOperands; ++i) {
3872 SDValue SubVec = Op.getOperand(i);
3873 if (SubVec.isUndef())
3874 continue;
3875 if (ISD::isFreezeUndef(SubVec.getNode())) {
3876 // If the freeze(undef) has multiple uses then we must fold to zero.
3877 if (SubVec.hasOneUse()) {
3878 ++NumFreezeUndef;
3879 } else {
3880 ++NumZero;
3881 Undefs.insert(SubVec);
3882 }
3883 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
3884 ++NumZero;
3885 else {
3886 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
3887 NonZeros |= 1 << i;
3888 ++NumNonZero;
3889 }
3890 }
3891
3892 // If we have more than 2 non-zeros, build each half separately.
3893 if (NumNonZero > 2) {
3894 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
3895 ArrayRef<SDUse> Ops = Op->ops();
3896 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3897 Ops.slice(0, NumOperands / 2));
3898 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3899 Ops.slice(NumOperands / 2));
3900 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
3901 }
3902
3903 // Otherwise, build it up through insert_subvectors.
3904 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
3905 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
3906 : DAG.getUNDEF(ResVT));
3907
3908 // Replace Undef operands with ZeroVector.
3909 for (SDValue U : Undefs)
3910 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
3911
3912 MVT SubVT = Op.getOperand(0).getSimpleValueType();
3913 unsigned NumSubElems = SubVT.getVectorNumElements();
3914 for (unsigned i = 0; i != NumOperands; ++i) {
3915 if ((NonZeros & (1 << i)) == 0)
3916 continue;
3917
3918 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
3919 DAG.getVectorIdxConstant(i * NumSubElems, DL));
3920 }
3921
3922 return Vec;
3923}
3924
3925SDValue
3926LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
3927 SelectionDAG &DAG) const {
3928 MVT EltVT = Op.getSimpleValueType();
3929 SDValue Vec = Op->getOperand(0);
3930 EVT VecTy = Vec->getValueType(0);
3931 SDValue Idx = Op->getOperand(1);
3932 SDLoc DL(Op);
3933 MVT GRLenVT = Subtarget.getGRLenVT();
3934
3935 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
3936
3937 if (isa<ConstantSDNode>(Idx))
3938 return Op;
3939
3940 switch (VecTy.getSimpleVT().SimpleTy) {
3941 default:
3942 llvm_unreachable("Unexpected type");
3943 case MVT::v32i8:
3944 case MVT::v16i16:
3945 case MVT::v4i64:
3946 case MVT::v4f64: {
3947 // Extract the high half subvector and place it to the low half of a new
3948 // vector. It doesn't matter what the high half of the new vector is.
3949 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
3950 SDValue VecHi =
3951 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
3952 SDValue TmpVec =
3953 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
3954 VecHi, DAG.getConstant(0, DL, GRLenVT));
3955
3956 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
3957 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
3958 // desired element.
3959 SDValue IdxCp =
3960 Subtarget.is64Bit()
3961 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
3962 : DAG.getBitcast(MVT::f32, Idx);
3963 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
3964 SDValue MaskVec =
3965 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
3966 SDValue ResVec =
3967 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
3968
3969 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
3970 DAG.getConstant(0, DL, GRLenVT));
3971 }
3972 case MVT::v8i32:
3973 case MVT::v8f32: {
3974 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
3975 SDValue SplatValue =
3976 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
3977
3978 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
3979 DAG.getConstant(0, DL, GRLenVT));
3980 }
3981 }
3982}
3983
3984SDValue
3985LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
3986 SelectionDAG &DAG) const {
3987 MVT VT = Op.getSimpleValueType();
3988 MVT EltVT = VT.getVectorElementType();
3989 unsigned NumElts = VT.getVectorNumElements();
3990 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
3991 SDLoc DL(Op);
3992 SDValue Op0 = Op.getOperand(0);
3993 SDValue Op1 = Op.getOperand(1);
3994 SDValue Op2 = Op.getOperand(2);
3995
3996 if (isa<ConstantSDNode>(Op2))
3997 return Op;
3998
3999 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4000 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4001
4002 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4003 return SDValue();
4004
4005 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4006 SmallVector<SDValue, 32> RawIndices;
4007 SDValue SplatIdx;
4008 SDValue Indices;
4009
4010 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4011 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4012 for (unsigned i = 0; i < NumElts; ++i) {
4013 RawIndices.push_back(Op2);
4014 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4015 }
4016 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4017 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4018
4019 RawIndices.clear();
4020 for (unsigned i = 0; i < NumElts; ++i) {
4021 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4022 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4023 }
4024 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4025 Indices = DAG.getBitcast(IdxVTy, Indices);
4026 } else {
4027 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4028
4029 for (unsigned i = 0; i < NumElts; ++i)
4030 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4031 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4032 }
4033
4034 // insert vec, elt, idx
4035 // =>
4036 // select (splatidx == {0,1,2...}) ? splatelt : vec
4037 SDValue SelectCC =
4038 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4039 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4040}
4041
4042SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4043 SelectionDAG &DAG) const {
4044 SDLoc DL(Op);
4045 SyncScope::ID FenceSSID =
4046 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4047
4048 // singlethread fences only synchronize with signal handlers on the same
4049 // thread and thus only need to preserve instruction order, not actually
4050 // enforce memory ordering.
4051 if (FenceSSID == SyncScope::SingleThread)
4052 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4053 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4054
4055 return Op;
4056}
4057
4059 MVT GRLenVT, SDValue RMValue) {
4060 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4061 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4062 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4063 //
4064 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4065 // Since the transformation is self-inverse, it applies in both directions:
4066 // LLVM RM <-> LoongArch FCSR RM
4067 //
4068 // Transformation: RM ^ (~(RM >> 1) & 1)
4069 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4070 DAG.getConstant(1, DL, GRLenVT));
4071
4072 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4073 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4074 DAG.getConstant(1, DL, GRLenVT)),
4075 DAG.getConstant(1, DL, GRLenVT));
4076
4077 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4078}
4079
4080SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4081 SelectionDAG &DAG) const {
4082 MVT GRLenVT = Subtarget.getGRLenVT();
4083 SDLoc DL(Op);
4084 SDValue Chain = Op.getOperand(0);
4085 SDValue RMValue = Op.getOperand(1);
4086
4087 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4088 uint64_t RM = CVal->getZExtValue();
4089 if (RM > 3) {
4090 MachineFunction &MF = DAG.getMachineFunction();
4091 LLVMContext &C = MF.getFunction().getContext();
4092 C.diagnose(DiagnosticInfoUnsupported(
4093 MF.getFunction(),
4094 "rounding mode is not supported by LoongArch hardware",
4095 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4096 return Chain;
4097 }
4098 }
4099
4100 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4101 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4102
4103 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4104 // into position before writing via WRFCSR.
4105 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4106 DAG.getConstant(8, DL, GRLenVT));
4107
4108 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4109 // unrelated fields in FCSR0.
4110 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4111 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4112 FCSRNo, RMValue, Chain);
4113 return SDValue(RN, 0);
4114}
4115
4116SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4117 SelectionDAG &DAG) const {
4118 MVT GRLenVT = Subtarget.getGRLenVT();
4119 SDLoc DL(Op);
4120 SDValue Chain = Op->getOperand(0);
4121
4122 // FCSR3 is an alias of the RM field.
4123 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4124 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4125 MVT::Other, FCSRNo, Chain);
4126 SDValue RMValue = SDValue(FCSR, 0);
4127 Chain = SDValue(FCSR, 1);
4128
4129 // The RM field in FCSR is at bits [9:8].
4130 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4131 DAG.getConstant(8, DL, GRLenVT));
4132 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4133
4134 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4135 return DAG.getMergeValues({RetVal, Chain}, DL);
4136}
4137
4138SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4139 SelectionDAG &DAG) const {
4140
4141 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4142 DAG.getContext()->emitError(
4143 "On LA64, only 64-bit registers can be written.");
4144 return Op.getOperand(0);
4145 }
4146
4147 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4148 DAG.getContext()->emitError(
4149 "On LA32, only 32-bit registers can be written.");
4150 return Op.getOperand(0);
4151 }
4152
4153 return Op;
4154}
4155
4156SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4157 SelectionDAG &DAG) const {
4158 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4159 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4160 "be a constant integer");
4161 return SDValue();
4162 }
4163
4164 MachineFunction &MF = DAG.getMachineFunction();
4166 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4167 EVT VT = Op.getValueType();
4168 SDLoc DL(Op);
4169 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4170 unsigned Depth = Op.getConstantOperandVal(0);
4171 int GRLenInBytes = Subtarget.getGRLen() / 8;
4172
4173 while (Depth--) {
4174 int Offset = -(GRLenInBytes * 2);
4175 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4176 DAG.getSignedConstant(Offset, DL, VT));
4177 FrameAddr =
4178 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4179 }
4180 return FrameAddr;
4181}
4182
4183SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4184 SelectionDAG &DAG) const {
4185 // Currently only support lowering return address for current frame.
4186 if (Op.getConstantOperandVal(0) != 0) {
4187 DAG.getContext()->emitError(
4188 "return address can only be determined for the current frame");
4189 return SDValue();
4190 }
4191
4192 MachineFunction &MF = DAG.getMachineFunction();
4194 MVT GRLenVT = Subtarget.getGRLenVT();
4195
4196 // Return the value of the return address register, marking it an implicit
4197 // live-in.
4198 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4199 getRegClassFor(GRLenVT));
4200 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4201}
4202
4203SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4204 SelectionDAG &DAG) const {
4205 MachineFunction &MF = DAG.getMachineFunction();
4206 auto Size = Subtarget.getGRLen() / 8;
4207 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4208 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4209}
4210
4211SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4212 SelectionDAG &DAG) const {
4213 MachineFunction &MF = DAG.getMachineFunction();
4214 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4215
4216 SDLoc DL(Op);
4217 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4219
4220 // vastart just stores the address of the VarArgsFrameIndex slot into the
4221 // memory location argument.
4222 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4223 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4224 MachinePointerInfo(SV));
4225}
4226
4227SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4228 SelectionDAG &DAG) const {
4229 SDLoc DL(Op);
4230 SDValue Op0 = Op.getOperand(0);
4231 EVT VT = Op.getValueType();
4232 EVT Op0VT = Op0.getValueType();
4233
4234 if (VT.isVector()) {
4235 if (VT.getScalarSizeInBits() != Op0VT.getScalarSizeInBits())
4236 return SDValue();
4237 return Op;
4238 }
4239
4240 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4243 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4244
4245 // We can't do uint64 -> double -> float because of double-rounding issue.
4246 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4247 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4248 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4249 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4250 DAG.getIntPtrConstant(0, DL));
4251 return Conv;
4252 }
4253
4254 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4255 return SDValue();
4256
4257 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4258 !Subtarget.hasBasicD() && "unexpected target features");
4259
4260 if (Op0->getOpcode() == ISD::AND) {
4261 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4262 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4263 return Op;
4264 }
4265
4266 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4267 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4268 Op0.getConstantOperandVal(2) == UINT64_C(0))
4269 return Op;
4270
4271 if (Op0.getOpcode() == ISD::AssertZext &&
4272 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4273 return Op;
4274
4275 EVT OpVT = Op0.getValueType();
4276 EVT RetVT = Op.getValueType();
4277 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4278 MakeLibCallOptions CallOptions;
4279 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4280 SDValue Chain = SDValue();
4282 std::tie(Result, Chain) =
4283 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4284 return Result;
4285}
4286
4287SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4288 SelectionDAG &DAG) const {
4289 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4290 !Subtarget.hasBasicD() && "unexpected target features");
4291
4292 SDLoc DL(Op);
4293 SDValue Op0 = Op.getOperand(0);
4294
4295 if ((Op0.getOpcode() == ISD::AssertSext ||
4297 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4298 return Op;
4299
4300 EVT OpVT = Op0.getValueType();
4301 EVT RetVT = Op.getValueType();
4302 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4303 MakeLibCallOptions CallOptions;
4304 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4305 SDValue Chain = SDValue();
4307 std::tie(Result, Chain) =
4308 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4309 return Result;
4310}
4311
4312SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4313 SelectionDAG &DAG) const {
4314
4315 SDLoc DL(Op);
4316 EVT VT = Op.getValueType();
4317 SDValue Op0 = Op.getOperand(0);
4318 EVT Op0VT = Op0.getValueType();
4319
4320 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4321 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4322 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4323 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4324 }
4325 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4326 SDValue Lo, Hi;
4327 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4328 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4329 }
4330 return Op;
4331}
4332
4333SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4334 SelectionDAG &DAG) const {
4335
4336 SDLoc DL(Op);
4337 SDValue Op0 = Op.getOperand(0);
4338
4339 if (Op0.getValueType() == MVT::f16)
4340 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4341
4342 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4343 !Subtarget.hasBasicD()) {
4344 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4345 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4346 }
4347
4348 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4349 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4350 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4351}
4352
4353SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4354 SelectionDAG &DAG) const {
4355 if (!Subtarget.hasExtLSX())
4356 return SDValue();
4357
4358 SDLoc DL(Op);
4359 SDValue Src = Op.getOperand(0);
4360 EVT VT = Op.getValueType();
4361 EVT SrcVT = Src.getValueType();
4362
4363 if (VT != MVT::i64)
4364 return SDValue();
4365
4366 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4367 return SDValue();
4368
4369 if (SrcVT == MVT::f32)
4370 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4371 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4372 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4373 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4374 DAG.getIntPtrConstant(0, DL));
4375}
4376
4378 SelectionDAG &DAG, unsigned Flags) {
4379 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4380}
4381
4383 SelectionDAG &DAG, unsigned Flags) {
4384 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4385 Flags);
4386}
4387
4389 SelectionDAG &DAG, unsigned Flags) {
4390 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4391 N->getOffset(), Flags);
4392}
4393
4395 SelectionDAG &DAG, unsigned Flags) {
4396 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4397}
4398
4399template <class NodeTy>
4400SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4402 bool IsLocal) const {
4403 SDLoc DL(N);
4404 EVT Ty = getPointerTy(DAG.getDataLayout());
4405 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4406 SDValue Load;
4407
4408 switch (M) {
4409 default:
4410 report_fatal_error("Unsupported code model");
4411
4412 case CodeModel::Large: {
4413 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4414
4415 // This is not actually used, but is necessary for successfully matching
4416 // the PseudoLA_*_LARGE nodes.
4417 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4418 if (IsLocal) {
4419 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4420 // eventually becomes the desired 5-insn code sequence.
4421 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4422 Tmp, Addr),
4423 0);
4424 } else {
4425 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4426 // eventually becomes the desired 5-insn code sequence.
4427 Load = SDValue(
4428 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4429 0);
4430 }
4431 break;
4432 }
4433
4434 case CodeModel::Small:
4435 case CodeModel::Medium:
4436 if (IsLocal) {
4437 // This generates the pattern (PseudoLA_PCREL sym), which
4438 //
4439 // for la32r expands to:
4440 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4441 //
4442 // for la32s and la64 expands to:
4443 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4444 Load = SDValue(
4445 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4446 } else {
4447 // This generates the pattern (PseudoLA_GOT sym), which
4448 //
4449 // for la32r expands to:
4450 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4451 //
4452 // for la32s and la64 expands to:
4453 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4454 Load =
4455 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4456 }
4457 }
4458
4459 if (!IsLocal) {
4460 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4461 MachineFunction &MF = DAG.getMachineFunction();
4462 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4466 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4467 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4468 }
4469
4470 return Load;
4471}
4472
4473SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4474 SelectionDAG &DAG) const {
4475 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4476 DAG.getTarget().getCodeModel());
4477}
4478
4479SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4480 SelectionDAG &DAG) const {
4481 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4482 DAG.getTarget().getCodeModel());
4483}
4484
4485SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4486 SelectionDAG &DAG) const {
4487 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4488 DAG.getTarget().getCodeModel());
4489}
4490
4491SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4492 SelectionDAG &DAG) const {
4493 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4494 assert(N->getOffset() == 0 && "unexpected offset in global node");
4495 auto CM = DAG.getTarget().getCodeModel();
4496 const GlobalValue *GV = N->getGlobal();
4497
4498 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4499 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4500 CM = *GCM;
4501 }
4502
4503 return getAddr(N, DAG, CM, GV->isDSOLocal());
4504}
4505
4506SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4507 SelectionDAG &DAG,
4508 unsigned Opc, bool UseGOT,
4509 bool Large) const {
4510 SDLoc DL(N);
4511 EVT Ty = getPointerTy(DAG.getDataLayout());
4512 MVT GRLenVT = Subtarget.getGRLenVT();
4513
4514 // This is not actually used, but is necessary for successfully matching the
4515 // PseudoLA_*_LARGE nodes.
4516 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4517 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4518
4519 // Only IE needs an extra argument for large code model.
4520 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4521 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4522 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4523
4524 // If it is LE for normal/medium code model, the add tp operation will occur
4525 // during the pseudo-instruction expansion.
4526 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4527 return Offset;
4528
4529 if (UseGOT) {
4530 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4531 MachineFunction &MF = DAG.getMachineFunction();
4532 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4536 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4537 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4538 }
4539
4540 // Add the thread pointer.
4541 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4542 DAG.getRegister(LoongArch::R2, GRLenVT));
4543}
4544
4545SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4546 SelectionDAG &DAG,
4547 unsigned Opc,
4548 bool Large) const {
4549 SDLoc DL(N);
4550 EVT Ty = getPointerTy(DAG.getDataLayout());
4551 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4552
4553 // This is not actually used, but is necessary for successfully matching the
4554 // PseudoLA_*_LARGE nodes.
4555 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4556
4557 // Use a PC-relative addressing mode to access the dynamic GOT address.
4558 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4559 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4560 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4561
4562 // Prepare argument list to generate call.
4564 Args.emplace_back(Load, CallTy);
4565
4566 // Setup call to __tls_get_addr.
4567 TargetLowering::CallLoweringInfo CLI(DAG);
4568 CLI.setDebugLoc(DL)
4569 .setChain(DAG.getEntryNode())
4570 .setLibCallee(CallingConv::C, CallTy,
4571 DAG.getExternalSymbol("__tls_get_addr", Ty),
4572 std::move(Args));
4573
4574 return LowerCallTo(CLI).first;
4575}
4576
4577SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4578 SelectionDAG &DAG, unsigned Opc,
4579 bool Large) const {
4580 SDLoc DL(N);
4581 EVT Ty = getPointerTy(DAG.getDataLayout());
4582 const GlobalValue *GV = N->getGlobal();
4583
4584 // This is not actually used, but is necessary for successfully matching the
4585 // PseudoLA_*_LARGE nodes.
4586 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4587
4588 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4589 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4590 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4591 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4592 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4593}
4594
4595SDValue
4596LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4597 SelectionDAG &DAG) const {
4600 report_fatal_error("In GHC calling convention TLS is not supported");
4601
4602 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4603 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4604
4605 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4606 assert(N->getOffset() == 0 && "unexpected offset in global node");
4607
4608 if (DAG.getTarget().useEmulatedTLS())
4609 reportFatalUsageError("the emulated TLS is prohibited");
4610
4611 bool IsDesc = DAG.getTarget().useTLSDESC();
4612
4613 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4615 // In this model, application code calls the dynamic linker function
4616 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4617 // runtime.
4618 if (!IsDesc)
4619 return getDynamicTLSAddr(N, DAG,
4620 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4621 : LoongArch::PseudoLA_TLS_GD,
4622 Large);
4623 break;
4625 // Same as GeneralDynamic, except for assembly modifiers and relocation
4626 // records.
4627 if (!IsDesc)
4628 return getDynamicTLSAddr(N, DAG,
4629 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4630 : LoongArch::PseudoLA_TLS_LD,
4631 Large);
4632 break;
4634 // This model uses the GOT to resolve TLS offsets.
4635 return getStaticTLSAddr(N, DAG,
4636 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4637 : LoongArch::PseudoLA_TLS_IE,
4638 /*UseGOT=*/true, Large);
4640 // This model is used when static linking as the TLS offsets are resolved
4641 // during program linking.
4642 //
4643 // This node doesn't need an extra argument for the large code model.
4644 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4645 /*UseGOT=*/false, Large);
4646 }
4647
4648 return getTLSDescAddr(N, DAG,
4649 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4650 : LoongArch::PseudoLA_TLS_DESC,
4651 Large);
4652}
4653
4654template <unsigned N>
4656 SelectionDAG &DAG, bool IsSigned = false) {
4657 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4658 // Check the ImmArg.
4659 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4660 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4661 DAG.getContext()->emitError(Op->getOperationName(0) +
4662 ": argument out of range.");
4663 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4664 }
4665 return SDValue();
4666}
4667
4668SDValue
4669LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4670 SelectionDAG &DAG) const {
4671 switch (Op.getConstantOperandVal(0)) {
4672 default:
4673 return SDValue(); // Don't custom lower most intrinsics.
4674 case Intrinsic::thread_pointer: {
4675 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4676 return DAG.getRegister(LoongArch::R2, PtrVT);
4677 }
4678 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4679 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4680 case Intrinsic::loongarch_lsx_vreplvei_d:
4681 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4682 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4683 case Intrinsic::loongarch_lsx_vreplvei_w:
4684 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4685 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4686 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
4687 case Intrinsic::loongarch_lasx_xvpickve_d:
4688 case Intrinsic::loongarch_lasx_xvpickve_d_f:
4689 return checkIntrinsicImmArg<2>(Op, 2, DAG);
4690 case Intrinsic::loongarch_lasx_xvinsve0_d:
4691 return checkIntrinsicImmArg<2>(Op, 3, DAG);
4692 case Intrinsic::loongarch_lsx_vsat_b:
4693 case Intrinsic::loongarch_lsx_vsat_bu:
4694 case Intrinsic::loongarch_lsx_vrotri_b:
4695 case Intrinsic::loongarch_lsx_vsllwil_h_b:
4696 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
4697 case Intrinsic::loongarch_lsx_vsrlri_b:
4698 case Intrinsic::loongarch_lsx_vsrari_b:
4699 case Intrinsic::loongarch_lsx_vreplvei_h:
4700 case Intrinsic::loongarch_lasx_xvsat_b:
4701 case Intrinsic::loongarch_lasx_xvsat_bu:
4702 case Intrinsic::loongarch_lasx_xvrotri_b:
4703 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
4704 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
4705 case Intrinsic::loongarch_lasx_xvsrlri_b:
4706 case Intrinsic::loongarch_lasx_xvsrari_b:
4707 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
4708 case Intrinsic::loongarch_lasx_xvpickve_w:
4709 case Intrinsic::loongarch_lasx_xvpickve_w_f:
4710 return checkIntrinsicImmArg<3>(Op, 2, DAG);
4711 case Intrinsic::loongarch_lasx_xvinsve0_w:
4712 return checkIntrinsicImmArg<3>(Op, 3, DAG);
4713 case Intrinsic::loongarch_lsx_vsat_h:
4714 case Intrinsic::loongarch_lsx_vsat_hu:
4715 case Intrinsic::loongarch_lsx_vrotri_h:
4716 case Intrinsic::loongarch_lsx_vsllwil_w_h:
4717 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
4718 case Intrinsic::loongarch_lsx_vsrlri_h:
4719 case Intrinsic::loongarch_lsx_vsrari_h:
4720 case Intrinsic::loongarch_lsx_vreplvei_b:
4721 case Intrinsic::loongarch_lasx_xvsat_h:
4722 case Intrinsic::loongarch_lasx_xvsat_hu:
4723 case Intrinsic::loongarch_lasx_xvrotri_h:
4724 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
4725 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
4726 case Intrinsic::loongarch_lasx_xvsrlri_h:
4727 case Intrinsic::loongarch_lasx_xvsrari_h:
4728 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
4729 return checkIntrinsicImmArg<4>(Op, 2, DAG);
4730 case Intrinsic::loongarch_lsx_vsrlni_b_h:
4731 case Intrinsic::loongarch_lsx_vsrani_b_h:
4732 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
4733 case Intrinsic::loongarch_lsx_vsrarni_b_h:
4734 case Intrinsic::loongarch_lsx_vssrlni_b_h:
4735 case Intrinsic::loongarch_lsx_vssrani_b_h:
4736 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
4737 case Intrinsic::loongarch_lsx_vssrani_bu_h:
4738 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
4739 case Intrinsic::loongarch_lsx_vssrarni_b_h:
4740 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
4741 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
4742 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
4743 case Intrinsic::loongarch_lasx_xvsrani_b_h:
4744 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
4745 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
4746 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
4747 case Intrinsic::loongarch_lasx_xvssrani_b_h:
4748 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
4749 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
4750 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
4751 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
4752 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
4753 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
4754 return checkIntrinsicImmArg<4>(Op, 3, DAG);
4755 case Intrinsic::loongarch_lsx_vsat_w:
4756 case Intrinsic::loongarch_lsx_vsat_wu:
4757 case Intrinsic::loongarch_lsx_vrotri_w:
4758 case Intrinsic::loongarch_lsx_vsllwil_d_w:
4759 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
4760 case Intrinsic::loongarch_lsx_vsrlri_w:
4761 case Intrinsic::loongarch_lsx_vsrari_w:
4762 case Intrinsic::loongarch_lsx_vslei_bu:
4763 case Intrinsic::loongarch_lsx_vslei_hu:
4764 case Intrinsic::loongarch_lsx_vslei_wu:
4765 case Intrinsic::loongarch_lsx_vslei_du:
4766 case Intrinsic::loongarch_lsx_vslti_bu:
4767 case Intrinsic::loongarch_lsx_vslti_hu:
4768 case Intrinsic::loongarch_lsx_vslti_wu:
4769 case Intrinsic::loongarch_lsx_vslti_du:
4770 case Intrinsic::loongarch_lsx_vbsll_v:
4771 case Intrinsic::loongarch_lsx_vbsrl_v:
4772 case Intrinsic::loongarch_lasx_xvsat_w:
4773 case Intrinsic::loongarch_lasx_xvsat_wu:
4774 case Intrinsic::loongarch_lasx_xvrotri_w:
4775 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
4776 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
4777 case Intrinsic::loongarch_lasx_xvsrlri_w:
4778 case Intrinsic::loongarch_lasx_xvsrari_w:
4779 case Intrinsic::loongarch_lasx_xvslei_bu:
4780 case Intrinsic::loongarch_lasx_xvslei_hu:
4781 case Intrinsic::loongarch_lasx_xvslei_wu:
4782 case Intrinsic::loongarch_lasx_xvslei_du:
4783 case Intrinsic::loongarch_lasx_xvslti_bu:
4784 case Intrinsic::loongarch_lasx_xvslti_hu:
4785 case Intrinsic::loongarch_lasx_xvslti_wu:
4786 case Intrinsic::loongarch_lasx_xvslti_du:
4787 case Intrinsic::loongarch_lasx_xvbsll_v:
4788 case Intrinsic::loongarch_lasx_xvbsrl_v:
4789 return checkIntrinsicImmArg<5>(Op, 2, DAG);
4790 case Intrinsic::loongarch_lsx_vseqi_b:
4791 case Intrinsic::loongarch_lsx_vseqi_h:
4792 case Intrinsic::loongarch_lsx_vseqi_w:
4793 case Intrinsic::loongarch_lsx_vseqi_d:
4794 case Intrinsic::loongarch_lsx_vslei_b:
4795 case Intrinsic::loongarch_lsx_vslei_h:
4796 case Intrinsic::loongarch_lsx_vslei_w:
4797 case Intrinsic::loongarch_lsx_vslei_d:
4798 case Intrinsic::loongarch_lsx_vslti_b:
4799 case Intrinsic::loongarch_lsx_vslti_h:
4800 case Intrinsic::loongarch_lsx_vslti_w:
4801 case Intrinsic::loongarch_lsx_vslti_d:
4802 case Intrinsic::loongarch_lasx_xvseqi_b:
4803 case Intrinsic::loongarch_lasx_xvseqi_h:
4804 case Intrinsic::loongarch_lasx_xvseqi_w:
4805 case Intrinsic::loongarch_lasx_xvseqi_d:
4806 case Intrinsic::loongarch_lasx_xvslei_b:
4807 case Intrinsic::loongarch_lasx_xvslei_h:
4808 case Intrinsic::loongarch_lasx_xvslei_w:
4809 case Intrinsic::loongarch_lasx_xvslei_d:
4810 case Intrinsic::loongarch_lasx_xvslti_b:
4811 case Intrinsic::loongarch_lasx_xvslti_h:
4812 case Intrinsic::loongarch_lasx_xvslti_w:
4813 case Intrinsic::loongarch_lasx_xvslti_d:
4814 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
4815 case Intrinsic::loongarch_lsx_vsrlni_h_w:
4816 case Intrinsic::loongarch_lsx_vsrani_h_w:
4817 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
4818 case Intrinsic::loongarch_lsx_vsrarni_h_w:
4819 case Intrinsic::loongarch_lsx_vssrlni_h_w:
4820 case Intrinsic::loongarch_lsx_vssrani_h_w:
4821 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
4822 case Intrinsic::loongarch_lsx_vssrani_hu_w:
4823 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
4824 case Intrinsic::loongarch_lsx_vssrarni_h_w:
4825 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
4826 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
4827 case Intrinsic::loongarch_lsx_vfrstpi_b:
4828 case Intrinsic::loongarch_lsx_vfrstpi_h:
4829 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
4830 case Intrinsic::loongarch_lasx_xvsrani_h_w:
4831 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
4832 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
4833 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
4834 case Intrinsic::loongarch_lasx_xvssrani_h_w:
4835 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
4836 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
4837 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
4838 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
4839 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
4840 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
4841 case Intrinsic::loongarch_lasx_xvfrstpi_b:
4842 case Intrinsic::loongarch_lasx_xvfrstpi_h:
4843 return checkIntrinsicImmArg<5>(Op, 3, DAG);
4844 case Intrinsic::loongarch_lsx_vsat_d:
4845 case Intrinsic::loongarch_lsx_vsat_du:
4846 case Intrinsic::loongarch_lsx_vrotri_d:
4847 case Intrinsic::loongarch_lsx_vsrlri_d:
4848 case Intrinsic::loongarch_lsx_vsrari_d:
4849 case Intrinsic::loongarch_lasx_xvsat_d:
4850 case Intrinsic::loongarch_lasx_xvsat_du:
4851 case Intrinsic::loongarch_lasx_xvrotri_d:
4852 case Intrinsic::loongarch_lasx_xvsrlri_d:
4853 case Intrinsic::loongarch_lasx_xvsrari_d:
4854 return checkIntrinsicImmArg<6>(Op, 2, DAG);
4855 case Intrinsic::loongarch_lsx_vsrlni_w_d:
4856 case Intrinsic::loongarch_lsx_vsrani_w_d:
4857 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
4858 case Intrinsic::loongarch_lsx_vsrarni_w_d:
4859 case Intrinsic::loongarch_lsx_vssrlni_w_d:
4860 case Intrinsic::loongarch_lsx_vssrani_w_d:
4861 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
4862 case Intrinsic::loongarch_lsx_vssrani_wu_d:
4863 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
4864 case Intrinsic::loongarch_lsx_vssrarni_w_d:
4865 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
4866 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
4867 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
4868 case Intrinsic::loongarch_lasx_xvsrani_w_d:
4869 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
4870 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
4871 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
4872 case Intrinsic::loongarch_lasx_xvssrani_w_d:
4873 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
4874 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
4875 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
4876 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
4877 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
4878 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
4879 return checkIntrinsicImmArg<6>(Op, 3, DAG);
4880 case Intrinsic::loongarch_lsx_vsrlni_d_q:
4881 case Intrinsic::loongarch_lsx_vsrani_d_q:
4882 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
4883 case Intrinsic::loongarch_lsx_vsrarni_d_q:
4884 case Intrinsic::loongarch_lsx_vssrlni_d_q:
4885 case Intrinsic::loongarch_lsx_vssrani_d_q:
4886 case Intrinsic::loongarch_lsx_vssrlni_du_q:
4887 case Intrinsic::loongarch_lsx_vssrani_du_q:
4888 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
4889 case Intrinsic::loongarch_lsx_vssrarni_d_q:
4890 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
4891 case Intrinsic::loongarch_lsx_vssrarni_du_q:
4892 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
4893 case Intrinsic::loongarch_lasx_xvsrani_d_q:
4894 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
4895 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
4896 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
4897 case Intrinsic::loongarch_lasx_xvssrani_d_q:
4898 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
4899 case Intrinsic::loongarch_lasx_xvssrani_du_q:
4900 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
4901 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
4902 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
4903 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
4904 return checkIntrinsicImmArg<7>(Op, 3, DAG);
4905 case Intrinsic::loongarch_lsx_vnori_b:
4906 case Intrinsic::loongarch_lsx_vshuf4i_b:
4907 case Intrinsic::loongarch_lsx_vshuf4i_h:
4908 case Intrinsic::loongarch_lsx_vshuf4i_w:
4909 case Intrinsic::loongarch_lasx_xvnori_b:
4910 case Intrinsic::loongarch_lasx_xvshuf4i_b:
4911 case Intrinsic::loongarch_lasx_xvshuf4i_h:
4912 case Intrinsic::loongarch_lasx_xvshuf4i_w:
4913 case Intrinsic::loongarch_lasx_xvpermi_d:
4914 return checkIntrinsicImmArg<8>(Op, 2, DAG);
4915 case Intrinsic::loongarch_lsx_vshuf4i_d:
4916 case Intrinsic::loongarch_lsx_vpermi_w:
4917 case Intrinsic::loongarch_lsx_vbitseli_b:
4918 case Intrinsic::loongarch_lsx_vextrins_b:
4919 case Intrinsic::loongarch_lsx_vextrins_h:
4920 case Intrinsic::loongarch_lsx_vextrins_w:
4921 case Intrinsic::loongarch_lsx_vextrins_d:
4922 case Intrinsic::loongarch_lasx_xvshuf4i_d:
4923 case Intrinsic::loongarch_lasx_xvpermi_w:
4924 case Intrinsic::loongarch_lasx_xvpermi_q:
4925 case Intrinsic::loongarch_lasx_xvbitseli_b:
4926 case Intrinsic::loongarch_lasx_xvextrins_b:
4927 case Intrinsic::loongarch_lasx_xvextrins_h:
4928 case Intrinsic::loongarch_lasx_xvextrins_w:
4929 case Intrinsic::loongarch_lasx_xvextrins_d:
4930 return checkIntrinsicImmArg<8>(Op, 3, DAG);
4931 case Intrinsic::loongarch_lsx_vrepli_b:
4932 case Intrinsic::loongarch_lsx_vrepli_h:
4933 case Intrinsic::loongarch_lsx_vrepli_w:
4934 case Intrinsic::loongarch_lsx_vrepli_d:
4935 case Intrinsic::loongarch_lasx_xvrepli_b:
4936 case Intrinsic::loongarch_lasx_xvrepli_h:
4937 case Intrinsic::loongarch_lasx_xvrepli_w:
4938 case Intrinsic::loongarch_lasx_xvrepli_d:
4939 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
4940 case Intrinsic::loongarch_lsx_vldi:
4941 case Intrinsic::loongarch_lasx_xvldi:
4942 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
4943 }
4944}
4945
4946// Helper function that emits error message for intrinsics with chain and return
4947// merge values of a UNDEF and the chain.
4949 StringRef ErrorMsg,
4950 SelectionDAG &DAG) {
4951 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
4952 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
4953 SDLoc(Op));
4954}
4955
4956SDValue
4957LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
4958 SelectionDAG &DAG) const {
4959 SDLoc DL(Op);
4960 MVT GRLenVT = Subtarget.getGRLenVT();
4961 EVT VT = Op.getValueType();
4962 SDValue Chain = Op.getOperand(0);
4963 const StringRef ErrorMsgOOR = "argument out of range";
4964 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
4965 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
4966
4967 switch (Op.getConstantOperandVal(1)) {
4968 default:
4969 return Op;
4970 case Intrinsic::loongarch_crc_w_b_w:
4971 case Intrinsic::loongarch_crc_w_h_w:
4972 case Intrinsic::loongarch_crc_w_w_w:
4973 case Intrinsic::loongarch_crc_w_d_w:
4974 case Intrinsic::loongarch_crcc_w_b_w:
4975 case Intrinsic::loongarch_crcc_w_h_w:
4976 case Intrinsic::loongarch_crcc_w_w_w:
4977 case Intrinsic::loongarch_crcc_w_d_w:
4978 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
4979 case Intrinsic::loongarch_csrrd_w:
4980 case Intrinsic::loongarch_csrrd_d: {
4981 unsigned Imm = Op.getConstantOperandVal(2);
4982 return !isUInt<14>(Imm)
4983 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
4984 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
4985 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
4986 }
4987 case Intrinsic::loongarch_csrwr_w:
4988 case Intrinsic::loongarch_csrwr_d: {
4989 unsigned Imm = Op.getConstantOperandVal(3);
4990 return !isUInt<14>(Imm)
4991 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
4992 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
4993 {Chain, Op.getOperand(2),
4994 DAG.getConstant(Imm, DL, GRLenVT)});
4995 }
4996 case Intrinsic::loongarch_csrxchg_w:
4997 case Intrinsic::loongarch_csrxchg_d: {
4998 unsigned Imm = Op.getConstantOperandVal(4);
4999 return !isUInt<14>(Imm)
5000 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5001 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5002 {Chain, Op.getOperand(2), Op.getOperand(3),
5003 DAG.getConstant(Imm, DL, GRLenVT)});
5004 }
5005 case Intrinsic::loongarch_iocsrrd_d: {
5006 return DAG.getNode(
5007 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5008 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5009 }
5010#define IOCSRRD_CASE(NAME, NODE) \
5011 case Intrinsic::loongarch_##NAME: { \
5012 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5013 {Chain, Op.getOperand(2)}); \
5014 }
5015 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5016 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5017 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5018#undef IOCSRRD_CASE
5019 case Intrinsic::loongarch_cpucfg: {
5020 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5021 {Chain, Op.getOperand(2)});
5022 }
5023 case Intrinsic::loongarch_lddir_d: {
5024 unsigned Imm = Op.getConstantOperandVal(3);
5025 return !isUInt<8>(Imm)
5026 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5027 : Op;
5028 }
5029 case Intrinsic::loongarch_movfcsr2gr: {
5030 if (!Subtarget.hasBasicF())
5031 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5032 unsigned Imm = Op.getConstantOperandVal(2);
5033 return !isUInt<2>(Imm)
5034 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5035 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5036 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5037 }
5038 case Intrinsic::loongarch_lsx_vld:
5039 case Intrinsic::loongarch_lsx_vldrepl_b:
5040 case Intrinsic::loongarch_lasx_xvld:
5041 case Intrinsic::loongarch_lasx_xvldrepl_b:
5042 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5043 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5044 : SDValue();
5045 case Intrinsic::loongarch_lsx_vldrepl_h:
5046 case Intrinsic::loongarch_lasx_xvldrepl_h:
5047 return !isShiftedInt<11, 1>(
5048 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5050 Op, "argument out of range or not a multiple of 2", DAG)
5051 : SDValue();
5052 case Intrinsic::loongarch_lsx_vldrepl_w:
5053 case Intrinsic::loongarch_lasx_xvldrepl_w:
5054 return !isShiftedInt<10, 2>(
5055 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5057 Op, "argument out of range or not a multiple of 4", DAG)
5058 : SDValue();
5059 case Intrinsic::loongarch_lsx_vldrepl_d:
5060 case Intrinsic::loongarch_lasx_xvldrepl_d:
5061 return !isShiftedInt<9, 3>(
5062 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5064 Op, "argument out of range or not a multiple of 8", DAG)
5065 : SDValue();
5066 }
5067}
5068
5069// Helper function that emits error message for intrinsics with void return
5070// value and return the chain.
5072 SelectionDAG &DAG) {
5073
5074 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5075 return Op.getOperand(0);
5076}
5077
5078SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5079 SelectionDAG &DAG) const {
5080 SDLoc DL(Op);
5081 MVT GRLenVT = Subtarget.getGRLenVT();
5082 SDValue Chain = Op.getOperand(0);
5083 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5084 SDValue Op2 = Op.getOperand(2);
5085 const StringRef ErrorMsgOOR = "argument out of range";
5086 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5087 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5088 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5089
5090 switch (IntrinsicEnum) {
5091 default:
5092 // TODO: Add more Intrinsics.
5093 return SDValue();
5094 case Intrinsic::loongarch_cacop_d:
5095 case Intrinsic::loongarch_cacop_w: {
5096 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5097 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5098 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5099 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5100 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5101 unsigned Imm1 = Op2->getAsZExtVal();
5102 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5103 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5104 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5105 return Op;
5106 }
5107 case Intrinsic::loongarch_dbar: {
5108 unsigned Imm = Op2->getAsZExtVal();
5109 return !isUInt<15>(Imm)
5110 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5111 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5112 DAG.getConstant(Imm, DL, GRLenVT));
5113 }
5114 case Intrinsic::loongarch_ibar: {
5115 unsigned Imm = Op2->getAsZExtVal();
5116 return !isUInt<15>(Imm)
5117 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5118 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5119 DAG.getConstant(Imm, DL, GRLenVT));
5120 }
5121 case Intrinsic::loongarch_break: {
5122 unsigned Imm = Op2->getAsZExtVal();
5123 return !isUInt<15>(Imm)
5124 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5125 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5126 DAG.getConstant(Imm, DL, GRLenVT));
5127 }
5128 case Intrinsic::loongarch_movgr2fcsr: {
5129 if (!Subtarget.hasBasicF())
5130 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5131 unsigned Imm = Op2->getAsZExtVal();
5132 return !isUInt<2>(Imm)
5133 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5134 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5135 DAG.getConstant(Imm, DL, GRLenVT),
5136 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5137 Op.getOperand(3)));
5138 }
5139 case Intrinsic::loongarch_syscall: {
5140 unsigned Imm = Op2->getAsZExtVal();
5141 return !isUInt<15>(Imm)
5142 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5143 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5144 DAG.getConstant(Imm, DL, GRLenVT));
5145 }
5146#define IOCSRWR_CASE(NAME, NODE) \
5147 case Intrinsic::loongarch_##NAME: { \
5148 SDValue Op3 = Op.getOperand(3); \
5149 return Subtarget.is64Bit() \
5150 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5151 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5152 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5153 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5154 Op3); \
5155 }
5156 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5157 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5158 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5159#undef IOCSRWR_CASE
5160 case Intrinsic::loongarch_iocsrwr_d: {
5161 return !Subtarget.is64Bit()
5162 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5163 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5164 Op2,
5165 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5166 Op.getOperand(3)));
5167 }
5168#define ASRT_LE_GT_CASE(NAME) \
5169 case Intrinsic::loongarch_##NAME: { \
5170 return !Subtarget.is64Bit() \
5171 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5172 : Op; \
5173 }
5174 ASRT_LE_GT_CASE(asrtle_d)
5175 ASRT_LE_GT_CASE(asrtgt_d)
5176#undef ASRT_LE_GT_CASE
5177 case Intrinsic::loongarch_ldpte_d: {
5178 unsigned Imm = Op.getConstantOperandVal(3);
5179 return !Subtarget.is64Bit()
5180 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5181 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5182 : Op;
5183 }
5184 case Intrinsic::loongarch_lsx_vst:
5185 case Intrinsic::loongarch_lasx_xvst:
5186 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5187 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5188 : SDValue();
5189 case Intrinsic::loongarch_lasx_xvstelm_b:
5190 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5191 !isUInt<5>(Op.getConstantOperandVal(5)))
5192 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5193 : SDValue();
5194 case Intrinsic::loongarch_lsx_vstelm_b:
5195 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5196 !isUInt<4>(Op.getConstantOperandVal(5)))
5197 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5198 : SDValue();
5199 case Intrinsic::loongarch_lasx_xvstelm_h:
5200 return (!isShiftedInt<8, 1>(
5201 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5202 !isUInt<4>(Op.getConstantOperandVal(5)))
5204 Op, "argument out of range or not a multiple of 2", DAG)
5205 : SDValue();
5206 case Intrinsic::loongarch_lsx_vstelm_h:
5207 return (!isShiftedInt<8, 1>(
5208 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5209 !isUInt<3>(Op.getConstantOperandVal(5)))
5211 Op, "argument out of range or not a multiple of 2", DAG)
5212 : SDValue();
5213 case Intrinsic::loongarch_lasx_xvstelm_w:
5214 return (!isShiftedInt<8, 2>(
5215 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5216 !isUInt<3>(Op.getConstantOperandVal(5)))
5218 Op, "argument out of range or not a multiple of 4", DAG)
5219 : SDValue();
5220 case Intrinsic::loongarch_lsx_vstelm_w:
5221 return (!isShiftedInt<8, 2>(
5222 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5223 !isUInt<2>(Op.getConstantOperandVal(5)))
5225 Op, "argument out of range or not a multiple of 4", DAG)
5226 : SDValue();
5227 case Intrinsic::loongarch_lasx_xvstelm_d:
5228 return (!isShiftedInt<8, 3>(
5229 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5230 !isUInt<2>(Op.getConstantOperandVal(5)))
5232 Op, "argument out of range or not a multiple of 8", DAG)
5233 : SDValue();
5234 case Intrinsic::loongarch_lsx_vstelm_d:
5235 return (!isShiftedInt<8, 3>(
5236 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5237 !isUInt<1>(Op.getConstantOperandVal(5)))
5239 Op, "argument out of range or not a multiple of 8", DAG)
5240 : SDValue();
5241 }
5242}
5243
5244SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5245 SelectionDAG &DAG) const {
5246 SDLoc DL(Op);
5247 SDValue Lo = Op.getOperand(0);
5248 SDValue Hi = Op.getOperand(1);
5249 SDValue Shamt = Op.getOperand(2);
5250 EVT VT = Lo.getValueType();
5251
5252 // if Shamt-GRLen < 0: // Shamt < GRLen
5253 // Lo = Lo << Shamt
5254 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5255 // else:
5256 // Lo = 0
5257 // Hi = Lo << (Shamt-GRLen)
5258
5259 SDValue Zero = DAG.getConstant(0, DL, VT);
5260 SDValue One = DAG.getConstant(1, DL, VT);
5261 SDValue MinusGRLen =
5262 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5263 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5264 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5265 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5266
5267 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5268 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5269 SDValue ShiftRightLo =
5270 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5271 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5272 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5273 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5274
5275 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5276
5277 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5278 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5279
5280 SDValue Parts[2] = {Lo, Hi};
5281 return DAG.getMergeValues(Parts, DL);
5282}
5283
5284SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5285 SelectionDAG &DAG,
5286 bool IsSRA) const {
5287 SDLoc DL(Op);
5288 SDValue Lo = Op.getOperand(0);
5289 SDValue Hi = Op.getOperand(1);
5290 SDValue Shamt = Op.getOperand(2);
5291 EVT VT = Lo.getValueType();
5292
5293 // SRA expansion:
5294 // if Shamt-GRLen < 0: // Shamt < GRLen
5295 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5296 // Hi = Hi >>s Shamt
5297 // else:
5298 // Lo = Hi >>s (Shamt-GRLen);
5299 // Hi = Hi >>s (GRLen-1)
5300 //
5301 // SRL expansion:
5302 // if Shamt-GRLen < 0: // Shamt < GRLen
5303 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5304 // Hi = Hi >>u Shamt
5305 // else:
5306 // Lo = Hi >>u (Shamt-GRLen);
5307 // Hi = 0;
5308
5309 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5310
5311 SDValue Zero = DAG.getConstant(0, DL, VT);
5312 SDValue One = DAG.getConstant(1, DL, VT);
5313 SDValue MinusGRLen =
5314 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5315 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5316 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5317 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5318
5319 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5320 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5321 SDValue ShiftLeftHi =
5322 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5323 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5324 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5325 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5326 SDValue HiFalse =
5327 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5328
5329 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5330
5331 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5332 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5333
5334 SDValue Parts[2] = {Lo, Hi};
5335 return DAG.getMergeValues(Parts, DL);
5336}
5337
5338// Returns the opcode of the target-specific SDNode that implements the 32-bit
5339// form of the given Opcode.
5340static unsigned getLoongArchWOpcode(unsigned Opcode) {
5341 switch (Opcode) {
5342 default:
5343 llvm_unreachable("Unexpected opcode");
5344 case ISD::SDIV:
5345 return LoongArchISD::DIV_W;
5346 case ISD::UDIV:
5347 return LoongArchISD::DIV_WU;
5348 case ISD::SREM:
5349 return LoongArchISD::MOD_W;
5350 case ISD::UREM:
5351 return LoongArchISD::MOD_WU;
5352 case ISD::SHL:
5353 return LoongArchISD::SLL_W;
5354 case ISD::SRA:
5355 return LoongArchISD::SRA_W;
5356 case ISD::SRL:
5357 return LoongArchISD::SRL_W;
5358 case ISD::ROTL:
5359 case ISD::ROTR:
5360 return LoongArchISD::ROTR_W;
5361 case ISD::CTTZ:
5362 return LoongArchISD::CTZ_W;
5363 case ISD::CTLZ:
5364 return LoongArchISD::CLZ_W;
5365 }
5366}
5367
5368// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5369// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5370// otherwise be promoted to i64, making it difficult to select the
5371// SLL_W/.../*W later one because the fact the operation was originally of
5372// type i8/i16/i32 is lost.
5374 unsigned ExtOpc = ISD::ANY_EXTEND) {
5375 SDLoc DL(N);
5376 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5377 SDValue NewOp0, NewRes;
5378
5379 switch (NumOp) {
5380 default:
5381 llvm_unreachable("Unexpected NumOp");
5382 case 1: {
5383 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5384 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5385 break;
5386 }
5387 case 2: {
5388 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5389 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5390 if (N->getOpcode() == ISD::ROTL) {
5391 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5392 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5393 }
5394 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5395 break;
5396 }
5397 // TODO:Handle more NumOp.
5398 }
5399
5400 // ReplaceNodeResults requires we maintain the same type for the return
5401 // value.
5402 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5403}
5404
5405// Converts the given 32-bit operation to a i64 operation with signed extension
5406// semantic to reduce the signed extension instructions.
5408 SDLoc DL(N);
5409 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5410 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5411 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5412 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5413 DAG.getValueType(MVT::i32));
5414 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5415}
5416
5417// Helper function that emits error message for intrinsics with/without chain
5418// and return a UNDEF or and the chain as the results.
5421 StringRef ErrorMsg, bool WithChain = true) {
5422 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5423 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5424 if (!WithChain)
5425 return;
5426 Results.push_back(N->getOperand(0));
5427}
5428
5429template <unsigned N>
5430static void
5432 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
5433 unsigned ResOp) {
5434 const StringRef ErrorMsgOOR = "argument out of range";
5435 unsigned Imm = Node->getConstantOperandVal(2);
5436 if (!isUInt<N>(Imm)) {
5438 /*WithChain=*/false);
5439 return;
5440 }
5441 SDLoc DL(Node);
5442 SDValue Vec = Node->getOperand(1);
5443
5444 SDValue PickElt =
5445 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5446 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5448 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5449 PickElt.getValue(0)));
5450}
5451
5454 SelectionDAG &DAG,
5455 const LoongArchSubtarget &Subtarget,
5456 unsigned ResOp) {
5457 SDLoc DL(N);
5458 SDValue Vec = N->getOperand(1);
5459
5460 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5461 Results.push_back(
5462 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5463}
5464
5465static void
5467 SelectionDAG &DAG,
5468 const LoongArchSubtarget &Subtarget) {
5469 switch (N->getConstantOperandVal(0)) {
5470 default:
5471 llvm_unreachable("Unexpected Intrinsic.");
5472 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5473 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5474 LoongArchISD::VPICK_SEXT_ELT);
5475 break;
5476 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5477 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5478 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5479 LoongArchISD::VPICK_SEXT_ELT);
5480 break;
5481 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5482 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5483 LoongArchISD::VPICK_SEXT_ELT);
5484 break;
5485 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5486 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5487 LoongArchISD::VPICK_ZEXT_ELT);
5488 break;
5489 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5490 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5491 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5492 LoongArchISD::VPICK_ZEXT_ELT);
5493 break;
5494 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5495 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5496 LoongArchISD::VPICK_ZEXT_ELT);
5497 break;
5498 case Intrinsic::loongarch_lsx_bz_b:
5499 case Intrinsic::loongarch_lsx_bz_h:
5500 case Intrinsic::loongarch_lsx_bz_w:
5501 case Intrinsic::loongarch_lsx_bz_d:
5502 case Intrinsic::loongarch_lasx_xbz_b:
5503 case Intrinsic::loongarch_lasx_xbz_h:
5504 case Intrinsic::loongarch_lasx_xbz_w:
5505 case Intrinsic::loongarch_lasx_xbz_d:
5506 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5507 LoongArchISD::VALL_ZERO);
5508 break;
5509 case Intrinsic::loongarch_lsx_bz_v:
5510 case Intrinsic::loongarch_lasx_xbz_v:
5511 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5512 LoongArchISD::VANY_ZERO);
5513 break;
5514 case Intrinsic::loongarch_lsx_bnz_b:
5515 case Intrinsic::loongarch_lsx_bnz_h:
5516 case Intrinsic::loongarch_lsx_bnz_w:
5517 case Intrinsic::loongarch_lsx_bnz_d:
5518 case Intrinsic::loongarch_lasx_xbnz_b:
5519 case Intrinsic::loongarch_lasx_xbnz_h:
5520 case Intrinsic::loongarch_lasx_xbnz_w:
5521 case Intrinsic::loongarch_lasx_xbnz_d:
5522 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5523 LoongArchISD::VALL_NONZERO);
5524 break;
5525 case Intrinsic::loongarch_lsx_bnz_v:
5526 case Intrinsic::loongarch_lasx_xbnz_v:
5527 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5528 LoongArchISD::VANY_NONZERO);
5529 break;
5530 }
5531}
5532
5535 SelectionDAG &DAG) {
5536 assert(N->getValueType(0) == MVT::i128 &&
5537 "AtomicCmpSwap on types less than 128 should be legal");
5538 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5539
5540 unsigned Opcode;
5541 switch (MemOp->getMergedOrdering()) {
5545 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5546 break;
5549 Opcode = LoongArch::PseudoCmpXchg128;
5550 break;
5551 default:
5552 llvm_unreachable("Unexpected ordering!");
5553 }
5554
5555 SDLoc DL(N);
5556 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5557 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5558 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5559 NewVal.first, NewVal.second, N->getOperand(0)};
5560
5561 SDNode *CmpSwap = DAG.getMachineNode(
5562 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5563 Ops);
5564 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5565 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5566 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5567 Results.push_back(SDValue(CmpSwap, 3));
5568}
5569
5572 SDLoc DL(N);
5573 EVT VT = N->getValueType(0);
5574 switch (N->getOpcode()) {
5575 default:
5576 llvm_unreachable("Don't know how to legalize this operation");
5577 case ISD::ADD:
5578 case ISD::SUB:
5579 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5580 "Unexpected custom legalisation");
5581 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5582 break;
5583 case ISD::SDIV:
5584 case ISD::UDIV:
5585 case ISD::SREM:
5586 case ISD::UREM:
5587 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5588 "Unexpected custom legalisation");
5589 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5590 Subtarget.hasDiv32() && VT == MVT::i32
5592 : ISD::SIGN_EXTEND));
5593 break;
5594 case ISD::SHL:
5595 case ISD::SRA:
5596 case ISD::SRL:
5597 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5598 "Unexpected custom legalisation");
5599 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5600 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5601 break;
5602 }
5603 break;
5604 case ISD::ROTL:
5605 case ISD::ROTR:
5606 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5607 "Unexpected custom legalisation");
5608 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5609 break;
5610 case ISD::LOAD: {
5611 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5612 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5613 // cast since type legalization will try to use an i64 load.
5614 MVT VT = N->getSimpleValueType(0);
5615 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5616 "Unexpected custom legalisation");
5618 "Unexpected type action!");
5619 if (!ISD::isNON_EXTLoad(N))
5620 return;
5621 auto *Ld = cast<LoadSDNode>(N);
5622 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5623 Ld->getPointerInfo(), Ld->getBaseAlign(),
5624 Ld->getMemOperand()->getFlags());
5625 SDValue Chain = Res.getValue(1);
5626 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5627 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5628 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5629 Res = DAG.getBitcast(WideVT, Res);
5630 Results.push_back(Res);
5631 Results.push_back(Chain);
5632 break;
5633 }
5634 case ISD::FP_TO_SINT: {
5635 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5636 "Unexpected custom legalisation");
5637 SDValue Src = N->getOperand(0);
5638 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5639 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5641 if (!isTypeLegal(Src.getValueType()))
5642 return;
5643 if (Src.getValueType() == MVT::f16)
5644 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5645 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5646 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5647 return;
5648 }
5649 // If the FP type needs to be softened, emit a library call using the 'si'
5650 // version. If we left it to default legalization we'd end up with 'di'.
5651 RTLIB::Libcall LC;
5652 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5653 MakeLibCallOptions CallOptions;
5654 EVT OpVT = Src.getValueType();
5655 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5656 SDValue Chain = SDValue();
5657 SDValue Result;
5658 std::tie(Result, Chain) =
5659 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5660 Results.push_back(Result);
5661 break;
5662 }
5663 case ISD::BITCAST: {
5664 SDValue Src = N->getOperand(0);
5665 EVT SrcVT = Src.getValueType();
5666 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5667 Subtarget.hasBasicF()) {
5668 SDValue Dst =
5669 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5670 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5671 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5672 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5673 DAG.getVTList(MVT::i32, MVT::i32), Src);
5674 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5675 NewReg.getValue(0), NewReg.getValue(1));
5676 Results.push_back(RetReg);
5677 }
5678 break;
5679 }
5680 case ISD::FP_TO_UINT: {
5681 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5682 "Unexpected custom legalisation");
5683 auto &TLI = DAG.getTargetLoweringInfo();
5684 SDValue Tmp1, Tmp2;
5685 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5686 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
5687 break;
5688 }
5689 case ISD::FP_ROUND: {
5690 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5691 "Unexpected custom legalisation");
5692 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
5693 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
5694 // a target-specific LoongArchISD::VFCVT to optimize it.
5695 SDValue Op0 = N->getOperand(0);
5696 EVT OpVT = Op0.getValueType();
5697 if (OpVT == MVT::v2f64) {
5698 SDValue Undef = DAG.getUNDEF(OpVT);
5699 SDValue Dst =
5700 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
5701 Results.push_back(Dst);
5702 }
5703 break;
5704 }
5705 case ISD::BSWAP: {
5706 SDValue Src = N->getOperand(0);
5707 assert((VT == MVT::i16 || VT == MVT::i32) &&
5708 "Unexpected custom legalization");
5709 MVT GRLenVT = Subtarget.getGRLenVT();
5710 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5711 SDValue Tmp;
5712 switch (VT.getSizeInBits()) {
5713 default:
5714 llvm_unreachable("Unexpected operand width");
5715 case 16:
5716 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
5717 break;
5718 case 32:
5719 // Only LA64 will get to here due to the size mismatch between VT and
5720 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
5721 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
5722 break;
5723 }
5724 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5725 break;
5726 }
5727 case ISD::BITREVERSE: {
5728 SDValue Src = N->getOperand(0);
5729 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
5730 "Unexpected custom legalization");
5731 MVT GRLenVT = Subtarget.getGRLenVT();
5732 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5733 SDValue Tmp;
5734 switch (VT.getSizeInBits()) {
5735 default:
5736 llvm_unreachable("Unexpected operand width");
5737 case 8:
5738 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
5739 break;
5740 case 32:
5741 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
5742 break;
5743 }
5744 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5745 break;
5746 }
5747 case ISD::CTLZ:
5748 case ISD::CTTZ: {
5749 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5750 "Unexpected custom legalisation");
5751 Results.push_back(customLegalizeToWOp(N, DAG, 1));
5752 break;
5753 }
5755 SDValue Chain = N->getOperand(0);
5756 SDValue Op2 = N->getOperand(2);
5757 MVT GRLenVT = Subtarget.getGRLenVT();
5758 const StringRef ErrorMsgOOR = "argument out of range";
5759 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5760 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5761
5762 switch (N->getConstantOperandVal(1)) {
5763 default:
5764 llvm_unreachable("Unexpected Intrinsic.");
5765 case Intrinsic::loongarch_movfcsr2gr: {
5766 if (!Subtarget.hasBasicF()) {
5767 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
5768 return;
5769 }
5770 unsigned Imm = Op2->getAsZExtVal();
5771 if (!isUInt<2>(Imm)) {
5772 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5773 return;
5774 }
5775 SDValue MOVFCSR2GRResults = DAG.getNode(
5776 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
5777 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5778 Results.push_back(
5779 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
5780 Results.push_back(MOVFCSR2GRResults.getValue(1));
5781 break;
5782 }
5783#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
5784 case Intrinsic::loongarch_##NAME: { \
5785 SDValue NODE = DAG.getNode( \
5786 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5787 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5788 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5789 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5790 Results.push_back(NODE.getValue(1)); \
5791 break; \
5792 }
5793 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
5794 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
5795 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
5796 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
5797 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
5798 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
5799#undef CRC_CASE_EXT_BINARYOP
5800
5801#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
5802 case Intrinsic::loongarch_##NAME: { \
5803 SDValue NODE = DAG.getNode( \
5804 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5805 {Chain, Op2, \
5806 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5807 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5808 Results.push_back(NODE.getValue(1)); \
5809 break; \
5810 }
5811 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
5812 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
5813#undef CRC_CASE_EXT_UNARYOP
5814#define CSR_CASE(ID) \
5815 case Intrinsic::loongarch_##ID: { \
5816 if (!Subtarget.is64Bit()) \
5817 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
5818 break; \
5819 }
5820 CSR_CASE(csrrd_d);
5821 CSR_CASE(csrwr_d);
5822 CSR_CASE(csrxchg_d);
5823 CSR_CASE(iocsrrd_d);
5824#undef CSR_CASE
5825 case Intrinsic::loongarch_csrrd_w: {
5826 unsigned Imm = Op2->getAsZExtVal();
5827 if (!isUInt<14>(Imm)) {
5828 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5829 return;
5830 }
5831 SDValue CSRRDResults =
5832 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5833 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5834 Results.push_back(
5835 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
5836 Results.push_back(CSRRDResults.getValue(1));
5837 break;
5838 }
5839 case Intrinsic::loongarch_csrwr_w: {
5840 unsigned Imm = N->getConstantOperandVal(3);
5841 if (!isUInt<14>(Imm)) {
5842 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5843 return;
5844 }
5845 SDValue CSRWRResults =
5846 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5847 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5848 DAG.getConstant(Imm, DL, GRLenVT)});
5849 Results.push_back(
5850 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
5851 Results.push_back(CSRWRResults.getValue(1));
5852 break;
5853 }
5854 case Intrinsic::loongarch_csrxchg_w: {
5855 unsigned Imm = N->getConstantOperandVal(4);
5856 if (!isUInt<14>(Imm)) {
5857 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5858 return;
5859 }
5860 SDValue CSRXCHGResults = DAG.getNode(
5861 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5862 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5863 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
5864 DAG.getConstant(Imm, DL, GRLenVT)});
5865 Results.push_back(
5866 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
5867 Results.push_back(CSRXCHGResults.getValue(1));
5868 break;
5869 }
5870#define IOCSRRD_CASE(NAME, NODE) \
5871 case Intrinsic::loongarch_##NAME: { \
5872 SDValue IOCSRRDResults = \
5873 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5874 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
5875 Results.push_back( \
5876 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
5877 Results.push_back(IOCSRRDResults.getValue(1)); \
5878 break; \
5879 }
5880 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5881 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5882 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5883#undef IOCSRRD_CASE
5884 case Intrinsic::loongarch_cpucfg: {
5885 SDValue CPUCFGResults =
5886 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5887 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
5888 Results.push_back(
5889 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
5890 Results.push_back(CPUCFGResults.getValue(1));
5891 break;
5892 }
5893 case Intrinsic::loongarch_lddir_d: {
5894 if (!Subtarget.is64Bit()) {
5895 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
5896 return;
5897 }
5898 break;
5899 }
5900 }
5901 break;
5902 }
5903 case ISD::READ_REGISTER: {
5904 if (Subtarget.is64Bit())
5905 DAG.getContext()->emitError(
5906 "On LA64, only 64-bit registers can be read.");
5907 else
5908 DAG.getContext()->emitError(
5909 "On LA32, only 32-bit registers can be read.");
5910 Results.push_back(DAG.getUNDEF(VT));
5911 Results.push_back(N->getOperand(0));
5912 break;
5913 }
5915 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
5916 break;
5917 }
5918 case ISD::LROUND: {
5919 SDValue Op0 = N->getOperand(0);
5920 EVT OpVT = Op0.getValueType();
5921 RTLIB::Libcall LC =
5922 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
5923 MakeLibCallOptions CallOptions;
5924 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
5925 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
5926 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
5927 Results.push_back(Result);
5928 break;
5929 }
5930 case ISD::ATOMIC_CMP_SWAP: {
5932 break;
5933 }
5934 case ISD::TRUNCATE: {
5935 MVT VT = N->getSimpleValueType(0);
5936 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
5937 return;
5938
5939 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
5940 SDValue In = N->getOperand(0);
5941 EVT InVT = In.getValueType();
5942 EVT InEltVT = InVT.getVectorElementType();
5943 EVT EltVT = VT.getVectorElementType();
5944 unsigned MinElts = VT.getVectorNumElements();
5945 unsigned WidenNumElts = WidenVT.getVectorNumElements();
5946 unsigned InBits = InVT.getSizeInBits();
5947
5948 // v8i64 -> (v8i32) -> v8i8
5949 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
5950 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
5951 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
5952 InBits = 256;
5953 }
5954
5955 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
5956 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
5957 WidenVT.is128BitVector()) {
5958 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
5959 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
5960 InBits = 128;
5961 InEltVT = InVT.getVectorElementType();
5962 }
5963
5964 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
5965 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
5966 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
5967 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
5968 for (unsigned I = 0; I < MinElts; ++I)
5969 TruncMask[I] = Scale * I;
5970
5971 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
5972 MVT SVT = In.getSimpleValueType().getScalarType();
5973 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
5974 SDValue WidenIn =
5975 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
5976 DAG.getVectorIdxConstant(0, DL));
5977 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
5978 "Illegal vector type in truncation");
5979 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
5980 Results.push_back(
5981 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
5982 return;
5983 }
5984 }
5985
5986 break;
5987 }
5988 case ISD::SIGN_EXTEND: {
5989 // LASX has native VEXT2XV_* for sign extension.
5990 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
5991 return;
5992
5993 EVT DstVT = N->getValueType(0);
5994 SDValue Src = N->getOperand(0);
5995 MVT SrcVT = Src.getSimpleValueType();
5996
5997 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
5998 unsigned DstEltBits = DstVT.getScalarSizeInBits();
5999 unsigned NumElts = DstVT.getVectorNumElements();
6000
6001 if (SrcVT.getSizeInBits() > 128)
6002 return;
6003
6004 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6005 return;
6006
6007 // Legalize and extend the src to 128-bit first.
6008 if (SrcVT.getSizeInBits() < 128) {
6009 unsigned WidenSrcElts = 128 / SrcEltBits;
6010 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6011 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6012 DAG.getUNDEF(WidenSrcVT), Src,
6013 DAG.getVectorIdxConstant(0, DL));
6014 SrcVT = WidenSrcVT;
6015
6016 unsigned FirstStageEltBits = 128 / NumElts;
6017 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6018 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6019 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6020 SrcVT = FirstStageVT;
6021 SrcEltBits = FirstStageEltBits;
6022 }
6023
6025 Blocks.push_back(Src);
6026
6027 // Sign-extend the src by using SLTI + VILVL + VILVH recursively.
6028 while (SrcEltBits < DstEltBits) {
6029 unsigned NextEltBits = SrcEltBits * 2;
6030 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6031 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6032 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6033 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6034
6035 SmallVector<SDValue, 8> NextBlocks;
6036 NextBlocks.reserve(Blocks.size() * 2);
6037 for (SDValue Block : Blocks) {
6038 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
6039 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Block, Zero,
6040 DAG.getCondCode(ISD::SETLT));
6041 SDValue LoInterleaved =
6042 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Block);
6043 SDValue HiInterleaved =
6044 DAG.getNode(LoongArchISD::VILVH, DL, SrcVT, Mask, Block);
6045
6046 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, LoInterleaved));
6047 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, HiInterleaved));
6048 }
6049
6050 Blocks = std::move(NextBlocks);
6051 SrcVT = NextBlockVT;
6052 SrcEltBits = NextEltBits;
6053 }
6054
6055 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6056 break;
6057 }
6058 case ISD::FP_EXTEND:
6059 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6060 // no target-specific lowering is required. Leave it unchanged and rely on
6061 // the default type legalization.
6062 break;
6063 }
6064}
6065
6066/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6068 SelectionDAG &DAG) {
6069 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6070
6071 MVT VT = N->getSimpleValueType(0);
6072 if (!VT.is128BitVector() && !VT.is256BitVector())
6073 return SDValue();
6074
6075 SDValue X, Y;
6076 SDValue N0 = N->getOperand(0);
6077 SDValue N1 = N->getOperand(1);
6078
6079 if (SDValue Not = isNOT(N0, DAG)) {
6080 X = Not;
6081 Y = N1;
6082 } else if (SDValue Not = isNOT(N1, DAG)) {
6083 X = Not;
6084 Y = N0;
6085 } else
6086 return SDValue();
6087
6088 X = DAG.getBitcast(VT, X);
6089 Y = DAG.getBitcast(VT, Y);
6090 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6091}
6092
6093static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6094 unsigned MinSizeInBits) {
6097
6098 if (!Node)
6099 return false;
6100
6101 APInt SplatUndef;
6102 unsigned SplatBitSize;
6103 bool HasAnyUndefs;
6104
6105 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6106 HasAnyUndefs, MinSizeInBits,
6107 /*IsBigEndian=*/false);
6108}
6109
6110static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6111 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6112 if (!BV)
6113 return SDValue();
6114
6115 SDValue Src;
6116 int Start = -1;
6117
6118 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6119 SDValue Op = BV->getOperand(i);
6120 if (Op.isUndef())
6121 continue;
6122 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6123 return SDValue();
6124
6125 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6126 if (!IdxC)
6127 return SDValue();
6128
6129 unsigned EltIdx = IdxC->getZExtValue();
6130 if (Start < 0)
6131 Start = (int)EltIdx - (int)(i * 2);
6132 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6133 return SDValue();
6134
6135 SDValue CurSrc = Op.getOperand(0);
6136 if (!Src)
6137 Src = CurSrc;
6138 else if (Src != CurSrc)
6139 return SDValue();
6140 }
6141
6142 if (!Src || Start < 0)
6143 return SDValue();
6144
6145 StartIndex = (unsigned)Start;
6146 return Src;
6147}
6148
6149static SDValue
6151 const LoongArchSubtarget &Subtarget) {
6152 if (!Subtarget.hasExtLSX())
6153 return SDValue();
6154
6155 unsigned Opc = N->getOpcode();
6156 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6157
6158 EVT VT = N->getValueType(0);
6159 SDLoc DL(N);
6160
6161 SDValue LHS = N->getOperand(0);
6162 SDValue RHS = N->getOperand(1);
6163
6164 bool isSigned;
6165 unsigned ExtOpc = LHS.getOpcode();
6166 if (ExtOpc == ISD::SIGN_EXTEND)
6167 isSigned = true;
6168 else if (ExtOpc == ISD::ZERO_EXTEND)
6169 isSigned = false;
6170 else
6171 return SDValue();
6172
6173 if (ExtOpc != RHS.getOpcode())
6174 return SDValue();
6175
6176 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6177 return SDValue();
6178
6179 unsigned OddIdx, EvenIdx;
6180 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6181 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6182
6183 if (!LHSVec || !RHSVec)
6184 return SDValue();
6185 if (OddIdx != 1 || EvenIdx != 0)
6186 return SDValue();
6187 if (LHSVec.getValueType() != RHSVec.getValueType())
6188 return SDValue();
6189
6190 EVT SrcVT = LHSVec.getValueType();
6191 EVT SrcEltVT = SrcVT.getVectorElementType();
6192 EVT DstEltVT = VT.getVectorElementType();
6193 auto &TLI = DAG.getTargetLoweringInfo();
6194
6195 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6196 return SDValue();
6197 if (!SrcVT.isVector() || !VT.isVector())
6198 return SDValue();
6199 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6200 return SDValue();
6201 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6202 return SDValue();
6203 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6204 return SDValue();
6205
6206 unsigned TargetOpc;
6207 if (Opc == ISD::ADD)
6208 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6209 else
6210 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6211
6212 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6213}
6214
6217 const LoongArchSubtarget &Subtarget) {
6218 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6219 return V;
6220
6221 if (DCI.isBeforeLegalizeOps())
6222 return SDValue();
6223
6224 EVT VT = N->getValueType(0);
6225 if (!VT.isVector())
6226 return SDValue();
6227
6228 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6229 return SDValue();
6230
6231 EVT EltVT = VT.getVectorElementType();
6232 if (!EltVT.isInteger())
6233 return SDValue();
6234
6235 // match:
6236 //
6237 // add
6238 // (and
6239 // (srl X, shift-1) / X
6240 // 1)
6241 // (srl/sra X, shift)
6242
6243 SDValue Add0 = N->getOperand(0);
6244 SDValue Add1 = N->getOperand(1);
6245 SDValue And;
6246 SDValue Shr;
6247
6248 if (Add0.getOpcode() == ISD::AND) {
6249 And = Add0;
6250 Shr = Add1;
6251 } else if (Add1.getOpcode() == ISD::AND) {
6252 And = Add1;
6253 Shr = Add0;
6254 } else {
6255 return SDValue();
6256 }
6257
6258 // match:
6259 //
6260 // srl/sra X, shift
6261
6262 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6263 return SDValue();
6264
6265 SDValue X = Shr.getOperand(0);
6266 SDValue Shift = Shr.getOperand(1);
6267 APInt ShiftVal;
6268
6269 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6270 return SDValue();
6271
6272 if (ShiftVal == 0)
6273 return SDValue();
6274
6275 // match:
6276 //
6277 // and
6278 // (srl X, shift-1) / X
6279 // 1
6280
6281 SDValue One = And.getOperand(1);
6282 APInt SplatVal;
6283
6284 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6285 return SDValue();
6286
6287 if (SplatVal != 1)
6288 return SDValue();
6289
6290 if (And.getOperand(0) == X) {
6291 // match:
6292 //
6293 // shift == 1
6294
6295 if (ShiftVal != 1)
6296 return SDValue();
6297 } else {
6298 // match:
6299 //
6300 // srl X, shift-1
6301
6302 SDValue Srl = And.getOperand(0);
6303
6304 if (Srl.getOpcode() != ISD::SRL)
6305 return SDValue();
6306
6307 if (Srl.getOperand(0) != X)
6308 return SDValue();
6309
6310 // match:
6311 //
6312 // shift-1
6313
6314 SDValue ShiftMinus1 = Srl.getOperand(1);
6315
6316 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6317 return SDValue();
6318
6319 if (ShiftVal != (SplatVal + 1))
6320 return SDValue();
6321 }
6322
6323 // We matched a rounded right shift pattern and can lower it
6324 // to a single vector rounded shift instruction.
6325
6326 SDLoc DL(N);
6327 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6328 : LoongArchISD::VSRAR,
6329 DL, VT, X, Shift);
6330}
6331
6334 const LoongArchSubtarget &Subtarget) {
6335 if (DCI.isBeforeLegalizeOps())
6336 return SDValue();
6337
6338 SDValue FirstOperand = N->getOperand(0);
6339 SDValue SecondOperand = N->getOperand(1);
6340 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6341 EVT ValTy = N->getValueType(0);
6342 SDLoc DL(N);
6343 uint64_t lsb, msb;
6344 unsigned SMIdx, SMLen;
6345 ConstantSDNode *CN;
6346 SDValue NewOperand;
6347 MVT GRLenVT = Subtarget.getGRLenVT();
6348
6349 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6350 return R;
6351
6352 // BSTRPICK requires the 32S feature.
6353 if (!Subtarget.has32S())
6354 return SDValue();
6355
6356 // Op's second operand must be a shifted mask.
6357 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6358 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6359 return SDValue();
6360
6361 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6362 // Pattern match BSTRPICK.
6363 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6364 // => BSTRPICK $dst, $src, msb, lsb
6365 // where msb = lsb + len - 1
6366
6367 // The second operand of the shift must be an immediate.
6368 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6369 return SDValue();
6370
6371 lsb = CN->getZExtValue();
6372
6373 // Return if the shifted mask does not start at bit 0 or the sum of its
6374 // length and lsb exceeds the word's size.
6375 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6376 return SDValue();
6377
6378 NewOperand = FirstOperand.getOperand(0);
6379 } else {
6380 // Pattern match BSTRPICK.
6381 // $dst = and $src, (2**len- 1) , if len > 12
6382 // => BSTRPICK $dst, $src, msb, lsb
6383 // where lsb = 0 and msb = len - 1
6384
6385 // If the mask is <= 0xfff, andi can be used instead.
6386 if (CN->getZExtValue() <= 0xfff)
6387 return SDValue();
6388
6389 // Return if the MSB exceeds.
6390 if (SMIdx + SMLen > ValTy.getSizeInBits())
6391 return SDValue();
6392
6393 if (SMIdx > 0) {
6394 // Omit if the constant has more than 2 uses. This a conservative
6395 // decision. Whether it is a win depends on the HW microarchitecture.
6396 // However it should always be better for 1 and 2 uses.
6397 if (CN->use_size() > 2)
6398 return SDValue();
6399 // Return if the constant can be composed by a single LU12I.W.
6400 if ((CN->getZExtValue() & 0xfff) == 0)
6401 return SDValue();
6402 // Return if the constand can be composed by a single ADDI with
6403 // the zero register.
6404 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6405 return SDValue();
6406 }
6407
6408 lsb = SMIdx;
6409 NewOperand = FirstOperand;
6410 }
6411
6412 msb = lsb + SMLen - 1;
6413 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6414 DAG.getConstant(msb, DL, GRLenVT),
6415 DAG.getConstant(lsb, DL, GRLenVT));
6416 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6417 return NR0;
6418 // Try to optimize to
6419 // bstrpick $Rd, $Rs, msb, lsb
6420 // slli $Rd, $Rd, lsb
6421 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6422 DAG.getConstant(lsb, DL, GRLenVT));
6423}
6424
6425// Return the original source vector if N consists of the half
6426// of each 128-bit lane.
6429
6430 EVT DstVT = N.getValueType();
6431 if (!DstVT.isVector())
6432 return SDValue();
6433
6434 unsigned NumElts = DstVT.getVectorNumElements();
6435
6436 // LSX canonical form:
6437 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6438 SDValue Src = N.getOperand(0);
6439 EVT SrcVT = Src.getValueType();
6440
6441 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6442 return SDValue();
6443 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6444 return SDValue();
6445 if (SrcVT.getVectorNumElements() != NumElts * 2)
6446 return SDValue();
6447 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6448 return SDValue();
6449
6450 return Src;
6451 }
6452
6453 // LASX canonical form:
6454 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6455 if (!BV)
6456 return SDValue();
6457
6458 if (NumElts % 2 != 0)
6459 return SDValue();
6460
6461 SDValue Src;
6462 EVT SrcVT;
6463
6464 for (unsigned I = 0; I != NumElts; ++I) {
6465 SDValue Elt = BV->getOperand(I);
6466 if (Elt.isUndef())
6467 continue;
6469 return SDValue();
6470
6471 SDValue ThisSrc = Elt.getOperand(0);
6472 SDValue Idx = Elt.getOperand(1);
6473 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6474 if (!CI)
6475 return SDValue();
6476
6477 if (!Src) {
6478 Src = ThisSrc;
6479 SrcVT = Src.getValueType();
6480 if (!SrcVT.isVector())
6481 return SDValue();
6482
6483 if (!SrcVT.is256BitVector())
6484 return SDValue();
6485 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6486 return SDValue();
6487 if (SrcVT.getVectorNumElements() != NumElts * 2)
6488 return SDValue();
6489 } else if (ThisSrc != Src) {
6490 return SDValue();
6491 }
6492
6493 unsigned Half = NumElts / 2;
6494 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6495 ExpectedIdx += isLow ? 0 : Half;
6496
6497 if (CI->getZExtValue() != ExpectedIdx)
6498 return SDValue();
6499 }
6500
6501 return Src;
6502}
6503
6506 const LoongArchSubtarget &Subtarget) {
6507 if (!Subtarget.hasExtLSX())
6508 return SDValue();
6509
6510 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6511
6512 EVT VT = N->getValueType(0);
6513 SDLoc DL(N);
6514
6515 SDValue LHS = N->getOperand(0);
6516 SDValue RHS = N->getOperand(1);
6517
6518 bool isSigned;
6519 unsigned ExtOpc = LHS.getOpcode();
6520 if (ExtOpc == ISD::SIGN_EXTEND)
6521 isSigned = true;
6522 else if (ExtOpc == ISD::ZERO_EXTEND)
6523 isSigned = false;
6524 else
6525 return SDValue();
6526
6527 if (!LHS.hasOneUse())
6528 return SDValue();
6529
6530 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6531 if (!Vec)
6532 return SDValue();
6533
6534 EVT SrcVT = Vec.getValueType();
6535 EVT SrcEltVT = SrcVT.getVectorElementType();
6536 EVT DstEltVT = VT.getVectorElementType();
6537
6538 if (!SrcVT.isVector() || !VT.isVector())
6539 return SDValue();
6540 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6541 return SDValue();
6542 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6543 return SDValue();
6544 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6545 return SDValue();
6546
6547 APInt Imm;
6548 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6549 return SDValue();
6550 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6551 return SDValue();
6552
6553 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6554 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6555 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6556}
6557
6560 const LoongArchSubtarget &Subtarget) {
6561 // BSTRPICK requires the 32S feature.
6562 if (!Subtarget.has32S())
6563 return SDValue();
6564
6565 if (DCI.isBeforeLegalizeOps())
6566 return SDValue();
6567
6568 // $dst = srl (and $src, Mask), Shamt
6569 // =>
6570 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6571 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6572 //
6573
6574 SDValue FirstOperand = N->getOperand(0);
6575 ConstantSDNode *CN;
6576 EVT ValTy = N->getValueType(0);
6577 SDLoc DL(N);
6578 MVT GRLenVT = Subtarget.getGRLenVT();
6579 unsigned MaskIdx, MaskLen;
6580 uint64_t Shamt;
6581
6582 // The first operand must be an AND and the second operand of the AND must be
6583 // a shifted mask.
6584 if (FirstOperand.getOpcode() != ISD::AND ||
6585 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6586 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6587 return SDValue();
6588
6589 // The second operand (shift amount) must be an immediate.
6590 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6591 return SDValue();
6592
6593 Shamt = CN->getZExtValue();
6594 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6595 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6596 FirstOperand->getOperand(0),
6597 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6598 DAG.getConstant(Shamt, DL, GRLenVT));
6599
6600 return SDValue();
6601}
6602
6605 const LoongArchSubtarget &Subtarget) {
6606 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6607 return V;
6608
6609 return SDValue();
6610}
6611
6612// Helper to peek through bitops/trunc/setcc to determine size of source vector.
6613// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
6614static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
6615 unsigned Depth) {
6616 // Limit recursion.
6618 return false;
6619 switch (Src.getOpcode()) {
6620 case ISD::SETCC:
6621 case ISD::TRUNCATE:
6622 return Src.getOperand(0).getValueSizeInBits() == Size;
6623 case ISD::FREEZE:
6624 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
6625 case ISD::AND:
6626 case ISD::XOR:
6627 case ISD::OR:
6628 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
6629 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
6630 case ISD::SELECT:
6631 case ISD::VSELECT:
6632 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
6633 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
6634 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
6635 case ISD::BUILD_VECTOR:
6636 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
6637 ISD::isBuildVectorAllOnes(Src.getNode());
6638 }
6639 return false;
6640}
6641
6642// Helper to push sign extension of vXi1 SETCC result through bitops.
6644 SDValue Src, const SDLoc &DL) {
6645 switch (Src.getOpcode()) {
6646 case ISD::SETCC:
6647 case ISD::FREEZE:
6648 case ISD::TRUNCATE:
6649 case ISD::BUILD_VECTOR:
6650 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6651 case ISD::AND:
6652 case ISD::XOR:
6653 case ISD::OR:
6654 return DAG.getNode(
6655 Src.getOpcode(), DL, SExtVT,
6656 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
6657 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
6658 case ISD::SELECT:
6659 case ISD::VSELECT:
6660 return DAG.getSelect(
6661 DL, SExtVT, Src.getOperand(0),
6662 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
6663 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
6664 }
6665 llvm_unreachable("Unexpected node type for vXi1 sign extension");
6666}
6667
6668static SDValue
6671 const LoongArchSubtarget &Subtarget) {
6672 SDLoc DL(N);
6673 EVT VT = N->getValueType(0);
6674 SDValue Src = N->getOperand(0);
6675 EVT SrcVT = Src.getValueType();
6676
6677 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
6678 return SDValue();
6679
6680 bool UseLASX;
6681 unsigned Opc = ISD::DELETED_NODE;
6682 EVT CmpVT = Src.getOperand(0).getValueType();
6683 EVT EltVT = CmpVT.getVectorElementType();
6684
6685 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
6686 UseLASX = false;
6687 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
6688 CmpVT.getSizeInBits() == 256)
6689 UseLASX = true;
6690 else
6691 return SDValue();
6692
6693 SDValue SrcN1 = Src.getOperand(1);
6694 switch (cast<CondCodeSDNode>(Src.getOperand(2))->get()) {
6695 default:
6696 break;
6697 case ISD::SETEQ:
6698 // x == 0 => not (vmsknez.b x)
6699 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6700 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
6701 break;
6702 case ISD::SETGT:
6703 // x > -1 => vmskgez.b x
6704 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
6705 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6706 break;
6707 case ISD::SETGE:
6708 // x >= 0 => vmskgez.b x
6709 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6710 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6711 break;
6712 case ISD::SETLT:
6713 // x < 0 => vmskltz.{b,h,w,d} x
6714 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
6715 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6716 EltVT == MVT::i64))
6717 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6718 break;
6719 case ISD::SETLE:
6720 // x <= -1 => vmskltz.{b,h,w,d} x
6721 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
6722 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6723 EltVT == MVT::i64))
6724 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6725 break;
6726 case ISD::SETNE:
6727 // x != 0 => vmsknez.b x
6728 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6729 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
6730 break;
6731 }
6732
6733 if (Opc == ISD::DELETED_NODE)
6734 return SDValue();
6735
6736 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
6738 V = DAG.getZExtOrTrunc(V, DL, T);
6739 return DAG.getBitcast(VT, V);
6740}
6741
6744 const LoongArchSubtarget &Subtarget) {
6745 SDLoc DL(N);
6746 EVT VT = N->getValueType(0);
6747 SDValue Src = N->getOperand(0);
6748 EVT SrcVT = Src.getValueType();
6749 MVT GRLenVT = Subtarget.getGRLenVT();
6750
6751 if (!DCI.isBeforeLegalizeOps())
6752 return SDValue();
6753
6754 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
6755 return SDValue();
6756
6757 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
6758 SDValue Res = performSETCC_BITCASTCombine(N, DAG, DCI, Subtarget);
6759 if (Res)
6760 return Res;
6761
6762 // Generate vXi1 using [X]VMSKLTZ
6763 MVT SExtVT;
6764 unsigned Opc;
6765 bool UseLASX = false;
6766 bool PropagateSExt = false;
6767
6768 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
6769 EVT CmpVT = Src.getOperand(0).getValueType();
6770 if (CmpVT.getSizeInBits() > 256)
6771 return SDValue();
6772 }
6773
6774 switch (SrcVT.getSimpleVT().SimpleTy) {
6775 default:
6776 return SDValue();
6777 case MVT::v2i1:
6778 SExtVT = MVT::v2i64;
6779 break;
6780 case MVT::v4i1:
6781 SExtVT = MVT::v4i32;
6782 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6783 SExtVT = MVT::v4i64;
6784 UseLASX = true;
6785 PropagateSExt = true;
6786 }
6787 break;
6788 case MVT::v8i1:
6789 SExtVT = MVT::v8i16;
6790 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6791 SExtVT = MVT::v8i32;
6792 UseLASX = true;
6793 PropagateSExt = true;
6794 }
6795 break;
6796 case MVT::v16i1:
6797 SExtVT = MVT::v16i8;
6798 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6799 SExtVT = MVT::v16i16;
6800 UseLASX = true;
6801 PropagateSExt = true;
6802 }
6803 break;
6804 case MVT::v32i1:
6805 SExtVT = MVT::v32i8;
6806 UseLASX = true;
6807 break;
6808 };
6809 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
6810 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6811
6812 SDValue V;
6813 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
6814 if (Src.getSimpleValueType() == MVT::v32i8) {
6815 SDValue Lo, Hi;
6816 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
6817 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
6818 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
6819 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
6820 DAG.getShiftAmountConstant(16, GRLenVT, DL));
6821 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
6822 } else if (UseLASX) {
6823 return SDValue();
6824 }
6825 }
6826
6827 if (!V) {
6828 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6829 V = DAG.getNode(Opc, DL, GRLenVT, Src);
6830 }
6831
6833 V = DAG.getZExtOrTrunc(V, DL, T);
6834 return DAG.getBitcast(VT, V);
6835}
6836
6839 const LoongArchSubtarget &Subtarget) {
6840 MVT GRLenVT = Subtarget.getGRLenVT();
6841 EVT ValTy = N->getValueType(0);
6842 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
6843 ConstantSDNode *CN0, *CN1;
6844 SDLoc DL(N);
6845 unsigned ValBits = ValTy.getSizeInBits();
6846 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
6847 unsigned Shamt;
6848 bool SwapAndRetried = false;
6849
6850 // BSTRPICK requires the 32S feature.
6851 if (!Subtarget.has32S())
6852 return SDValue();
6853
6854 if (DCI.isBeforeLegalizeOps())
6855 return SDValue();
6856
6857 if (ValBits != 32 && ValBits != 64)
6858 return SDValue();
6859
6860Retry:
6861 // 1st pattern to match BSTRINS:
6862 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
6863 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
6864 // =>
6865 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6866 if (N0.getOpcode() == ISD::AND &&
6867 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6868 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6869 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
6870 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6871 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6872 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
6873 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6874 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6875 (MaskIdx0 + MaskLen0 <= ValBits)) {
6876 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
6877 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6878 N1.getOperand(0).getOperand(0),
6879 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6880 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6881 }
6882
6883 // 2nd pattern to match BSTRINS:
6884 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
6885 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
6886 // =>
6887 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6888 if (N0.getOpcode() == ISD::AND &&
6889 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6890 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6891 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
6892 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6893 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6894 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6895 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6896 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
6897 (MaskIdx0 + MaskLen0 <= ValBits)) {
6898 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
6899 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6900 N1.getOperand(0).getOperand(0),
6901 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6902 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6903 }
6904
6905 // 3rd pattern to match BSTRINS:
6906 // R = or (and X, mask0), (and Y, mask1)
6907 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
6908 // =>
6909 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
6910 // where msb = lsb + size - 1
6911 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
6912 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6913 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6914 (MaskIdx0 + MaskLen0 <= 64) &&
6915 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
6916 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
6917 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
6918 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6919 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
6920 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
6921 DAG.getConstant(ValBits == 32
6922 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
6923 : (MaskIdx0 + MaskLen0 - 1),
6924 DL, GRLenVT),
6925 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6926 }
6927
6928 // 4th pattern to match BSTRINS:
6929 // R = or (and X, mask), (shl Y, shamt)
6930 // where mask = (2**shamt - 1)
6931 // =>
6932 // R = BSTRINS X, Y, ValBits - 1, shamt
6933 // where ValBits = 32 or 64
6934 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
6935 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6936 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
6937 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6938 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
6939 (MaskIdx0 + MaskLen0 <= ValBits)) {
6940 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
6941 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6942 N1.getOperand(0),
6943 DAG.getConstant((ValBits - 1), DL, GRLenVT),
6944 DAG.getConstant(Shamt, DL, GRLenVT));
6945 }
6946
6947 // 5th pattern to match BSTRINS:
6948 // R = or (and X, mask), const
6949 // where ~mask = (2**size - 1) << lsb, mask & const = 0
6950 // =>
6951 // R = BSTRINS X, (const >> lsb), msb, lsb
6952 // where msb = lsb + size - 1
6953 if (N0.getOpcode() == ISD::AND &&
6954 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6955 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6956 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
6957 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
6958 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
6959 return DAG.getNode(
6960 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6961 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
6962 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
6963 : (MaskIdx0 + MaskLen0 - 1),
6964 DL, GRLenVT),
6965 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6966 }
6967
6968 // 6th pattern.
6969 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
6970 // by the incoming bits are known to be zero.
6971 // =>
6972 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
6973 //
6974 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
6975 // pattern is more common than the 1st. So we put the 1st before the 6th in
6976 // order to match as many nodes as possible.
6977 ConstantSDNode *CNMask, *CNShamt;
6978 unsigned MaskIdx, MaskLen;
6979 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
6980 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6981 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
6982 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6983 CNShamt->getZExtValue() + MaskLen <= ValBits) {
6984 Shamt = CNShamt->getZExtValue();
6985 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
6986 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
6987 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
6988 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
6989 N1.getOperand(0).getOperand(0),
6990 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
6991 DAG.getConstant(Shamt, DL, GRLenVT));
6992 }
6993 }
6994
6995 // 7th pattern.
6996 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
6997 // overwritten by the incoming bits are known to be zero.
6998 // =>
6999 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7000 //
7001 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7002 // before the 7th in order to match as many nodes as possible.
7003 if (N1.getOpcode() == ISD::AND &&
7004 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7005 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7006 N1.getOperand(0).getOpcode() == ISD::SHL &&
7007 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7008 CNShamt->getZExtValue() == MaskIdx) {
7009 APInt ShMask(ValBits, CNMask->getZExtValue());
7010 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7011 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7012 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7013 N1.getOperand(0).getOperand(0),
7014 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7015 DAG.getConstant(MaskIdx, DL, GRLenVT));
7016 }
7017 }
7018
7019 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7020 if (!SwapAndRetried) {
7021 std::swap(N0, N1);
7022 SwapAndRetried = true;
7023 goto Retry;
7024 }
7025
7026 SwapAndRetried = false;
7027Retry2:
7028 // 8th pattern.
7029 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7030 // the incoming bits are known to be zero.
7031 // =>
7032 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7033 //
7034 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7035 // we put it here in order to match as many nodes as possible or generate less
7036 // instructions.
7037 if (N1.getOpcode() == ISD::AND &&
7038 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7039 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7040 APInt ShMask(ValBits, CNMask->getZExtValue());
7041 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7042 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7043 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7044 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7045 N1->getOperand(0),
7046 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7047 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7048 DAG.getConstant(MaskIdx, DL, GRLenVT));
7049 }
7050 }
7051 // Swap N0/N1 and retry.
7052 if (!SwapAndRetried) {
7053 std::swap(N0, N1);
7054 SwapAndRetried = true;
7055 goto Retry2;
7056 }
7057
7058 return SDValue();
7059}
7060
7061static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
7062 ExtType = ISD::NON_EXTLOAD;
7063
7064 switch (V.getNode()->getOpcode()) {
7065 case ISD::LOAD: {
7066 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7067 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7068 (LoadNode->getMemoryVT() == MVT::i16)) {
7069 ExtType = LoadNode->getExtensionType();
7070 return true;
7071 }
7072 return false;
7073 }
7074 case ISD::AssertSext: {
7075 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7076 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7077 ExtType = ISD::SEXTLOAD;
7078 return true;
7079 }
7080 return false;
7081 }
7082 case ISD::AssertZext: {
7083 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7084 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7085 ExtType = ISD::ZEXTLOAD;
7086 return true;
7087 }
7088 return false;
7089 }
7090 default:
7091 return false;
7092 }
7093
7094 return false;
7095}
7096
7097// Eliminate redundant truncation and zero-extension nodes.
7098// * Case 1:
7099// +------------+ +------------+ +------------+
7100// | Input1 | | Input2 | | CC |
7101// +------------+ +------------+ +------------+
7102// | | |
7103// V V +----+
7104// +------------+ +------------+ |
7105// | TRUNCATE | | TRUNCATE | |
7106// +------------+ +------------+ |
7107// | | |
7108// V V |
7109// +------------+ +------------+ |
7110// | ZERO_EXT | | ZERO_EXT | |
7111// +------------+ +------------+ |
7112// | | |
7113// | +-------------+ |
7114// V V | |
7115// +----------------+ | |
7116// | AND | | |
7117// +----------------+ | |
7118// | | |
7119// +---------------+ | |
7120// | | |
7121// V V V
7122// +-------------+
7123// | CMP |
7124// +-------------+
7125// * Case 2:
7126// +------------+ +------------+ +-------------+ +------------+ +------------+
7127// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7128// +------------+ +------------+ +-------------+ +------------+ +------------+
7129// | | | | |
7130// V | | | |
7131// +------------+ | | | |
7132// | XOR |<---------------------+ | |
7133// +------------+ | | |
7134// | | | |
7135// V V +---------------+ |
7136// +------------+ +------------+ | |
7137// | TRUNCATE | | TRUNCATE | | +-------------------------+
7138// +------------+ +------------+ | |
7139// | | | |
7140// V V | |
7141// +------------+ +------------+ | |
7142// | ZERO_EXT | | ZERO_EXT | | |
7143// +------------+ +------------+ | |
7144// | | | |
7145// V V | |
7146// +----------------+ | |
7147// | AND | | |
7148// +----------------+ | |
7149// | | |
7150// +---------------+ | |
7151// | | |
7152// V V V
7153// +-------------+
7154// | CMP |
7155// +-------------+
7158 const LoongArchSubtarget &Subtarget) {
7159 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
7160
7161 SDNode *AndNode = N->getOperand(0).getNode();
7162 if (AndNode->getOpcode() != ISD::AND)
7163 return SDValue();
7164
7165 SDValue AndInputValue2 = AndNode->getOperand(1);
7166 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7167 return SDValue();
7168
7169 SDValue CmpInputValue = N->getOperand(1);
7170 SDValue AndInputValue1 = AndNode->getOperand(0);
7171 if (AndInputValue1.getOpcode() == ISD::XOR) {
7172 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7173 return SDValue();
7174 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7175 if (!CN || !CN->isAllOnes())
7176 return SDValue();
7177 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7178 if (!CN || !CN->isZero())
7179 return SDValue();
7180 AndInputValue1 = AndInputValue1.getOperand(0);
7181 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7182 return SDValue();
7183 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7184 if (AndInputValue2 != CmpInputValue)
7185 return SDValue();
7186 } else {
7187 return SDValue();
7188 }
7189
7190 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7191 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7192 return SDValue();
7193
7194 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7195 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7196 return SDValue();
7197
7198 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7199 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7200 ISD::LoadExtType ExtType1;
7201 ISD::LoadExtType ExtType2;
7202
7203 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7204 !checkValueWidth(TruncInputValue2, ExtType2))
7205 return SDValue();
7206
7207 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7208 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7209 return SDValue();
7210
7211 if ((ExtType2 != ISD::ZEXTLOAD) &&
7212 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7213 return SDValue();
7214
7215 // These truncation and zero-extension nodes are not necessary, remove them.
7216 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7217 TruncInputValue1, TruncInputValue2);
7218 SDValue NewSetCC =
7219 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7220 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7221 return SDValue(N, 0);
7222}
7223
7224// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7227 const LoongArchSubtarget &Subtarget) {
7228 if (DCI.isBeforeLegalizeOps())
7229 return SDValue();
7230
7231 SDValue Src = N->getOperand(0);
7232 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7233 return SDValue();
7234
7235 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7236 Src.getOperand(0));
7237}
7238
7239// Perform common combines for BR_CC and SELECT_CC conditions.
7240static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7241 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
7242 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7243
7244 // As far as arithmetic right shift always saves the sign,
7245 // shift can be omitted.
7246 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7247 // setge (sra X, N), 0 -> setge X, 0
7248 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7249 LHS.getOpcode() == ISD::SRA) {
7250 LHS = LHS.getOperand(0);
7251 return true;
7252 }
7253
7254 if (!ISD::isIntEqualitySetCC(CCVal))
7255 return false;
7256
7257 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7258 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7259 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7260 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7261 // If we're looking for eq 0 instead of ne 0, we need to invert the
7262 // condition.
7263 bool Invert = CCVal == ISD::SETEQ;
7264 CCVal = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
7265 if (Invert)
7266 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7267
7268 RHS = LHS.getOperand(1);
7269 LHS = LHS.getOperand(0);
7270 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7271
7272 CC = DAG.getCondCode(CCVal);
7273 return true;
7274 }
7275
7276 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7277 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7278 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7279 SDValue LHS0 = LHS.getOperand(0);
7280 if (LHS0.getOpcode() == ISD::AND &&
7281 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7282 uint64_t Mask = LHS0.getConstantOperandVal(1);
7283 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7284 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7285 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7286 CC = DAG.getCondCode(CCVal);
7287
7288 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7289 LHS = LHS0.getOperand(0);
7290 if (ShAmt != 0)
7291 LHS =
7292 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7293 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7294 return true;
7295 }
7296 }
7297 }
7298
7299 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7300 // This can occur when legalizing some floating point comparisons.
7301 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7302 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7303 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7304 CC = DAG.getCondCode(CCVal);
7305 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7306 return true;
7307 }
7308
7309 return false;
7310}
7311
7314 const LoongArchSubtarget &Subtarget) {
7315 SDValue LHS = N->getOperand(1);
7316 SDValue RHS = N->getOperand(2);
7317 SDValue CC = N->getOperand(3);
7318 SDLoc DL(N);
7319
7320 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7321 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7322 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7323
7324 return SDValue();
7325}
7326
7329 const LoongArchSubtarget &Subtarget) {
7330 // Transform
7331 SDValue LHS = N->getOperand(0);
7332 SDValue RHS = N->getOperand(1);
7333 SDValue CC = N->getOperand(2);
7334 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7335 SDValue TrueV = N->getOperand(3);
7336 SDValue FalseV = N->getOperand(4);
7337 SDLoc DL(N);
7338 EVT VT = N->getValueType(0);
7339
7340 // If the True and False values are the same, we don't need a select_cc.
7341 if (TrueV == FalseV)
7342 return TrueV;
7343
7344 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7345 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7346 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7348 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7349 if (CCVal == ISD::CondCode::SETGE)
7350 std::swap(TrueV, FalseV);
7351
7352 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7353 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7354 // Only handle simm12, if it is not in this range, it can be considered as
7355 // register.
7356 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7357 isInt<12>(TrueSImm - FalseSImm)) {
7358 SDValue SRA =
7359 DAG.getNode(ISD::SRA, DL, VT, LHS,
7360 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7361 SDValue AND =
7362 DAG.getNode(ISD::AND, DL, VT, SRA,
7363 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7364 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7365 }
7366
7367 if (CCVal == ISD::CondCode::SETGE)
7368 std::swap(TrueV, FalseV);
7369 }
7370
7371 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7372 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
7373 {LHS, RHS, CC, TrueV, FalseV});
7374
7375 return SDValue();
7376}
7377
7378template <unsigned N>
7380 SelectionDAG &DAG,
7381 const LoongArchSubtarget &Subtarget,
7382 bool IsSigned = false) {
7383 SDLoc DL(Node);
7384 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7385 // Check the ImmArg.
7386 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7387 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7388 DAG.getContext()->emitError(Node->getOperationName(0) +
7389 ": argument out of range.");
7390 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
7391 }
7392 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
7393}
7394
7395template <unsigned N>
7396static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
7397 SelectionDAG &DAG, bool IsSigned = false) {
7398 SDLoc DL(Node);
7399 EVT ResTy = Node->getValueType(0);
7400 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7401
7402 // Check the ImmArg.
7403 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7404 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7405 DAG.getContext()->emitError(Node->getOperationName(0) +
7406 ": argument out of range.");
7407 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7408 }
7409 return DAG.getConstant(
7411 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
7412 DL, ResTy);
7413}
7414
7416 SDLoc DL(Node);
7417 EVT ResTy = Node->getValueType(0);
7418 SDValue Vec = Node->getOperand(2);
7419 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
7420 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
7421}
7422
7424 SDLoc DL(Node);
7425 EVT ResTy = Node->getValueType(0);
7426 SDValue One = DAG.getConstant(1, DL, ResTy);
7427 SDValue Bit =
7428 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
7429
7430 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
7431 DAG.getNOT(DL, Bit, ResTy));
7432}
7433
7434template <unsigned N>
7436 SDLoc DL(Node);
7437 EVT ResTy = Node->getValueType(0);
7438 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7439 // Check the unsigned ImmArg.
7440 if (!isUInt<N>(CImm->getZExtValue())) {
7441 DAG.getContext()->emitError(Node->getOperationName(0) +
7442 ": argument out of range.");
7443 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7444 }
7445
7446 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7447 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
7448
7449 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
7450}
7451
7452template <unsigned N>
7454 SDLoc DL(Node);
7455 EVT ResTy = Node->getValueType(0);
7456 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7457 // Check the unsigned ImmArg.
7458 if (!isUInt<N>(CImm->getZExtValue())) {
7459 DAG.getContext()->emitError(Node->getOperationName(0) +
7460 ": argument out of range.");
7461 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7462 }
7463
7464 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7465 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7466 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
7467}
7468
7469template <unsigned N>
7471 SDLoc DL(Node);
7472 EVT ResTy = Node->getValueType(0);
7473 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7474 // Check the unsigned ImmArg.
7475 if (!isUInt<N>(CImm->getZExtValue())) {
7476 DAG.getContext()->emitError(Node->getOperationName(0) +
7477 ": argument out of range.");
7478 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7479 }
7480
7481 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7482 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7483 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
7484}
7485
7486template <unsigned W>
7488 unsigned ResOp) {
7489 unsigned Imm = N->getConstantOperandVal(2);
7490 if (!isUInt<W>(Imm)) {
7491 const StringRef ErrorMsg = "argument out of range";
7492 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
7493 return DAG.getUNDEF(N->getValueType(0));
7494 }
7495 SDLoc DL(N);
7496 SDValue Vec = N->getOperand(1);
7497 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
7499 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
7500}
7501
7502static SDValue
7505 const LoongArchSubtarget &Subtarget) {
7506 SDLoc DL(N);
7507 switch (N->getConstantOperandVal(0)) {
7508 default:
7509 break;
7510 case Intrinsic::loongarch_lsx_vadd_b:
7511 case Intrinsic::loongarch_lsx_vadd_h:
7512 case Intrinsic::loongarch_lsx_vadd_w:
7513 case Intrinsic::loongarch_lsx_vadd_d:
7514 case Intrinsic::loongarch_lasx_xvadd_b:
7515 case Intrinsic::loongarch_lasx_xvadd_h:
7516 case Intrinsic::loongarch_lasx_xvadd_w:
7517 case Intrinsic::loongarch_lasx_xvadd_d:
7518 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7519 N->getOperand(2));
7520 case Intrinsic::loongarch_lsx_vaddi_bu:
7521 case Intrinsic::loongarch_lsx_vaddi_hu:
7522 case Intrinsic::loongarch_lsx_vaddi_wu:
7523 case Intrinsic::loongarch_lsx_vaddi_du:
7524 case Intrinsic::loongarch_lasx_xvaddi_bu:
7525 case Intrinsic::loongarch_lasx_xvaddi_hu:
7526 case Intrinsic::loongarch_lasx_xvaddi_wu:
7527 case Intrinsic::loongarch_lasx_xvaddi_du:
7528 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7529 lowerVectorSplatImm<5>(N, 2, DAG));
7530 case Intrinsic::loongarch_lsx_vsub_b:
7531 case Intrinsic::loongarch_lsx_vsub_h:
7532 case Intrinsic::loongarch_lsx_vsub_w:
7533 case Intrinsic::loongarch_lsx_vsub_d:
7534 case Intrinsic::loongarch_lasx_xvsub_b:
7535 case Intrinsic::loongarch_lasx_xvsub_h:
7536 case Intrinsic::loongarch_lasx_xvsub_w:
7537 case Intrinsic::loongarch_lasx_xvsub_d:
7538 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7539 N->getOperand(2));
7540 case Intrinsic::loongarch_lsx_vsubi_bu:
7541 case Intrinsic::loongarch_lsx_vsubi_hu:
7542 case Intrinsic::loongarch_lsx_vsubi_wu:
7543 case Intrinsic::loongarch_lsx_vsubi_du:
7544 case Intrinsic::loongarch_lasx_xvsubi_bu:
7545 case Intrinsic::loongarch_lasx_xvsubi_hu:
7546 case Intrinsic::loongarch_lasx_xvsubi_wu:
7547 case Intrinsic::loongarch_lasx_xvsubi_du:
7548 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7549 lowerVectorSplatImm<5>(N, 2, DAG));
7550 case Intrinsic::loongarch_lsx_vneg_b:
7551 case Intrinsic::loongarch_lsx_vneg_h:
7552 case Intrinsic::loongarch_lsx_vneg_w:
7553 case Intrinsic::loongarch_lsx_vneg_d:
7554 case Intrinsic::loongarch_lasx_xvneg_b:
7555 case Intrinsic::loongarch_lasx_xvneg_h:
7556 case Intrinsic::loongarch_lasx_xvneg_w:
7557 case Intrinsic::loongarch_lasx_xvneg_d:
7558 return DAG.getNode(
7559 ISD::SUB, DL, N->getValueType(0),
7560 DAG.getConstant(
7561 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
7562 /*isSigned=*/true),
7563 SDLoc(N), N->getValueType(0)),
7564 N->getOperand(1));
7565 case Intrinsic::loongarch_lsx_vmax_b:
7566 case Intrinsic::loongarch_lsx_vmax_h:
7567 case Intrinsic::loongarch_lsx_vmax_w:
7568 case Intrinsic::loongarch_lsx_vmax_d:
7569 case Intrinsic::loongarch_lasx_xvmax_b:
7570 case Intrinsic::loongarch_lasx_xvmax_h:
7571 case Intrinsic::loongarch_lasx_xvmax_w:
7572 case Intrinsic::loongarch_lasx_xvmax_d:
7573 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7574 N->getOperand(2));
7575 case Intrinsic::loongarch_lsx_vmax_bu:
7576 case Intrinsic::loongarch_lsx_vmax_hu:
7577 case Intrinsic::loongarch_lsx_vmax_wu:
7578 case Intrinsic::loongarch_lsx_vmax_du:
7579 case Intrinsic::loongarch_lasx_xvmax_bu:
7580 case Intrinsic::loongarch_lasx_xvmax_hu:
7581 case Intrinsic::loongarch_lasx_xvmax_wu:
7582 case Intrinsic::loongarch_lasx_xvmax_du:
7583 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7584 N->getOperand(2));
7585 case Intrinsic::loongarch_lsx_vmaxi_b:
7586 case Intrinsic::loongarch_lsx_vmaxi_h:
7587 case Intrinsic::loongarch_lsx_vmaxi_w:
7588 case Intrinsic::loongarch_lsx_vmaxi_d:
7589 case Intrinsic::loongarch_lasx_xvmaxi_b:
7590 case Intrinsic::loongarch_lasx_xvmaxi_h:
7591 case Intrinsic::loongarch_lasx_xvmaxi_w:
7592 case Intrinsic::loongarch_lasx_xvmaxi_d:
7593 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7594 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7595 case Intrinsic::loongarch_lsx_vmaxi_bu:
7596 case Intrinsic::loongarch_lsx_vmaxi_hu:
7597 case Intrinsic::loongarch_lsx_vmaxi_wu:
7598 case Intrinsic::loongarch_lsx_vmaxi_du:
7599 case Intrinsic::loongarch_lasx_xvmaxi_bu:
7600 case Intrinsic::loongarch_lasx_xvmaxi_hu:
7601 case Intrinsic::loongarch_lasx_xvmaxi_wu:
7602 case Intrinsic::loongarch_lasx_xvmaxi_du:
7603 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7604 lowerVectorSplatImm<5>(N, 2, DAG));
7605 case Intrinsic::loongarch_lsx_vmin_b:
7606 case Intrinsic::loongarch_lsx_vmin_h:
7607 case Intrinsic::loongarch_lsx_vmin_w:
7608 case Intrinsic::loongarch_lsx_vmin_d:
7609 case Intrinsic::loongarch_lasx_xvmin_b:
7610 case Intrinsic::loongarch_lasx_xvmin_h:
7611 case Intrinsic::loongarch_lasx_xvmin_w:
7612 case Intrinsic::loongarch_lasx_xvmin_d:
7613 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7614 N->getOperand(2));
7615 case Intrinsic::loongarch_lsx_vmin_bu:
7616 case Intrinsic::loongarch_lsx_vmin_hu:
7617 case Intrinsic::loongarch_lsx_vmin_wu:
7618 case Intrinsic::loongarch_lsx_vmin_du:
7619 case Intrinsic::loongarch_lasx_xvmin_bu:
7620 case Intrinsic::loongarch_lasx_xvmin_hu:
7621 case Intrinsic::loongarch_lasx_xvmin_wu:
7622 case Intrinsic::loongarch_lasx_xvmin_du:
7623 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7624 N->getOperand(2));
7625 case Intrinsic::loongarch_lsx_vmini_b:
7626 case Intrinsic::loongarch_lsx_vmini_h:
7627 case Intrinsic::loongarch_lsx_vmini_w:
7628 case Intrinsic::loongarch_lsx_vmini_d:
7629 case Intrinsic::loongarch_lasx_xvmini_b:
7630 case Intrinsic::loongarch_lasx_xvmini_h:
7631 case Intrinsic::loongarch_lasx_xvmini_w:
7632 case Intrinsic::loongarch_lasx_xvmini_d:
7633 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7634 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7635 case Intrinsic::loongarch_lsx_vmini_bu:
7636 case Intrinsic::loongarch_lsx_vmini_hu:
7637 case Intrinsic::loongarch_lsx_vmini_wu:
7638 case Intrinsic::loongarch_lsx_vmini_du:
7639 case Intrinsic::loongarch_lasx_xvmini_bu:
7640 case Intrinsic::loongarch_lasx_xvmini_hu:
7641 case Intrinsic::loongarch_lasx_xvmini_wu:
7642 case Intrinsic::loongarch_lasx_xvmini_du:
7643 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7644 lowerVectorSplatImm<5>(N, 2, DAG));
7645 case Intrinsic::loongarch_lsx_vmul_b:
7646 case Intrinsic::loongarch_lsx_vmul_h:
7647 case Intrinsic::loongarch_lsx_vmul_w:
7648 case Intrinsic::loongarch_lsx_vmul_d:
7649 case Intrinsic::loongarch_lasx_xvmul_b:
7650 case Intrinsic::loongarch_lasx_xvmul_h:
7651 case Intrinsic::loongarch_lasx_xvmul_w:
7652 case Intrinsic::loongarch_lasx_xvmul_d:
7653 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
7654 N->getOperand(2));
7655 case Intrinsic::loongarch_lsx_vmadd_b:
7656 case Intrinsic::loongarch_lsx_vmadd_h:
7657 case Intrinsic::loongarch_lsx_vmadd_w:
7658 case Intrinsic::loongarch_lsx_vmadd_d:
7659 case Intrinsic::loongarch_lasx_xvmadd_b:
7660 case Intrinsic::loongarch_lasx_xvmadd_h:
7661 case Intrinsic::loongarch_lasx_xvmadd_w:
7662 case Intrinsic::loongarch_lasx_xvmadd_d: {
7663 EVT ResTy = N->getValueType(0);
7664 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
7665 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7666 N->getOperand(3)));
7667 }
7668 case Intrinsic::loongarch_lsx_vmsub_b:
7669 case Intrinsic::loongarch_lsx_vmsub_h:
7670 case Intrinsic::loongarch_lsx_vmsub_w:
7671 case Intrinsic::loongarch_lsx_vmsub_d:
7672 case Intrinsic::loongarch_lasx_xvmsub_b:
7673 case Intrinsic::loongarch_lasx_xvmsub_h:
7674 case Intrinsic::loongarch_lasx_xvmsub_w:
7675 case Intrinsic::loongarch_lasx_xvmsub_d: {
7676 EVT ResTy = N->getValueType(0);
7677 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
7678 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7679 N->getOperand(3)));
7680 }
7681 case Intrinsic::loongarch_lsx_vdiv_b:
7682 case Intrinsic::loongarch_lsx_vdiv_h:
7683 case Intrinsic::loongarch_lsx_vdiv_w:
7684 case Intrinsic::loongarch_lsx_vdiv_d:
7685 case Intrinsic::loongarch_lasx_xvdiv_b:
7686 case Intrinsic::loongarch_lasx_xvdiv_h:
7687 case Intrinsic::loongarch_lasx_xvdiv_w:
7688 case Intrinsic::loongarch_lasx_xvdiv_d:
7689 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
7690 N->getOperand(2));
7691 case Intrinsic::loongarch_lsx_vdiv_bu:
7692 case Intrinsic::loongarch_lsx_vdiv_hu:
7693 case Intrinsic::loongarch_lsx_vdiv_wu:
7694 case Intrinsic::loongarch_lsx_vdiv_du:
7695 case Intrinsic::loongarch_lasx_xvdiv_bu:
7696 case Intrinsic::loongarch_lasx_xvdiv_hu:
7697 case Intrinsic::loongarch_lasx_xvdiv_wu:
7698 case Intrinsic::loongarch_lasx_xvdiv_du:
7699 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
7700 N->getOperand(2));
7701 case Intrinsic::loongarch_lsx_vmod_b:
7702 case Intrinsic::loongarch_lsx_vmod_h:
7703 case Intrinsic::loongarch_lsx_vmod_w:
7704 case Intrinsic::loongarch_lsx_vmod_d:
7705 case Intrinsic::loongarch_lasx_xvmod_b:
7706 case Intrinsic::loongarch_lasx_xvmod_h:
7707 case Intrinsic::loongarch_lasx_xvmod_w:
7708 case Intrinsic::loongarch_lasx_xvmod_d:
7709 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
7710 N->getOperand(2));
7711 case Intrinsic::loongarch_lsx_vmod_bu:
7712 case Intrinsic::loongarch_lsx_vmod_hu:
7713 case Intrinsic::loongarch_lsx_vmod_wu:
7714 case Intrinsic::loongarch_lsx_vmod_du:
7715 case Intrinsic::loongarch_lasx_xvmod_bu:
7716 case Intrinsic::loongarch_lasx_xvmod_hu:
7717 case Intrinsic::loongarch_lasx_xvmod_wu:
7718 case Intrinsic::loongarch_lasx_xvmod_du:
7719 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
7720 N->getOperand(2));
7721 case Intrinsic::loongarch_lsx_vand_v:
7722 case Intrinsic::loongarch_lasx_xvand_v:
7723 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
7724 N->getOperand(2));
7725 case Intrinsic::loongarch_lsx_vor_v:
7726 case Intrinsic::loongarch_lasx_xvor_v:
7727 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7728 N->getOperand(2));
7729 case Intrinsic::loongarch_lsx_vxor_v:
7730 case Intrinsic::loongarch_lasx_xvxor_v:
7731 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
7732 N->getOperand(2));
7733 case Intrinsic::loongarch_lsx_vnor_v:
7734 case Intrinsic::loongarch_lasx_xvnor_v: {
7735 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7736 N->getOperand(2));
7737 return DAG.getNOT(DL, Res, Res->getValueType(0));
7738 }
7739 case Intrinsic::loongarch_lsx_vandi_b:
7740 case Intrinsic::loongarch_lasx_xvandi_b:
7741 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
7742 lowerVectorSplatImm<8>(N, 2, DAG));
7743 case Intrinsic::loongarch_lsx_vori_b:
7744 case Intrinsic::loongarch_lasx_xvori_b:
7745 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7746 lowerVectorSplatImm<8>(N, 2, DAG));
7747 case Intrinsic::loongarch_lsx_vxori_b:
7748 case Intrinsic::loongarch_lasx_xvxori_b:
7749 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
7750 lowerVectorSplatImm<8>(N, 2, DAG));
7751 case Intrinsic::loongarch_lsx_vsll_b:
7752 case Intrinsic::loongarch_lsx_vsll_h:
7753 case Intrinsic::loongarch_lsx_vsll_w:
7754 case Intrinsic::loongarch_lsx_vsll_d:
7755 case Intrinsic::loongarch_lasx_xvsll_b:
7756 case Intrinsic::loongarch_lasx_xvsll_h:
7757 case Intrinsic::loongarch_lasx_xvsll_w:
7758 case Intrinsic::loongarch_lasx_xvsll_d:
7759 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7760 truncateVecElts(N, DAG));
7761 case Intrinsic::loongarch_lsx_vslli_b:
7762 case Intrinsic::loongarch_lasx_xvslli_b:
7763 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7764 lowerVectorSplatImm<3>(N, 2, DAG));
7765 case Intrinsic::loongarch_lsx_vslli_h:
7766 case Intrinsic::loongarch_lasx_xvslli_h:
7767 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7768 lowerVectorSplatImm<4>(N, 2, DAG));
7769 case Intrinsic::loongarch_lsx_vslli_w:
7770 case Intrinsic::loongarch_lasx_xvslli_w:
7771 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7772 lowerVectorSplatImm<5>(N, 2, DAG));
7773 case Intrinsic::loongarch_lsx_vslli_d:
7774 case Intrinsic::loongarch_lasx_xvslli_d:
7775 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7776 lowerVectorSplatImm<6>(N, 2, DAG));
7777 case Intrinsic::loongarch_lsx_vsrl_b:
7778 case Intrinsic::loongarch_lsx_vsrl_h:
7779 case Intrinsic::loongarch_lsx_vsrl_w:
7780 case Intrinsic::loongarch_lsx_vsrl_d:
7781 case Intrinsic::loongarch_lasx_xvsrl_b:
7782 case Intrinsic::loongarch_lasx_xvsrl_h:
7783 case Intrinsic::loongarch_lasx_xvsrl_w:
7784 case Intrinsic::loongarch_lasx_xvsrl_d:
7785 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7786 truncateVecElts(N, DAG));
7787 case Intrinsic::loongarch_lsx_vsrli_b:
7788 case Intrinsic::loongarch_lasx_xvsrli_b:
7789 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7790 lowerVectorSplatImm<3>(N, 2, DAG));
7791 case Intrinsic::loongarch_lsx_vsrli_h:
7792 case Intrinsic::loongarch_lasx_xvsrli_h:
7793 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7794 lowerVectorSplatImm<4>(N, 2, DAG));
7795 case Intrinsic::loongarch_lsx_vsrli_w:
7796 case Intrinsic::loongarch_lasx_xvsrli_w:
7797 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7798 lowerVectorSplatImm<5>(N, 2, DAG));
7799 case Intrinsic::loongarch_lsx_vsrli_d:
7800 case Intrinsic::loongarch_lasx_xvsrli_d:
7801 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7802 lowerVectorSplatImm<6>(N, 2, DAG));
7803 case Intrinsic::loongarch_lsx_vsra_b:
7804 case Intrinsic::loongarch_lsx_vsra_h:
7805 case Intrinsic::loongarch_lsx_vsra_w:
7806 case Intrinsic::loongarch_lsx_vsra_d:
7807 case Intrinsic::loongarch_lasx_xvsra_b:
7808 case Intrinsic::loongarch_lasx_xvsra_h:
7809 case Intrinsic::loongarch_lasx_xvsra_w:
7810 case Intrinsic::loongarch_lasx_xvsra_d:
7811 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
7812 truncateVecElts(N, DAG));
7813 case Intrinsic::loongarch_lsx_vsrai_b:
7814 case Intrinsic::loongarch_lasx_xvsrai_b:
7815 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
7816 lowerVectorSplatImm<3>(N, 2, DAG));
7817 case Intrinsic::loongarch_lsx_vsrai_h:
7818 case Intrinsic::loongarch_lasx_xvsrai_h:
7819 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
7820 lowerVectorSplatImm<4>(N, 2, DAG));
7821 case Intrinsic::loongarch_lsx_vsrai_w:
7822 case Intrinsic::loongarch_lasx_xvsrai_w:
7823 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
7824 lowerVectorSplatImm<5>(N, 2, DAG));
7825 case Intrinsic::loongarch_lsx_vsrai_d:
7826 case Intrinsic::loongarch_lasx_xvsrai_d:
7827 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
7828 lowerVectorSplatImm<6>(N, 2, DAG));
7829 case Intrinsic::loongarch_lsx_vclz_b:
7830 case Intrinsic::loongarch_lsx_vclz_h:
7831 case Intrinsic::loongarch_lsx_vclz_w:
7832 case Intrinsic::loongarch_lsx_vclz_d:
7833 case Intrinsic::loongarch_lasx_xvclz_b:
7834 case Intrinsic::loongarch_lasx_xvclz_h:
7835 case Intrinsic::loongarch_lasx_xvclz_w:
7836 case Intrinsic::loongarch_lasx_xvclz_d:
7837 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
7838 case Intrinsic::loongarch_lsx_vpcnt_b:
7839 case Intrinsic::loongarch_lsx_vpcnt_h:
7840 case Intrinsic::loongarch_lsx_vpcnt_w:
7841 case Intrinsic::loongarch_lsx_vpcnt_d:
7842 case Intrinsic::loongarch_lasx_xvpcnt_b:
7843 case Intrinsic::loongarch_lasx_xvpcnt_h:
7844 case Intrinsic::loongarch_lasx_xvpcnt_w:
7845 case Intrinsic::loongarch_lasx_xvpcnt_d:
7846 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
7847 case Intrinsic::loongarch_lsx_vbitclr_b:
7848 case Intrinsic::loongarch_lsx_vbitclr_h:
7849 case Intrinsic::loongarch_lsx_vbitclr_w:
7850 case Intrinsic::loongarch_lsx_vbitclr_d:
7851 case Intrinsic::loongarch_lasx_xvbitclr_b:
7852 case Intrinsic::loongarch_lasx_xvbitclr_h:
7853 case Intrinsic::loongarch_lasx_xvbitclr_w:
7854 case Intrinsic::loongarch_lasx_xvbitclr_d:
7855 return lowerVectorBitClear(N, DAG);
7856 case Intrinsic::loongarch_lsx_vbitclri_b:
7857 case Intrinsic::loongarch_lasx_xvbitclri_b:
7858 return lowerVectorBitClearImm<3>(N, DAG);
7859 case Intrinsic::loongarch_lsx_vbitclri_h:
7860 case Intrinsic::loongarch_lasx_xvbitclri_h:
7861 return lowerVectorBitClearImm<4>(N, DAG);
7862 case Intrinsic::loongarch_lsx_vbitclri_w:
7863 case Intrinsic::loongarch_lasx_xvbitclri_w:
7864 return lowerVectorBitClearImm<5>(N, DAG);
7865 case Intrinsic::loongarch_lsx_vbitclri_d:
7866 case Intrinsic::loongarch_lasx_xvbitclri_d:
7867 return lowerVectorBitClearImm<6>(N, DAG);
7868 case Intrinsic::loongarch_lsx_vbitset_b:
7869 case Intrinsic::loongarch_lsx_vbitset_h:
7870 case Intrinsic::loongarch_lsx_vbitset_w:
7871 case Intrinsic::loongarch_lsx_vbitset_d:
7872 case Intrinsic::loongarch_lasx_xvbitset_b:
7873 case Intrinsic::loongarch_lasx_xvbitset_h:
7874 case Intrinsic::loongarch_lasx_xvbitset_w:
7875 case Intrinsic::loongarch_lasx_xvbitset_d: {
7876 EVT VecTy = N->getValueType(0);
7877 SDValue One = DAG.getConstant(1, DL, VecTy);
7878 return DAG.getNode(
7879 ISD::OR, DL, VecTy, N->getOperand(1),
7880 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
7881 }
7882 case Intrinsic::loongarch_lsx_vbitseti_b:
7883 case Intrinsic::loongarch_lasx_xvbitseti_b:
7884 return lowerVectorBitSetImm<3>(N, DAG);
7885 case Intrinsic::loongarch_lsx_vbitseti_h:
7886 case Intrinsic::loongarch_lasx_xvbitseti_h:
7887 return lowerVectorBitSetImm<4>(N, DAG);
7888 case Intrinsic::loongarch_lsx_vbitseti_w:
7889 case Intrinsic::loongarch_lasx_xvbitseti_w:
7890 return lowerVectorBitSetImm<5>(N, DAG);
7891 case Intrinsic::loongarch_lsx_vbitseti_d:
7892 case Intrinsic::loongarch_lasx_xvbitseti_d:
7893 return lowerVectorBitSetImm<6>(N, DAG);
7894 case Intrinsic::loongarch_lsx_vbitrev_b:
7895 case Intrinsic::loongarch_lsx_vbitrev_h:
7896 case Intrinsic::loongarch_lsx_vbitrev_w:
7897 case Intrinsic::loongarch_lsx_vbitrev_d:
7898 case Intrinsic::loongarch_lasx_xvbitrev_b:
7899 case Intrinsic::loongarch_lasx_xvbitrev_h:
7900 case Intrinsic::loongarch_lasx_xvbitrev_w:
7901 case Intrinsic::loongarch_lasx_xvbitrev_d: {
7902 EVT VecTy = N->getValueType(0);
7903 SDValue One = DAG.getConstant(1, DL, VecTy);
7904 return DAG.getNode(
7905 ISD::XOR, DL, VecTy, N->getOperand(1),
7906 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
7907 }
7908 case Intrinsic::loongarch_lsx_vbitrevi_b:
7909 case Intrinsic::loongarch_lasx_xvbitrevi_b:
7910 return lowerVectorBitRevImm<3>(N, DAG);
7911 case Intrinsic::loongarch_lsx_vbitrevi_h:
7912 case Intrinsic::loongarch_lasx_xvbitrevi_h:
7913 return lowerVectorBitRevImm<4>(N, DAG);
7914 case Intrinsic::loongarch_lsx_vbitrevi_w:
7915 case Intrinsic::loongarch_lasx_xvbitrevi_w:
7916 return lowerVectorBitRevImm<5>(N, DAG);
7917 case Intrinsic::loongarch_lsx_vbitrevi_d:
7918 case Intrinsic::loongarch_lasx_xvbitrevi_d:
7919 return lowerVectorBitRevImm<6>(N, DAG);
7920 case Intrinsic::loongarch_lsx_vfadd_s:
7921 case Intrinsic::loongarch_lsx_vfadd_d:
7922 case Intrinsic::loongarch_lasx_xvfadd_s:
7923 case Intrinsic::loongarch_lasx_xvfadd_d:
7924 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
7925 N->getOperand(2));
7926 case Intrinsic::loongarch_lsx_vfsub_s:
7927 case Intrinsic::loongarch_lsx_vfsub_d:
7928 case Intrinsic::loongarch_lasx_xvfsub_s:
7929 case Intrinsic::loongarch_lasx_xvfsub_d:
7930 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
7931 N->getOperand(2));
7932 case Intrinsic::loongarch_lsx_vfmul_s:
7933 case Intrinsic::loongarch_lsx_vfmul_d:
7934 case Intrinsic::loongarch_lasx_xvfmul_s:
7935 case Intrinsic::loongarch_lasx_xvfmul_d:
7936 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
7937 N->getOperand(2));
7938 case Intrinsic::loongarch_lsx_vfdiv_s:
7939 case Intrinsic::loongarch_lsx_vfdiv_d:
7940 case Intrinsic::loongarch_lasx_xvfdiv_s:
7941 case Intrinsic::loongarch_lasx_xvfdiv_d:
7942 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
7943 N->getOperand(2));
7944 case Intrinsic::loongarch_lsx_vfmadd_s:
7945 case Intrinsic::loongarch_lsx_vfmadd_d:
7946 case Intrinsic::loongarch_lasx_xvfmadd_s:
7947 case Intrinsic::loongarch_lasx_xvfmadd_d:
7948 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
7949 N->getOperand(2), N->getOperand(3));
7950 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
7951 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
7952 N->getOperand(1), N->getOperand(2),
7953 legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
7954 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
7955 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
7956 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
7957 N->getOperand(1), N->getOperand(2),
7958 legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
7959 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
7960 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
7961 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
7962 N->getOperand(1), N->getOperand(2),
7963 legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
7964 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
7965 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
7966 N->getOperand(1), N->getOperand(2),
7967 legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
7968 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
7969 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
7970 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
7971 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
7972 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
7973 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
7974 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
7975 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
7976 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
7977 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
7978 N->getOperand(1)));
7979 case Intrinsic::loongarch_lsx_vreplve_b:
7980 case Intrinsic::loongarch_lsx_vreplve_h:
7981 case Intrinsic::loongarch_lsx_vreplve_w:
7982 case Intrinsic::loongarch_lsx_vreplve_d:
7983 case Intrinsic::loongarch_lasx_xvreplve_b:
7984 case Intrinsic::loongarch_lasx_xvreplve_h:
7985 case Intrinsic::loongarch_lasx_xvreplve_w:
7986 case Intrinsic::loongarch_lasx_xvreplve_d:
7987 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
7988 N->getOperand(1),
7989 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
7990 N->getOperand(2)));
7991 case Intrinsic::loongarch_lsx_vpickve2gr_b:
7992 if (!Subtarget.is64Bit())
7993 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
7994 break;
7995 case Intrinsic::loongarch_lsx_vpickve2gr_h:
7996 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
7997 if (!Subtarget.is64Bit())
7998 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
7999 break;
8000 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8001 if (!Subtarget.is64Bit())
8002 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8003 break;
8004 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8005 if (!Subtarget.is64Bit())
8006 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8007 break;
8008 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8009 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8010 if (!Subtarget.is64Bit())
8011 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8012 break;
8013 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8014 if (!Subtarget.is64Bit())
8015 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8016 break;
8017 case Intrinsic::loongarch_lsx_bz_b:
8018 case Intrinsic::loongarch_lsx_bz_h:
8019 case Intrinsic::loongarch_lsx_bz_w:
8020 case Intrinsic::loongarch_lsx_bz_d:
8021 case Intrinsic::loongarch_lasx_xbz_b:
8022 case Intrinsic::loongarch_lasx_xbz_h:
8023 case Intrinsic::loongarch_lasx_xbz_w:
8024 case Intrinsic::loongarch_lasx_xbz_d:
8025 if (!Subtarget.is64Bit())
8026 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8027 N->getOperand(1));
8028 break;
8029 case Intrinsic::loongarch_lsx_bz_v:
8030 case Intrinsic::loongarch_lasx_xbz_v:
8031 if (!Subtarget.is64Bit())
8032 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8033 N->getOperand(1));
8034 break;
8035 case Intrinsic::loongarch_lsx_bnz_b:
8036 case Intrinsic::loongarch_lsx_bnz_h:
8037 case Intrinsic::loongarch_lsx_bnz_w:
8038 case Intrinsic::loongarch_lsx_bnz_d:
8039 case Intrinsic::loongarch_lasx_xbnz_b:
8040 case Intrinsic::loongarch_lasx_xbnz_h:
8041 case Intrinsic::loongarch_lasx_xbnz_w:
8042 case Intrinsic::loongarch_lasx_xbnz_d:
8043 if (!Subtarget.is64Bit())
8044 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8045 N->getOperand(1));
8046 break;
8047 case Intrinsic::loongarch_lsx_bnz_v:
8048 case Intrinsic::loongarch_lasx_xbnz_v:
8049 if (!Subtarget.is64Bit())
8050 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8051 N->getOperand(1));
8052 break;
8053 case Intrinsic::loongarch_lasx_concat_128_s:
8054 case Intrinsic::loongarch_lasx_concat_128_d:
8055 case Intrinsic::loongarch_lasx_concat_128:
8056 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8057 N->getOperand(1), N->getOperand(2));
8058 }
8059 return SDValue();
8060}
8061
8064 const LoongArchSubtarget &Subtarget) {
8065 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8066 // conversion is unnecessary and can be replaced with the
8067 // MOVFR2GR_S_LA64 operand.
8068 SDValue Op0 = N->getOperand(0);
8069 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8070 return Op0.getOperand(0);
8071 return SDValue();
8072}
8073
8076 const LoongArchSubtarget &Subtarget) {
8077 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8078 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8079 // operand.
8080 SDValue Op0 = N->getOperand(0);
8081 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8082 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8083 "Unexpected value type!");
8084 return Op0.getOperand(0);
8085 }
8086 return SDValue();
8087}
8088
8089static SDValue
8092 MVT VT = N->getSimpleValueType(0);
8093 unsigned NumBits = VT.getScalarSizeInBits();
8094
8095 // Simplify the inputs.
8096 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8097 APInt DemandedMask(APInt::getAllOnes(NumBits));
8098 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8099 return SDValue(N, 0);
8100
8101 return SDValue();
8102}
8103
8104static SDValue
8107 const LoongArchSubtarget &Subtarget) {
8108 SDValue Op0 = N->getOperand(0);
8109 SDLoc DL(N);
8110
8111 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8112 // redundant. Instead, use BuildPairF64's operands directly.
8113 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8114 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8115
8116 if (Op0->isUndef()) {
8117 SDValue Lo = DAG.getUNDEF(MVT::i32);
8118 SDValue Hi = DAG.getUNDEF(MVT::i32);
8119 return DCI.CombineTo(N, Lo, Hi);
8120 }
8121
8122 // It's cheaper to materialise two 32-bit integers than to load a double
8123 // from the constant pool and transfer it to integer registers through the
8124 // stack.
8126 APInt V = C->getValueAPF().bitcastToAPInt();
8127 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8128 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8129 return DCI.CombineTo(N, Lo, Hi);
8130 }
8131
8132 return SDValue();
8133}
8134
8135/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8138 const LoongArchSubtarget &Subtarget) {
8139 SDValue N0 = N->getOperand(0);
8140 SDValue N1 = N->getOperand(1);
8141 MVT VT = N->getSimpleValueType(0);
8142 SDLoc DL(N);
8143
8144 // VANDN(undef, x) -> 0
8145 // VANDN(x, undef) -> 0
8146 if (N0.isUndef() || N1.isUndef())
8147 return DAG.getConstant(0, DL, VT);
8148
8149 // VANDN(0, x) -> x
8151 return N1;
8152
8153 // VANDN(x, 0) -> 0
8155 return DAG.getConstant(0, DL, VT);
8156
8157 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8159 return DAG.getNOT(DL, N0, VT);
8160
8161 // Turn VANDN back to AND if input is inverted.
8162 if (SDValue Not = isNOT(N0, DAG))
8163 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8164
8165 // Folds for better commutativity:
8166 if (N1->hasOneUse()) {
8167 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8168 if (SDValue Not = isNOT(N1, DAG))
8169 return DAG.getNOT(
8170 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8171
8172 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8173 // -> NOT(OR(x, SplatVector(-Imm))
8174 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8175 // gain benefits.
8176 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8177 N1.getOpcode() == ISD::BUILD_VECTOR) {
8178 if (SDValue SplatValue =
8179 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8180 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8181 return SDValue();
8182
8183 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8184 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8185 SDValue Not =
8186 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8187 return DAG.getNOT(
8188 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8189 VT);
8190 }
8191 }
8192 }
8193 }
8194
8195 return SDValue();
8196}
8197
8198static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8199 SDLoc DL(N);
8200 EVT VT = N->getValueType(0);
8201 SDValue Src = N->getOperand(0);
8202 EVT SrcVT = Src.getValueType();
8203
8204 unsigned DstElts = VT.getVectorNumElements();
8205 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8206 unsigned DstEltBits = VT.getScalarSizeInBits();
8207
8208 if (SrcEltBits >= DstEltBits)
8209 return SDValue();
8210
8211 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8212 MVT WidenSrcVT = MVT::getVectorVT(WidenEltVT, DstElts);
8213
8214 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8215 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8216}
8217
8218// Merge two 64 to 32 convert instructions into one,
8219// e.g.
8220// vffint.s.l $vr0, $vr1, $vr2
8221// will convert 4 si64 into 4 float at once.
8222// or
8223// vftintrz.w.d $vr0, $vr1, $vr2
8224// which will convert 4 double into 4 si32 at once.
8225// also deal with their 256-bits LASX version.
8226static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8227 unsigned BlockBits) {
8228 SDLoc DL(N);
8229 MVT DstVT = N->getSimpleValueType(0);
8230 SDValue Src = N->getOperand(0);
8231 MVT SrcVT = Src.getSimpleValueType();
8232 unsigned SrcBits = SrcVT.getSizeInBits();
8233
8235 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8236 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8237 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8238 Src.getOperand(0).getValueType() == BlockVT) {
8239 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8240 Blocks.push_back(Src.getOperand(i));
8241 } else if (SrcBits > BlockBits) {
8242 // Wider than one register: extract each BlockBits-wide sub-vector.
8243 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8244 Blocks.push_back(
8245 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8246 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8247 } else {
8248 BlockBits = SrcBits;
8249 Blocks.push_back(Src);
8250 }
8251
8252 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8253 BlockBits / DstVT.getScalarSizeInBits());
8255 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8256 SDValue Lo = Blocks[i];
8257 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8258 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8259
8260 if (BlockBits == 256) {
8261 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8262 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8263 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8264 Res = DAG.getBitcast(NativeVecVT, Res);
8265 }
8266
8267 Parts.push_back(Res);
8268 }
8269
8270 if (Blocks.size() == 1)
8271 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8272 DAG.getVectorIdxConstant(0, DL));
8273 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8274}
8275
8278 const LoongArchSubtarget &Subtarget) {
8279 SDLoc DL(N);
8280 EVT VT = N->getValueType(0);
8281 SDValue Src = N->getOperand(0);
8282 EVT SrcVT = Src.getValueType();
8283
8284 if (VT.isVector()) {
8285 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8286 unsigned DstEltBits = VT.getScalarSizeInBits();
8287 unsigned NumElts = VT.getVectorNumElements();
8288 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8289
8290 // Sign-extend src to avoid scalarization.
8291 if (SrcEltBits <= DstEltBits)
8292 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8293
8294 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8295 return SDValue();
8296
8297 if (!SrcVT.isSimple() || !VT.isSimple())
8298 return SDValue();
8299
8300 // Combine [x]vffint.s.l for vector si64 to float conversion.
8301 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8302 }
8303
8304 if (VT != MVT::f32 && VT != MVT::f64)
8305 return SDValue();
8306 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8307 return SDValue();
8308 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8309 return SDValue();
8310
8311 // Only optimize when the source and destination types have the same width.
8312 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8313 return SDValue();
8314
8315 // If the result of an integer load is only used by an integer-to-float
8316 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8317 // (movgr2fr) instruction.
8318 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8319 // Do not change the width of a volatile load. This condition check is
8320 // inspired by AArch64.
8321 !cast<LoadSDNode>(Src)->isVolatile()) {
8322 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8323 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8324 LN0->getPointerInfo(), LN0->getAlign(),
8325 LN0->getMemOperand()->getFlags());
8326
8327 // Make sure successors of the original load stay after it by updating them
8328 // to use the new Chain.
8329 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8330 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8331 }
8332
8333 return SDValue();
8334}
8335
8338 const LoongArchSubtarget &Subtarget) {
8339 SDLoc DL(N);
8340 EVT VT = N->getValueType(0);
8341
8342 // Zero-extend src to avoid scalarization.
8343 if (VT.isVector())
8344 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8345
8346 return SDValue();
8347}
8348
8349// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
8350// For example:
8351// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
8352// Can be combined into:
8353// v4i32 = VFTINTRZ_W_D v2f64. v2f64
8356 const LoongArchSubtarget &Subtarget) {
8357 if (!Subtarget.hasExtLSX())
8358 return SDValue();
8359
8360 SDLoc DL(N);
8361 EVT DstVT = N->getValueType(0);
8362 SDValue Src = N->getOperand(0);
8363 EVT SrcVT = Src.getValueType();
8364 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
8365
8366 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
8367 return SDValue();
8368
8369 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8370 unsigned SrcBits = SrcVT.getSizeInBits();
8371 unsigned DstEltBits = DstVT.getScalarSizeInBits();
8372 unsigned NumElts = DstVT.getVectorNumElements();
8373 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8374
8375 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
8376 return SDValue();
8377
8378 if (SrcBits % BlockBits != 0 && SrcBits != 128)
8379 return SDValue();
8380
8381 if (DstEltBits < 32) {
8382 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
8383 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
8384 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
8385 }
8386
8387 if (SrcEltBits != 64 || DstEltBits != 32)
8388 return SDValue();
8389
8390 if (!IsSigned) {
8391 // LASX already has pattern for double convert to uint32.
8392 if (Subtarget.hasExtLASX())
8393 return SDValue();
8394 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
8395 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
8396 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
8397 }
8398
8399 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
8400}
8401
8402// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
8403// logical operations, like in the example below.
8404// or (and (truncate x, truncate y)),
8405// (xor (truncate z, build_vector (constants)))
8406// Given a target type \p VT, we generate
8407// or (and x, y), (xor z, zext(build_vector (constants)))
8408// given x, y and z are of type \p VT. We can do so, if operands are either
8409// truncates from VT types, the second operand is a vector of constants, can
8410// be recursively promoted or is an existing extension we can extend further.
8412 SelectionDAG &DAG,
8413 const LoongArchSubtarget &Subtarget,
8414 unsigned Depth) {
8415 // Limit recursion to avoid excessive compile times.
8417 return SDValue();
8418
8419 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
8420 return SDValue();
8421
8422 SDValue N0 = N.getOperand(0);
8423 SDValue N1 = N.getOperand(1);
8424
8425 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8426 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
8427 return SDValue();
8428
8429 if (SDValue NN0 =
8430 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
8431 N0 = NN0;
8432 else {
8433 // The left side has to be a 'trunc'.
8434 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
8435 N0.getOperand(0).getValueType() == VT;
8436 if (LHSTrunc)
8437 N0 = N0.getOperand(0);
8438 else
8439 return SDValue();
8440 }
8441
8442 if (SDValue NN1 =
8443 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
8444 N1 = NN1;
8445 else {
8446 // The right side has to be a 'trunc', a (foldable) constant or an
8447 // existing extension we can extend further.
8448 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
8449 N1.getOperand(0).getValueType() == VT;
8450 if (RHSTrunc)
8451 N1 = N1.getOperand(0);
8452 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
8453 Subtarget.hasExtLASX() && N1.hasOneUse())
8454 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
8455 // On 32-bit platform, i64 is an illegal integer scalar type, and
8456 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
8457 // future.
8458 else if (SDValue Cst =
8460 N1 = Cst;
8461 else
8462 return SDValue();
8463 }
8464
8465 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
8466}
8467
8468// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
8469// is LSX-sized register. In most cases we actually compare or select LASX-sized
8470// registers and mixing the two types creates horrible code. This method
8471// optimizes some of the transition sequences.
8473 SelectionDAG &DAG,
8474 const LoongArchSubtarget &Subtarget) {
8475 EVT VT = N.getValueType();
8476 assert(VT.isVector() && "Expected vector type");
8477 assert((N.getOpcode() == ISD::ANY_EXTEND ||
8478 N.getOpcode() == ISD::ZERO_EXTEND ||
8479 N.getOpcode() == ISD::SIGN_EXTEND) &&
8480 "Invalid Node");
8481
8482 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
8483 return SDValue();
8484
8485 SDValue Narrow = N.getOperand(0);
8486 EVT NarrowVT = Narrow.getValueType();
8487
8488 // Generate the wide operation.
8489 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
8490 if (!Op)
8491 return SDValue();
8492 switch (N.getOpcode()) {
8493 default:
8494 llvm_unreachable("Unexpected opcode");
8495 case ISD::ANY_EXTEND:
8496 return Op;
8497 case ISD::ZERO_EXTEND:
8498 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
8499 case ISD::SIGN_EXTEND:
8500 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
8501 DAG.getValueType(NarrowVT));
8502 }
8503}
8504
8507 const LoongArchSubtarget &Subtarget) {
8508 EVT VT = N->getValueType(0);
8509 SDLoc DL(N);
8510
8511 if (VT.isVector()) {
8512 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
8513 return R;
8514
8515 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
8516 if (N->getOpcode() == ISD::SIGN_EXTEND)
8517 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
8518 if (N->getOpcode() == ISD::ZERO_EXTEND)
8519 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
8520 }
8521 }
8522
8523 return SDValue();
8524}
8525
8526static SDValue
8529 const LoongArchSubtarget &Subtarget) {
8530 SDLoc DL(N);
8531 EVT VT = N->getValueType(0);
8532
8533 if (VT.isVector() && N->getNumOperands() == 2)
8534 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
8535 return R;
8536
8537 return SDValue();
8538}
8539
8542 const LoongArchSubtarget &Subtarget) {
8543 if (DCI.isBeforeLegalizeOps())
8544 return SDValue();
8545
8546 EVT VT = N->getValueType(0);
8547 if (!VT.isVector())
8548 return SDValue();
8549
8550 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
8551 return SDValue();
8552
8553 EVT EltVT = VT.getVectorElementType();
8554 if (!EltVT.isInteger())
8555 return SDValue();
8556
8557 SDValue Cond = N->getOperand(0);
8558 SDValue TrueVal = N->getOperand(1);
8559 SDValue FalseVal = N->getOperand(2);
8560
8561 // match:
8562 //
8563 // vselect (setcc shift, 0, seteq),
8564 // x,
8565 // rounded_shift
8566
8567 if (Cond.getOpcode() != ISD::SETCC)
8568 return SDValue();
8569
8570 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
8571 return SDValue();
8572
8573 auto *CC = cast<CondCodeSDNode>(Cond.getOperand(2));
8574 if (CC->get() != ISD::SETEQ)
8575 return SDValue();
8576
8577 SDValue Shift = Cond.getOperand(0);
8578
8579 // True branch must be original value:
8580 //
8581 // vselect cond, x, ...
8582
8583 SDValue X = TrueVal;
8584
8585 // Now match rounded shift pattern:
8586 //
8587 // add
8588 // (and
8589 // (srl X, shift-1)
8590 // 1)
8591 // (srl/sra X, shift)
8592
8593 if (FalseVal.getOpcode() != ISD::ADD)
8594 return SDValue();
8595
8596 SDValue Add0 = FalseVal.getOperand(0);
8597 SDValue Add1 = FalseVal.getOperand(1);
8598 SDValue And;
8599 SDValue Shr;
8600
8601 if (Add0.getOpcode() == ISD::AND) {
8602 And = Add0;
8603 Shr = Add1;
8604 } else if (Add1.getOpcode() == ISD::AND) {
8605 And = Add1;
8606 Shr = Add0;
8607 } else {
8608 return SDValue();
8609 }
8610
8611 // match:
8612 //
8613 // srl/sra X, shift
8614
8615 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
8616 return SDValue();
8617
8618 if (Shr.getOperand(0) != X)
8619 return SDValue();
8620
8621 if (Shr.getOperand(1) != Shift)
8622 return SDValue();
8623
8624 // match:
8625 //
8626 // and
8627 // (srl X, shift-1)
8628 // 1
8629
8630 SDValue Srl = And.getOperand(0);
8631 SDValue One = And.getOperand(1);
8632 APInt SplatVal;
8633
8634 if (Srl.getOpcode() != ISD::SRL)
8635 return SDValue();
8636
8637 One = peekThroughBitcasts(One);
8638 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
8639 return SDValue();
8640
8641 if (SplatVal != 1)
8642 return SDValue();
8643
8644 if (Srl.getOperand(0) != X)
8645 return SDValue();
8646
8647 // match:
8648 //
8649 // shift-1
8650
8651 SDValue ShiftMinus1 = Srl.getOperand(1);
8652
8653 if (ShiftMinus1.getOpcode() != ISD::ADD)
8654 return SDValue();
8655
8656 if (ShiftMinus1.getOperand(0) != Shift)
8657 return SDValue();
8658
8660 return SDValue();
8661
8662 // We matched a rounded right shift pattern and can lower it
8663 // to a single vector rounded shift instruction.
8664
8665 SDLoc DL(N);
8666 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
8667 : LoongArchISD::VSRAR,
8668 DL, VT, X, Shift);
8669}
8670
8672 DAGCombinerInfo &DCI) const {
8673 SelectionDAG &DAG = DCI.DAG;
8674 switch (N->getOpcode()) {
8675 default:
8676 break;
8677 case ISD::ADD:
8678 return performADDCombine(N, DAG, DCI, Subtarget);
8679 case ISD::AND:
8680 return performANDCombine(N, DAG, DCI, Subtarget);
8681 case ISD::OR:
8682 return performORCombine(N, DAG, DCI, Subtarget);
8683 case ISD::SETCC:
8684 return performSETCCCombine(N, DAG, DCI, Subtarget);
8685 case ISD::SHL:
8686 return performSHLCombine(N, DAG, DCI, Subtarget);
8687 case ISD::SRL:
8688 return performSRLCombine(N, DAG, DCI, Subtarget);
8689 case ISD::SUB:
8690 return performSUBCombine(N, DAG, DCI, Subtarget);
8691 case ISD::BITCAST:
8692 return performBITCASTCombine(N, DAG, DCI, Subtarget);
8693 case ISD::ANY_EXTEND:
8694 case ISD::ZERO_EXTEND:
8695 case ISD::SIGN_EXTEND:
8696 return performEXTENDCombine(N, DAG, DCI, Subtarget);
8697 case ISD::SINT_TO_FP:
8698 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8699 case ISD::UINT_TO_FP:
8700 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8701 case ISD::FP_TO_SINT:
8702 case ISD::FP_TO_UINT:
8703 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
8704 case LoongArchISD::BITREV_W:
8705 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
8706 case LoongArchISD::BR_CC:
8707 return performBR_CCCombine(N, DAG, DCI, Subtarget);
8708 case LoongArchISD::SELECT_CC:
8709 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
8711 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
8712 case LoongArchISD::MOVGR2FR_W_LA64:
8713 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
8714 case LoongArchISD::MOVFR2GR_S_LA64:
8715 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
8716 case LoongArchISD::CRC_W_B_W:
8717 case LoongArchISD::CRC_W_H_W:
8718 case LoongArchISD::CRCC_W_B_W:
8719 case LoongArchISD::CRCC_W_H_W:
8720 case LoongArchISD::VMSKLTZ:
8721 case LoongArchISD::XVMSKLTZ:
8722 return performDemandedBitsCombine(N, DAG, DCI);
8723 case LoongArchISD::SPLIT_PAIR_F64:
8724 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
8725 case LoongArchISD::VANDN:
8726 return performVANDNCombine(N, DAG, DCI, Subtarget);
8728 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
8729 case ISD::VSELECT:
8730 return performVSELECTCombine(N, DAG, DCI, Subtarget);
8731 case LoongArchISD::VPACKEV:
8732 case LoongArchISD::VPERMI:
8733 if (SDValue Result =
8734 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
8735 return Result;
8736 }
8737 return SDValue();
8738}
8739
8742 if (!ZeroDivCheck)
8743 return MBB;
8744
8745 // Build instructions:
8746 // MBB:
8747 // div(or mod) $dst, $dividend, $divisor
8748 // bne $divisor, $zero, SinkMBB
8749 // BreakMBB:
8750 // break 7 // BRK_DIVZERO
8751 // SinkMBB:
8752 // fallthrough
8753 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
8754 MachineFunction::iterator It = ++MBB->getIterator();
8755 MachineFunction *MF = MBB->getParent();
8756 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
8757 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
8758 MF->insert(It, BreakMBB);
8759 MF->insert(It, SinkMBB);
8760
8761 // Transfer the remainder of MBB and its successor edges to SinkMBB.
8762 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
8763 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
8764
8765 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
8766 DebugLoc DL = MI.getDebugLoc();
8767 MachineOperand &Divisor = MI.getOperand(2);
8768 Register DivisorReg = Divisor.getReg();
8769
8770 // MBB:
8771 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
8772 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
8773 .addReg(LoongArch::R0)
8774 .addMBB(SinkMBB);
8775 MBB->addSuccessor(BreakMBB);
8776 MBB->addSuccessor(SinkMBB);
8777
8778 // BreakMBB:
8779 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
8780 // definition of BRK_DIVZERO.
8781 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
8782 BreakMBB->addSuccessor(SinkMBB);
8783
8784 // Clear Divisor's kill flag.
8785 Divisor.setIsKill(false);
8786
8787 return SinkMBB;
8788}
8789
8790static MachineBasicBlock *
8792 const LoongArchSubtarget &Subtarget) {
8793 unsigned CondOpc;
8794 switch (MI.getOpcode()) {
8795 default:
8796 llvm_unreachable("Unexpected opcode");
8797 case LoongArch::PseudoVBZ:
8798 CondOpc = LoongArch::VSETEQZ_V;
8799 break;
8800 case LoongArch::PseudoVBZ_B:
8801 CondOpc = LoongArch::VSETANYEQZ_B;
8802 break;
8803 case LoongArch::PseudoVBZ_H:
8804 CondOpc = LoongArch::VSETANYEQZ_H;
8805 break;
8806 case LoongArch::PseudoVBZ_W:
8807 CondOpc = LoongArch::VSETANYEQZ_W;
8808 break;
8809 case LoongArch::PseudoVBZ_D:
8810 CondOpc = LoongArch::VSETANYEQZ_D;
8811 break;
8812 case LoongArch::PseudoVBNZ:
8813 CondOpc = LoongArch::VSETNEZ_V;
8814 break;
8815 case LoongArch::PseudoVBNZ_B:
8816 CondOpc = LoongArch::VSETALLNEZ_B;
8817 break;
8818 case LoongArch::PseudoVBNZ_H:
8819 CondOpc = LoongArch::VSETALLNEZ_H;
8820 break;
8821 case LoongArch::PseudoVBNZ_W:
8822 CondOpc = LoongArch::VSETALLNEZ_W;
8823 break;
8824 case LoongArch::PseudoVBNZ_D:
8825 CondOpc = LoongArch::VSETALLNEZ_D;
8826 break;
8827 case LoongArch::PseudoXVBZ:
8828 CondOpc = LoongArch::XVSETEQZ_V;
8829 break;
8830 case LoongArch::PseudoXVBZ_B:
8831 CondOpc = LoongArch::XVSETANYEQZ_B;
8832 break;
8833 case LoongArch::PseudoXVBZ_H:
8834 CondOpc = LoongArch::XVSETANYEQZ_H;
8835 break;
8836 case LoongArch::PseudoXVBZ_W:
8837 CondOpc = LoongArch::XVSETANYEQZ_W;
8838 break;
8839 case LoongArch::PseudoXVBZ_D:
8840 CondOpc = LoongArch::XVSETANYEQZ_D;
8841 break;
8842 case LoongArch::PseudoXVBNZ:
8843 CondOpc = LoongArch::XVSETNEZ_V;
8844 break;
8845 case LoongArch::PseudoXVBNZ_B:
8846 CondOpc = LoongArch::XVSETALLNEZ_B;
8847 break;
8848 case LoongArch::PseudoXVBNZ_H:
8849 CondOpc = LoongArch::XVSETALLNEZ_H;
8850 break;
8851 case LoongArch::PseudoXVBNZ_W:
8852 CondOpc = LoongArch::XVSETALLNEZ_W;
8853 break;
8854 case LoongArch::PseudoXVBNZ_D:
8855 CondOpc = LoongArch::XVSETALLNEZ_D;
8856 break;
8857 }
8858
8859 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
8860 const BasicBlock *LLVM_BB = BB->getBasicBlock();
8861 DebugLoc DL = MI.getDebugLoc();
8864
8865 MachineFunction *F = BB->getParent();
8866 MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
8867 MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
8868 MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
8869
8870 F->insert(It, FalseBB);
8871 F->insert(It, TrueBB);
8872 F->insert(It, SinkBB);
8873
8874 // Transfer the remainder of MBB and its successor edges to Sink.
8875 SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
8877
8878 // Insert the real instruction to BB.
8879 Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
8880 BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
8881
8882 // Insert branch.
8883 BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
8884 BB->addSuccessor(FalseBB);
8885 BB->addSuccessor(TrueBB);
8886
8887 // FalseBB.
8888 Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
8889 BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
8890 .addReg(LoongArch::R0)
8891 .addImm(0);
8892 BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
8893 FalseBB->addSuccessor(SinkBB);
8894
8895 // TrueBB.
8896 Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
8897 BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
8898 .addReg(LoongArch::R0)
8899 .addImm(1);
8900 TrueBB->addSuccessor(SinkBB);
8901
8902 // SinkBB: merge the results.
8903 BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
8904 MI.getOperand(0).getReg())
8905 .addReg(RD1)
8906 .addMBB(FalseBB)
8907 .addReg(RD2)
8908 .addMBB(TrueBB);
8909
8910 // The pseudo instruction is gone now.
8911 MI.eraseFromParent();
8912 return SinkBB;
8913}
8914
8915static MachineBasicBlock *
8917 const LoongArchSubtarget &Subtarget) {
8918 unsigned InsOp;
8919 unsigned BroadcastOp;
8920 unsigned HalfSize;
8921 switch (MI.getOpcode()) {
8922 default:
8923 llvm_unreachable("Unexpected opcode");
8924 case LoongArch::PseudoXVINSGR2VR_B:
8925 HalfSize = 16;
8926 BroadcastOp = LoongArch::XVREPLGR2VR_B;
8927 InsOp = LoongArch::XVEXTRINS_B;
8928 break;
8929 case LoongArch::PseudoXVINSGR2VR_H:
8930 HalfSize = 8;
8931 BroadcastOp = LoongArch::XVREPLGR2VR_H;
8932 InsOp = LoongArch::XVEXTRINS_H;
8933 break;
8934 }
8935 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
8936 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
8937 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
8938 DebugLoc DL = MI.getDebugLoc();
8940 // XDst = vector_insert XSrc, Elt, Idx
8941 Register XDst = MI.getOperand(0).getReg();
8942 Register XSrc = MI.getOperand(1).getReg();
8943 Register Elt = MI.getOperand(2).getReg();
8944 unsigned Idx = MI.getOperand(3).getImm();
8945
8946 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
8947 Idx < HalfSize) {
8948 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
8949 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
8950
8951 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
8952 .addReg(XSrc, {}, LoongArch::sub_128);
8953 BuildMI(*BB, MI, DL,
8954 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
8955 : LoongArch::VINSGR2VR_B),
8956 ScratchSubReg2)
8957 .addReg(ScratchSubReg1)
8958 .addReg(Elt)
8959 .addImm(Idx);
8960
8961 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
8962 .addReg(ScratchSubReg2)
8963 .addImm(LoongArch::sub_128);
8964 } else {
8965 Register ScratchReg1 = MRI.createVirtualRegister(RC);
8966 Register ScratchReg2 = MRI.createVirtualRegister(RC);
8967
8968 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
8969
8970 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
8971 .addReg(ScratchReg1)
8972 .addReg(XSrc)
8973 .addImm(Idx >= HalfSize ? 48 : 18);
8974
8975 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
8976 .addReg(XSrc)
8977 .addReg(ScratchReg2)
8978 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
8979 }
8980
8981 MI.eraseFromParent();
8982 return BB;
8983}
8984
8987 const LoongArchSubtarget &Subtarget) {
8988 assert(Subtarget.hasExtLSX());
8989 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
8990 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
8991 DebugLoc DL = MI.getDebugLoc();
8993 Register Dst = MI.getOperand(0).getReg();
8994 Register Src = MI.getOperand(1).getReg();
8995
8996 unsigned BroadcastOp, CTOp, PickOp;
8997 switch (MI.getOpcode()) {
8998 default:
8999 llvm_unreachable("Unexpected opcode");
9000 case LoongArch::PseudoCTPOP_B:
9001 BroadcastOp = LoongArch::VREPLGR2VR_B;
9002 CTOp = LoongArch::VPCNT_B;
9003 PickOp = LoongArch::VPICKVE2GR_B;
9004 break;
9005 case LoongArch::PseudoCTPOP_H:
9006 case LoongArch::PseudoCTPOP_H_LA32:
9007 BroadcastOp = LoongArch::VREPLGR2VR_H;
9008 CTOp = LoongArch::VPCNT_H;
9009 PickOp = LoongArch::VPICKVE2GR_H;
9010 break;
9011 case LoongArch::PseudoCTPOP_W:
9012 case LoongArch::PseudoCTPOP_W_LA32:
9013 BroadcastOp = LoongArch::VREPLGR2VR_W;
9014 CTOp = LoongArch::VPCNT_W;
9015 PickOp = LoongArch::VPICKVE2GR_W;
9016 break;
9017 case LoongArch::PseudoCTPOP_D:
9018 BroadcastOp = LoongArch::VREPLGR2VR_D;
9019 CTOp = LoongArch::VPCNT_D;
9020 PickOp = LoongArch::VPICKVE2GR_D;
9021 break;
9022 }
9023
9024 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9025 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9026 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9027 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9028 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9029
9030 MI.eraseFromParent();
9031 return BB;
9032}
9033
9034static MachineBasicBlock *
9036 const LoongArchSubtarget &Subtarget) {
9037 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9038 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9039 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9041 Register Dst = MI.getOperand(0).getReg();
9042 Register Src = MI.getOperand(1).getReg();
9043 DebugLoc DL = MI.getDebugLoc();
9044 unsigned EleBits = 8;
9045 unsigned NotOpc = 0;
9046 unsigned MskOpc;
9047
9048 switch (MI.getOpcode()) {
9049 default:
9050 llvm_unreachable("Unexpected opcode");
9051 case LoongArch::PseudoVMSKLTZ_B:
9052 MskOpc = LoongArch::VMSKLTZ_B;
9053 break;
9054 case LoongArch::PseudoVMSKLTZ_H:
9055 MskOpc = LoongArch::VMSKLTZ_H;
9056 EleBits = 16;
9057 break;
9058 case LoongArch::PseudoVMSKLTZ_W:
9059 MskOpc = LoongArch::VMSKLTZ_W;
9060 EleBits = 32;
9061 break;
9062 case LoongArch::PseudoVMSKLTZ_D:
9063 MskOpc = LoongArch::VMSKLTZ_D;
9064 EleBits = 64;
9065 break;
9066 case LoongArch::PseudoVMSKGEZ_B:
9067 MskOpc = LoongArch::VMSKGEZ_B;
9068 break;
9069 case LoongArch::PseudoVMSKEQZ_B:
9070 MskOpc = LoongArch::VMSKNZ_B;
9071 NotOpc = LoongArch::VNOR_V;
9072 break;
9073 case LoongArch::PseudoVMSKNEZ_B:
9074 MskOpc = LoongArch::VMSKNZ_B;
9075 break;
9076 case LoongArch::PseudoXVMSKLTZ_B:
9077 MskOpc = LoongArch::XVMSKLTZ_B;
9078 RC = &LoongArch::LASX256RegClass;
9079 break;
9080 case LoongArch::PseudoXVMSKLTZ_H:
9081 MskOpc = LoongArch::XVMSKLTZ_H;
9082 RC = &LoongArch::LASX256RegClass;
9083 EleBits = 16;
9084 break;
9085 case LoongArch::PseudoXVMSKLTZ_W:
9086 MskOpc = LoongArch::XVMSKLTZ_W;
9087 RC = &LoongArch::LASX256RegClass;
9088 EleBits = 32;
9089 break;
9090 case LoongArch::PseudoXVMSKLTZ_D:
9091 MskOpc = LoongArch::XVMSKLTZ_D;
9092 RC = &LoongArch::LASX256RegClass;
9093 EleBits = 64;
9094 break;
9095 case LoongArch::PseudoXVMSKGEZ_B:
9096 MskOpc = LoongArch::XVMSKGEZ_B;
9097 RC = &LoongArch::LASX256RegClass;
9098 break;
9099 case LoongArch::PseudoXVMSKEQZ_B:
9100 MskOpc = LoongArch::XVMSKNZ_B;
9101 NotOpc = LoongArch::XVNOR_V;
9102 RC = &LoongArch::LASX256RegClass;
9103 break;
9104 case LoongArch::PseudoXVMSKNEZ_B:
9105 MskOpc = LoongArch::XVMSKNZ_B;
9106 RC = &LoongArch::LASX256RegClass;
9107 break;
9108 }
9109
9110 Register Msk = MRI.createVirtualRegister(RC);
9111 if (NotOpc) {
9112 Register Tmp = MRI.createVirtualRegister(RC);
9113 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9114 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk)
9115 .addReg(Tmp, RegState::Kill)
9116 .addReg(Tmp, RegState::Kill);
9117 } else {
9118 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9119 }
9120
9121 if (TRI->getRegSizeInBits(*RC) > 128) {
9122 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9123 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9124 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9125 .addReg(Msk)
9126 .addImm(0);
9127 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9128 .addReg(Msk, RegState::Kill)
9129 .addImm(4);
9130 BuildMI(*BB, MI, DL,
9131 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9132 : LoongArch::BSTRINS_W),
9133 Dst)
9136 .addImm(256 / EleBits - 1)
9137 .addImm(128 / EleBits);
9138 } else {
9139 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9140 .addReg(Msk, RegState::Kill)
9141 .addImm(0);
9142 }
9143
9144 MI.eraseFromParent();
9145 return BB;
9146}
9147
9148static MachineBasicBlock *
9150 const LoongArchSubtarget &Subtarget) {
9151 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9152 "Unexpected instruction");
9153
9154 MachineFunction &MF = *BB->getParent();
9155 DebugLoc DL = MI.getDebugLoc();
9157 Register LoReg = MI.getOperand(0).getReg();
9158 Register HiReg = MI.getOperand(1).getReg();
9159 Register SrcReg = MI.getOperand(2).getReg();
9160
9161 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9162 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9163 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9164 MI.eraseFromParent(); // The pseudo instruction is gone now.
9165 return BB;
9166}
9167
9168static MachineBasicBlock *
9170 const LoongArchSubtarget &Subtarget) {
9171 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9172 "Unexpected instruction");
9173
9174 MachineFunction &MF = *BB->getParent();
9175 DebugLoc DL = MI.getDebugLoc();
9178 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9179 Register DstReg = MI.getOperand(0).getReg();
9180 Register LoReg = MI.getOperand(1).getReg();
9181 Register HiReg = MI.getOperand(2).getReg();
9182
9183 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
9184 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
9185 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
9186 .addReg(TmpReg, RegState::Kill)
9187 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
9188 MI.eraseFromParent(); // The pseudo instruction is gone now.
9189 return BB;
9190}
9191
9193 switch (MI.getOpcode()) {
9194 default:
9195 return false;
9196 case LoongArch::Select_GPR_Using_CC_GPR:
9197 return true;
9198 }
9199}
9200
9201static MachineBasicBlock *
9203 const LoongArchSubtarget &Subtarget) {
9204 // To "insert" Select_* instructions, we actually have to insert the triangle
9205 // control-flow pattern. The incoming instructions know the destination vreg
9206 // to set, the condition code register to branch on, the true/false values to
9207 // select between, and the condcode to use to select the appropriate branch.
9208 //
9209 // We produce the following control flow:
9210 // HeadMBB
9211 // | \
9212 // | IfFalseMBB
9213 // | /
9214 // TailMBB
9215 //
9216 // When we find a sequence of selects we attempt to optimize their emission
9217 // by sharing the control flow. Currently we only handle cases where we have
9218 // multiple selects with the exact same condition (same LHS, RHS and CC).
9219 // The selects may be interleaved with other instructions if the other
9220 // instructions meet some requirements we deem safe:
9221 // - They are not pseudo instructions.
9222 // - They are debug instructions. Otherwise,
9223 // - They do not have side-effects, do not access memory and their inputs do
9224 // not depend on the results of the select pseudo-instructions.
9225 // The TrueV/FalseV operands of the selects cannot depend on the result of
9226 // previous selects in the sequence.
9227 // These conditions could be further relaxed. See the X86 target for a
9228 // related approach and more information.
9229
9230 Register LHS = MI.getOperand(1).getReg();
9231 Register RHS;
9232 if (MI.getOperand(2).isReg())
9233 RHS = MI.getOperand(2).getReg();
9234 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
9235
9236 SmallVector<MachineInstr *, 4> SelectDebugValues;
9237 SmallSet<Register, 4> SelectDests;
9238 SelectDests.insert(MI.getOperand(0).getReg());
9239
9240 MachineInstr *LastSelectPseudo = &MI;
9241 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
9242 SequenceMBBI != E; ++SequenceMBBI) {
9243 if (SequenceMBBI->isDebugInstr())
9244 continue;
9245 if (isSelectPseudo(*SequenceMBBI)) {
9246 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
9247 !SequenceMBBI->getOperand(2).isReg() ||
9248 SequenceMBBI->getOperand(2).getReg() != RHS ||
9249 SequenceMBBI->getOperand(3).getImm() != CC ||
9250 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
9251 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
9252 break;
9253 LastSelectPseudo = &*SequenceMBBI;
9254 SequenceMBBI->collectDebugValues(SelectDebugValues);
9255 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
9256 continue;
9257 }
9258 if (SequenceMBBI->hasUnmodeledSideEffects() ||
9259 SequenceMBBI->mayLoadOrStore() ||
9260 SequenceMBBI->usesCustomInsertionHook())
9261 break;
9262 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
9263 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
9264 }))
9265 break;
9266 }
9267
9268 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
9269 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9270 DebugLoc DL = MI.getDebugLoc();
9272
9273 MachineBasicBlock *HeadMBB = BB;
9274 MachineFunction *F = BB->getParent();
9275 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
9276 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
9277
9278 F->insert(I, IfFalseMBB);
9279 F->insert(I, TailMBB);
9280
9281 // Set the call frame size on entry to the new basic blocks.
9282 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
9283 IfFalseMBB->setCallFrameSize(CallFrameSize);
9284 TailMBB->setCallFrameSize(CallFrameSize);
9285
9286 // Transfer debug instructions associated with the selects to TailMBB.
9287 for (MachineInstr *DebugInstr : SelectDebugValues) {
9288 TailMBB->push_back(DebugInstr->removeFromParent());
9289 }
9290
9291 // Move all instructions after the sequence to TailMBB.
9292 TailMBB->splice(TailMBB->end(), HeadMBB,
9293 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
9294 // Update machine-CFG edges by transferring all successors of the current
9295 // block to the new block which will contain the Phi nodes for the selects.
9296 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
9297 // Set the successors for HeadMBB.
9298 HeadMBB->addSuccessor(IfFalseMBB);
9299 HeadMBB->addSuccessor(TailMBB);
9300
9301 // Insert appropriate branch.
9302 if (MI.getOperand(2).isImm())
9303 BuildMI(HeadMBB, DL, TII.get(CC))
9304 .addReg(LHS)
9305 .addImm(MI.getOperand(2).getImm())
9306 .addMBB(TailMBB);
9307 else
9308 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
9309
9310 // IfFalseMBB just falls through to TailMBB.
9311 IfFalseMBB->addSuccessor(TailMBB);
9312
9313 // Create PHIs for all of the select pseudo-instructions.
9314 auto SelectMBBI = MI.getIterator();
9315 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
9316 auto InsertionPoint = TailMBB->begin();
9317 while (SelectMBBI != SelectEnd) {
9318 auto Next = std::next(SelectMBBI);
9319 if (isSelectPseudo(*SelectMBBI)) {
9320 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
9321 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
9322 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
9323 .addReg(SelectMBBI->getOperand(4).getReg())
9324 .addMBB(HeadMBB)
9325 .addReg(SelectMBBI->getOperand(5).getReg())
9326 .addMBB(IfFalseMBB);
9327 SelectMBBI->eraseFromParent();
9328 }
9329 SelectMBBI = Next;
9330 }
9331
9332 F->getProperties().resetNoPHIs();
9333 return TailMBB;
9334}
9335
9336MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
9337 MachineInstr &MI, MachineBasicBlock *BB) const {
9338 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9339 DebugLoc DL = MI.getDebugLoc();
9340
9341 switch (MI.getOpcode()) {
9342 default:
9343 llvm_unreachable("Unexpected instr type to insert");
9344 case LoongArch::DIV_W:
9345 case LoongArch::DIV_WU:
9346 case LoongArch::MOD_W:
9347 case LoongArch::MOD_WU:
9348 case LoongArch::DIV_D:
9349 case LoongArch::DIV_DU:
9350 case LoongArch::MOD_D:
9351 case LoongArch::MOD_DU:
9352 return insertDivByZeroTrap(MI, BB);
9353 break;
9354 case LoongArch::WRFCSR: {
9355 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
9356 LoongArch::FCSR0 + MI.getOperand(0).getImm())
9357 .addReg(MI.getOperand(1).getReg());
9358 MI.eraseFromParent();
9359 return BB;
9360 }
9361 case LoongArch::RDFCSR: {
9362 MachineInstr *ReadFCSR =
9363 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
9364 MI.getOperand(0).getReg())
9365 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
9366 ReadFCSR->getOperand(1).setIsUndef();
9367 MI.eraseFromParent();
9368 return BB;
9369 }
9370 case LoongArch::Select_GPR_Using_CC_GPR:
9371 return emitSelectPseudo(MI, BB, Subtarget);
9372 case LoongArch::BuildPairF64Pseudo:
9373 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
9374 case LoongArch::SplitPairF64Pseudo:
9375 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
9376 case LoongArch::PseudoVBZ:
9377 case LoongArch::PseudoVBZ_B:
9378 case LoongArch::PseudoVBZ_H:
9379 case LoongArch::PseudoVBZ_W:
9380 case LoongArch::PseudoVBZ_D:
9381 case LoongArch::PseudoVBNZ:
9382 case LoongArch::PseudoVBNZ_B:
9383 case LoongArch::PseudoVBNZ_H:
9384 case LoongArch::PseudoVBNZ_W:
9385 case LoongArch::PseudoVBNZ_D:
9386 case LoongArch::PseudoXVBZ:
9387 case LoongArch::PseudoXVBZ_B:
9388 case LoongArch::PseudoXVBZ_H:
9389 case LoongArch::PseudoXVBZ_W:
9390 case LoongArch::PseudoXVBZ_D:
9391 case LoongArch::PseudoXVBNZ:
9392 case LoongArch::PseudoXVBNZ_B:
9393 case LoongArch::PseudoXVBNZ_H:
9394 case LoongArch::PseudoXVBNZ_W:
9395 case LoongArch::PseudoXVBNZ_D:
9396 return emitVecCondBranchPseudo(MI, BB, Subtarget);
9397 case LoongArch::PseudoXVINSGR2VR_B:
9398 case LoongArch::PseudoXVINSGR2VR_H:
9399 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
9400 case LoongArch::PseudoCTPOP_B:
9401 case LoongArch::PseudoCTPOP_H:
9402 case LoongArch::PseudoCTPOP_W:
9403 case LoongArch::PseudoCTPOP_D:
9404 case LoongArch::PseudoCTPOP_H_LA32:
9405 case LoongArch::PseudoCTPOP_W_LA32:
9406 return emitPseudoCTPOP(MI, BB, Subtarget);
9407 case LoongArch::PseudoVMSKLTZ_B:
9408 case LoongArch::PseudoVMSKLTZ_H:
9409 case LoongArch::PseudoVMSKLTZ_W:
9410 case LoongArch::PseudoVMSKLTZ_D:
9411 case LoongArch::PseudoVMSKGEZ_B:
9412 case LoongArch::PseudoVMSKEQZ_B:
9413 case LoongArch::PseudoVMSKNEZ_B:
9414 case LoongArch::PseudoXVMSKLTZ_B:
9415 case LoongArch::PseudoXVMSKLTZ_H:
9416 case LoongArch::PseudoXVMSKLTZ_W:
9417 case LoongArch::PseudoXVMSKLTZ_D:
9418 case LoongArch::PseudoXVMSKGEZ_B:
9419 case LoongArch::PseudoXVMSKEQZ_B:
9420 case LoongArch::PseudoXVMSKNEZ_B:
9421 return emitPseudoVMSKCOND(MI, BB, Subtarget);
9422 case TargetOpcode::STATEPOINT:
9423 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
9424 // while bl call instruction (where statepoint will be lowered at the
9425 // end) has implicit def. This def is early-clobber as it will be set at
9426 // the moment of the call and earlier than any use is read.
9427 // Add this implicit dead def here as a workaround.
9428 MI.addOperand(*MI.getMF(),
9430 LoongArch::R1, /*isDef*/ true,
9431 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
9432 /*isUndef*/ false, /*isEarlyClobber*/ true));
9433 if (!Subtarget.is64Bit())
9434 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
9435 return emitPatchPoint(MI, BB);
9436 case LoongArch::PROBED_STACKALLOC_DYN:
9437 return emitDynamicProbedAlloc(MI, BB);
9438 }
9439}
9440
9442 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
9443 unsigned *Fast) const {
9444 if (!Subtarget.hasUAL())
9445 return false;
9446
9447 // TODO: set reasonable speed number.
9448 if (Fast)
9449 *Fast = 1;
9450 return true;
9451}
9452
9453//===----------------------------------------------------------------------===//
9454// Calling Convention Implementation
9455//===----------------------------------------------------------------------===//
9456
9457// Eight general-purpose registers a0-a7 used for passing integer arguments,
9458// with a0-a1 reused to return values. Generally, the GPRs are used to pass
9459// fixed-point arguments, and floating-point arguments when no FPR is available
9460// or with soft float ABI.
9461const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
9462 LoongArch::R7, LoongArch::R8, LoongArch::R9,
9463 LoongArch::R10, LoongArch::R11};
9464
9465// PreserveNone calling convention:
9466// Arguments may be passed in any general-purpose registers except:
9467// - R1 : return address register
9468// - R22 : frame pointer
9469// - R31 : base pointer
9470//
9471// All general-purpose registers are treated as caller-saved,
9472// except R1 (RA) and R22 (FP).
9473//
9474// Non-volatile registers are allocated first so that a function
9475// can call normal functions without having to spill and reload
9476// argument registers.
9478 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
9479 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
9480 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
9481 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
9482 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
9483 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
9484 LoongArch::R20};
9485
9486// Eight floating-point registers fa0-fa7 used for passing floating-point
9487// arguments, and fa0-fa1 are also used to return values.
9488const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
9489 LoongArch::F3, LoongArch::F4, LoongArch::F5,
9490 LoongArch::F6, LoongArch::F7};
9491// FPR32 and FPR64 alias each other.
9493 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
9494 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
9495
9496const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
9497 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
9498 LoongArch::VR6, LoongArch::VR7};
9499
9500const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
9501 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
9502 LoongArch::XR6, LoongArch::XR7};
9503
9505 switch (State.getCallingConv()) {
9507 if (!State.isVarArg())
9508 return State.AllocateReg(PreserveNoneArgGPRs);
9509 [[fallthrough]];
9510 default:
9511 return State.AllocateReg(ArgGPRs);
9512 }
9513}
9514
9515// Pass a 2*GRLen argument that has been split into two GRLen values through
9516// registers or the stack as necessary.
9517static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
9518 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
9519 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
9520 ISD::ArgFlagsTy ArgFlags2) {
9521 unsigned GRLenInBytes = GRLen / 8;
9522 if (Register Reg = allocateArgGPR(State)) {
9523 // At least one half can be passed via register.
9524 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
9525 VA1.getLocVT(), CCValAssign::Full));
9526 } else {
9527 // Both halves must be passed on the stack, with proper alignment.
9528 Align StackAlign =
9529 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
9530 State.addLoc(
9532 State.AllocateStack(GRLenInBytes, StackAlign),
9533 VA1.getLocVT(), CCValAssign::Full));
9534 State.addLoc(CCValAssign::getMem(
9535 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9536 LocVT2, CCValAssign::Full));
9537 return false;
9538 }
9539 if (Register Reg = allocateArgGPR(State)) {
9540 // The second half can also be passed via register.
9541 State.addLoc(
9542 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
9543 } else {
9544 // The second half is passed via the stack, without additional alignment.
9545 State.addLoc(CCValAssign::getMem(
9546 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9547 LocVT2, CCValAssign::Full));
9548 }
9549 return false;
9550}
9551
9552// Implements the LoongArch calling convention. Returns true upon failure.
9554 unsigned ValNo, MVT ValVT,
9555 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
9556 CCState &State, bool IsRet, Type *OrigTy) {
9557 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
9558 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
9559 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
9560 MVT LocVT = ValVT;
9561
9562 // Any return value split into more than two values can't be returned
9563 // directly.
9564 if (IsRet && ValNo > 1)
9565 return true;
9566
9567 // If passing a variadic argument, or if no FPR is available.
9568 bool UseGPRForFloat = true;
9569
9570 switch (ABI) {
9571 default:
9572 llvm_unreachable("Unexpected ABI");
9573 break;
9578 UseGPRForFloat = ArgFlags.isVarArg();
9579 break;
9582 break;
9583 }
9584
9585 // If this is a variadic argument, the LoongArch calling convention requires
9586 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
9587 // byte alignment. An aligned register should be used regardless of whether
9588 // the original argument was split during legalisation or not. The argument
9589 // will not be passed by registers if the original type is larger than
9590 // 2*GRLen, so the register alignment rule does not apply.
9591 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
9592 if (ArgFlags.isVarArg() &&
9593 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
9594 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
9595 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
9596 // Skip 'odd' register if necessary.
9597 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
9598 State.AllocateReg(ArgGPRs);
9599 }
9600
9601 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
9602 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
9603 State.getPendingArgFlags();
9604
9605 assert(PendingLocs.size() == PendingArgFlags.size() &&
9606 "PendingLocs and PendingArgFlags out of sync");
9607
9608 // FPR32 and FPR64 alias each other.
9609 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
9610 UseGPRForFloat = true;
9611
9612 if (UseGPRForFloat && ValVT == MVT::f32) {
9613 LocVT = GRLenVT;
9614 LocInfo = CCValAssign::BCvt;
9615 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
9616 LocVT = MVT::i64;
9617 LocInfo = CCValAssign::BCvt;
9618 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
9619 // Handle passing f64 on LA32D with a soft float ABI or when floating point
9620 // registers are exhausted.
9621 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
9622 // Depending on available argument GPRS, f64 may be passed in a pair of
9623 // GPRs, split between a GPR and the stack, or passed completely on the
9624 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
9625 // cases.
9626 MCRegister Reg = allocateArgGPR(State);
9627 if (!Reg) {
9628 int64_t StackOffset = State.AllocateStack(8, Align(8));
9629 State.addLoc(
9630 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9631 return false;
9632 }
9633 LocVT = MVT::i32;
9634 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9635 MCRegister HiReg = allocateArgGPR(State);
9636 if (HiReg) {
9637 State.addLoc(
9638 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
9639 } else {
9640 int64_t StackOffset = State.AllocateStack(4, Align(4));
9641 State.addLoc(
9642 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9643 }
9644 return false;
9645 }
9646
9647 // Split arguments might be passed indirectly, so keep track of the pending
9648 // values.
9649 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
9650 LocVT = GRLenVT;
9651 LocInfo = CCValAssign::Indirect;
9652 PendingLocs.push_back(
9653 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
9654 PendingArgFlags.push_back(ArgFlags);
9655 if (!ArgFlags.isSplitEnd()) {
9656 return false;
9657 }
9658 }
9659
9660 // If the split argument only had two elements, it should be passed directly
9661 // in registers or on the stack.
9662 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
9663 PendingLocs.size() <= 2) {
9664 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
9665 // Apply the normal calling convention rules to the first half of the
9666 // split argument.
9667 CCValAssign VA = PendingLocs[0];
9668 ISD::ArgFlagsTy AF = PendingArgFlags[0];
9669 PendingLocs.clear();
9670 PendingArgFlags.clear();
9671 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
9672 ArgFlags);
9673 }
9674
9675 // Allocate to a register if possible, or else a stack slot.
9676 Register Reg;
9677 unsigned StoreSizeBytes = GRLen / 8;
9678 Align StackAlign = Align(GRLen / 8);
9679
9680 if (ValVT == MVT::f32 && !UseGPRForFloat) {
9681 Reg = State.AllocateReg(ArgFPR32s);
9682 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
9683 Reg = State.AllocateReg(ArgFPR64s);
9684 } else if (ValVT.is128BitVector()) {
9685 Reg = State.AllocateReg(ArgVRs);
9686 UseGPRForFloat = false;
9687 StoreSizeBytes = 16;
9688 StackAlign = Align(16);
9689 } else if (ValVT.is256BitVector()) {
9690 Reg = State.AllocateReg(ArgXRs);
9691 UseGPRForFloat = false;
9692 StoreSizeBytes = 32;
9693 StackAlign = Align(32);
9694 } else {
9695 Reg = allocateArgGPR(State);
9696 }
9697
9698 unsigned StackOffset =
9699 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
9700
9701 // If we reach this point and PendingLocs is non-empty, we must be at the
9702 // end of a split argument that must be passed indirectly.
9703 if (!PendingLocs.empty()) {
9704 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
9705 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
9706 for (auto &It : PendingLocs) {
9707 if (Reg)
9708 It.convertToReg(Reg);
9709 else
9710 It.convertToMem(StackOffset);
9711 State.addLoc(It);
9712 }
9713 PendingLocs.clear();
9714 PendingArgFlags.clear();
9715 return false;
9716 }
9717 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
9718 "Expected an GRLenVT at this stage");
9719
9720 if (Reg) {
9721 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9722 return false;
9723 }
9724
9725 // When a floating-point value is passed on the stack, no bit-cast is needed.
9726 if (ValVT.isFloatingPoint()) {
9727 LocVT = ValVT;
9728 LocInfo = CCValAssign::Full;
9729 }
9730
9731 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9732 return false;
9733}
9734
9735void LoongArchTargetLowering::analyzeInputArgs(
9736 MachineFunction &MF, CCState &CCInfo,
9737 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
9738 LoongArchCCAssignFn Fn) const {
9739 FunctionType *FType = MF.getFunction().getFunctionType();
9740 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
9741 MVT ArgVT = Ins[i].VT;
9742 Type *ArgTy = nullptr;
9743 if (IsRet)
9744 ArgTy = FType->getReturnType();
9745 else if (Ins[i].isOrigArg())
9746 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
9748 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
9749 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
9750 CCInfo, IsRet, ArgTy)) {
9751 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
9752 << '\n');
9753 llvm_unreachable("");
9754 }
9755 }
9756}
9757
9758void LoongArchTargetLowering::analyzeOutputArgs(
9759 MachineFunction &MF, CCState &CCInfo,
9760 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
9761 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
9762 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
9763 MVT ArgVT = Outs[i].VT;
9764 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
9766 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
9767 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
9768 CCInfo, IsRet, OrigTy)) {
9769 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
9770 << "\n");
9771 llvm_unreachable("");
9772 }
9773 }
9774}
9775
9776// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
9777// values.
9779 const CCValAssign &VA, const SDLoc &DL) {
9780 switch (VA.getLocInfo()) {
9781 default:
9782 llvm_unreachable("Unexpected CCValAssign::LocInfo");
9783 case CCValAssign::Full:
9785 break;
9786 case CCValAssign::BCvt:
9787 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
9788 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
9789 else
9790 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
9791 break;
9792 }
9793 return Val;
9794}
9795
9797 const CCValAssign &VA, const SDLoc &DL,
9798 const ISD::InputArg &In,
9799 const LoongArchTargetLowering &TLI) {
9802 EVT LocVT = VA.getLocVT();
9803 SDValue Val;
9804 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
9805 Register VReg = RegInfo.createVirtualRegister(RC);
9806 RegInfo.addLiveIn(VA.getLocReg(), VReg);
9807 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
9808
9809 // If input is sign extended from 32 bits, note it for the OptW pass.
9810 if (In.isOrigArg()) {
9811 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
9812 if (OrigArg->getType()->isIntegerTy()) {
9813 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
9814 // An input zero extended from i31 can also be considered sign extended.
9815 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
9816 (BitWidth < 32 && In.Flags.isZExt())) {
9819 LAFI->addSExt32Register(VReg);
9820 }
9821 }
9822 }
9823
9824 return convertLocVTToValVT(DAG, Val, VA, DL);
9825}
9826
9827// The caller is responsible for loading the full value if the argument is
9828// passed with CCValAssign::Indirect.
9830 const CCValAssign &VA, const SDLoc &DL) {
9832 MachineFrameInfo &MFI = MF.getFrameInfo();
9833 EVT ValVT = VA.getValVT();
9834 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
9835 /*IsImmutable=*/true);
9836 SDValue FIN = DAG.getFrameIndex(
9838
9839 ISD::LoadExtType ExtType;
9840 switch (VA.getLocInfo()) {
9841 default:
9842 llvm_unreachable("Unexpected CCValAssign::LocInfo");
9843 case CCValAssign::Full:
9845 case CCValAssign::BCvt:
9846 ExtType = ISD::NON_EXTLOAD;
9847 break;
9848 }
9849 return DAG.getExtLoad(
9850 ExtType, DL, VA.getLocVT(), Chain, FIN,
9852}
9853
9855 const CCValAssign &VA,
9856 const CCValAssign &HiVA,
9857 const SDLoc &DL) {
9858 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
9859 "Unexpected VA");
9861 MachineFrameInfo &MFI = MF.getFrameInfo();
9863
9864 assert(VA.isRegLoc() && "Expected register VA assignment");
9865
9866 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
9867 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
9868 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
9869 SDValue Hi;
9870 if (HiVA.isMemLoc()) {
9871 // Second half of f64 is passed on the stack.
9872 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
9873 /*IsImmutable=*/true);
9874 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
9875 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
9877 } else {
9878 // Second half of f64 is passed in another GPR.
9879 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
9880 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
9881 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
9882 }
9883 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
9884}
9885
9887 const CCValAssign &VA, const SDLoc &DL) {
9888 EVT LocVT = VA.getLocVT();
9889
9890 switch (VA.getLocInfo()) {
9891 default:
9892 llvm_unreachable("Unexpected CCValAssign::LocInfo");
9893 case CCValAssign::Full:
9894 break;
9895 case CCValAssign::BCvt:
9896 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
9897 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
9898 else
9899 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
9900 break;
9901 }
9902 return Val;
9903}
9904
9905static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
9906 CCValAssign::LocInfo LocInfo,
9907 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
9908 CCState &State) {
9909 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
9910 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
9911 // s0 s1 s2 s3 s4 s5 s6 s7 s8
9912 static const MCPhysReg GPRList[] = {
9913 LoongArch::R23, LoongArch::R24, LoongArch::R25,
9914 LoongArch::R26, LoongArch::R27, LoongArch::R28,
9915 LoongArch::R29, LoongArch::R30, LoongArch::R31};
9916 if (MCRegister Reg = State.AllocateReg(GPRList)) {
9917 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9918 return false;
9919 }
9920 }
9921
9922 if (LocVT == MVT::f32) {
9923 // Pass in STG registers: F1, F2, F3, F4
9924 // fs0,fs1,fs2,fs3
9925 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
9926 LoongArch::F26, LoongArch::F27};
9927 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
9928 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9929 return false;
9930 }
9931 }
9932
9933 if (LocVT == MVT::f64) {
9934 // Pass in STG registers: D1, D2, D3, D4
9935 // fs4,fs5,fs6,fs7
9936 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
9937 LoongArch::F30_64, LoongArch::F31_64};
9938 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
9939 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9940 return false;
9941 }
9942 }
9943
9944 report_fatal_error("No registers left in GHC calling convention");
9945 return true;
9946}
9947
9948// Transform physical registers into virtual registers.
9950 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
9951 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
9952 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
9953
9955
9956 switch (CallConv) {
9957 default:
9958 llvm_unreachable("Unsupported calling convention");
9959 case CallingConv::C:
9960 case CallingConv::Fast:
9963 break;
9964 case CallingConv::GHC:
9965 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
9966 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
9968 "GHC calling convention requires the F and D extensions");
9969 }
9970
9971 const Function &Func = MF.getFunction();
9972 EVT PtrVT = getPointerTy(DAG.getDataLayout());
9973 MVT GRLenVT = Subtarget.getGRLenVT();
9974 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
9975
9976 // Check if this function has any musttail calls. If so, incoming indirect
9977 // arg pointers must be saved in virtual registers so they survive across
9978 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
9979 // when needed to avoid adding register pressure to non-musttail functions.
9980 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
9981 return llvm::any_of(BB, [](const Instruction &I) {
9982 if (const auto *CI = dyn_cast<CallInst>(&I))
9983 return CI->isMustTailCall();
9984 return false;
9985 });
9986 });
9987 // Used with varargs to acumulate store chains.
9988 std::vector<SDValue> OutChains;
9989
9990 // Assign locations to all of the incoming arguments.
9992 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
9993
9994 if (CallConv == CallingConv::GHC)
9996 else
9997 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
9998
9999 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10000 CCValAssign &VA = ArgLocs[i];
10001 SDValue ArgValue;
10002 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10003 // case.
10004 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10005 assert(VA.needsCustom());
10006 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10007 } else if (VA.isRegLoc())
10008 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10009 else
10010 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10011 if (VA.getLocInfo() == CCValAssign::Indirect) {
10012 // If the original argument was split and passed by reference, we need to
10013 // load all parts of it here (using the same address).
10014 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10016 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10017 if (HasMusttail) {
10020 Register VReg =
10021 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10022 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10023 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10024 }
10025 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10026 assert(ArgPartOffset == 0);
10027 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10028 CCValAssign &PartVA = ArgLocs[i + 1];
10029 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10030 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10031 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10032 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10034 ++i;
10035 ++InsIdx;
10036 }
10037 continue;
10038 }
10039 InVals.push_back(ArgValue);
10040 }
10041
10042 if (IsVarArg) {
10044 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10045 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10046 MachineFrameInfo &MFI = MF.getFrameInfo();
10047 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10048 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10049
10050 // Offset of the first variable argument from stack pointer, and size of
10051 // the vararg save area. For now, the varargs save area is either zero or
10052 // large enough to hold a0-a7.
10053 int VaArgOffset, VarArgsSaveSize;
10054
10055 // If all registers are allocated, then all varargs must be passed on the
10056 // stack and we don't need to save any argregs.
10057 if (ArgRegs.size() == Idx) {
10058 VaArgOffset = CCInfo.getStackSize();
10059 VarArgsSaveSize = 0;
10060 } else {
10061 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10062 VaArgOffset = -VarArgsSaveSize;
10063 }
10064
10065 // Record the frame index of the first variable argument
10066 // which is a value necessary to VASTART.
10067 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10068 LoongArchFI->setVarArgsFrameIndex(FI);
10069
10070 // If saving an odd number of registers then create an extra stack slot to
10071 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10072 // offsets to even-numbered registered remain 2*GRLen-aligned.
10073 if (Idx % 2) {
10074 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10075 true);
10076 VarArgsSaveSize += GRLenInBytes;
10077 }
10078
10079 // Copy the integer registers that may have been used for passing varargs
10080 // to the vararg save area.
10081 for (unsigned I = Idx; I < ArgRegs.size();
10082 ++I, VaArgOffset += GRLenInBytes) {
10083 const Register Reg = RegInfo.createVirtualRegister(RC);
10084 RegInfo.addLiveIn(ArgRegs[I], Reg);
10085 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10086 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10087 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10088 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10090 cast<StoreSDNode>(Store.getNode())
10091 ->getMemOperand()
10092 ->setValue((Value *)nullptr);
10093 OutChains.push_back(Store);
10094 }
10095 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10096 }
10097
10098 // All stores are grouped in one node to allow the matching between
10099 // the size of Ins and InVals. This only happens for vararg functions.
10100 if (!OutChains.empty()) {
10101 OutChains.push_back(Chain);
10102 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10103 }
10104
10105 return Chain;
10106}
10107
10109 return CI->isTailCall();
10110}
10111
10112// Check if the return value is used as only a return value, as otherwise
10113// we can't perform a tail-call.
10115 SDValue &Chain) const {
10116 if (N->getNumValues() != 1)
10117 return false;
10118 if (!N->hasNUsesOfValue(1, 0))
10119 return false;
10120
10121 SDNode *Copy = *N->user_begin();
10122 if (Copy->getOpcode() != ISD::CopyToReg)
10123 return false;
10124
10125 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10126 // isn't safe to perform a tail call.
10127 if (Copy->getGluedNode())
10128 return false;
10129
10130 // The copy must be used by a LoongArchISD::RET, and nothing else.
10131 bool HasRet = false;
10132 for (SDNode *Node : Copy->users()) {
10133 if (Node->getOpcode() != LoongArchISD::RET)
10134 return false;
10135 HasRet = true;
10136 }
10137
10138 if (!HasRet)
10139 return false;
10140
10141 Chain = Copy->getOperand(0);
10142 return true;
10143}
10144
10145// Check whether the call is eligible for tail call optimization.
10146bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10147 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10148 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10149
10150 auto CalleeCC = CLI.CallConv;
10151 auto &Outs = CLI.Outs;
10152 auto &Caller = MF.getFunction();
10153 auto CallerCC = Caller.getCallingConv();
10154
10155 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10156
10157 // Byval parameters hand the function a pointer directly into the stack area
10158 // we want to reuse during a tail call. Working around this *is* possible
10159 // but less efficient and uglier in LowerCall. For musttail, there is no
10160 // workaround today: a byval arg requires a local copy that becomes invalid
10161 // after the tail call deallocates the caller's frame, so rejecting here
10162 // (and triggering reportFatalInternalError in LowerCall) is safer than
10163 // miscompiling.
10164 for (auto &Arg : Outs)
10165 if (Arg.Flags.isByVal())
10166 return false;
10167
10168 // musttail bypasses the remaining checks: the checks either reject cases
10169 // we handle specially (indirect args are forwarded via incoming pointers,
10170 // stack-passed args reuse the matching incoming layout, sret is forwarded
10171 // like any other pointer arg) or are optimizations not applicable to
10172 // mandatory tail calls.
10173 if (IsMustTail)
10174 return true;
10175
10176 // Do not tail call opt if the stack is used to pass parameters.
10177 if (CCInfo.getStackSize() != 0)
10178 return false;
10179
10180 // Do not tail call opt if any parameters need to be passed indirectly.
10181 for (auto &VA : ArgLocs)
10182 if (VA.getLocInfo() == CCValAssign::Indirect)
10183 return false;
10184
10185 // Do not tail call opt if either caller or callee uses struct return
10186 // semantics.
10187 auto IsCallerStructRet = Caller.hasStructRetAttr();
10188 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10189 if (IsCallerStructRet || IsCalleeStructRet)
10190 return false;
10191
10192 // The callee has to preserve all registers the caller needs to preserve.
10193 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10194 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10195 if (CalleeCC != CallerCC) {
10196 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10197 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10198 return false;
10199 }
10200 return true;
10201}
10202
10204 return DAG.getDataLayout().getPrefTypeAlign(
10205 VT.getTypeForEVT(*DAG.getContext()));
10206}
10207
10208// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
10209// and output parameter nodes.
10210SDValue
10212 SmallVectorImpl<SDValue> &InVals) const {
10213 SelectionDAG &DAG = CLI.DAG;
10214 SDLoc &DL = CLI.DL;
10216 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10218 SDValue Chain = CLI.Chain;
10219 SDValue Callee = CLI.Callee;
10220 CallingConv::ID CallConv = CLI.CallConv;
10221 bool IsVarArg = CLI.IsVarArg;
10222 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10223 MVT GRLenVT = Subtarget.getGRLenVT();
10224 bool &IsTailCall = CLI.IsTailCall;
10225
10227
10228 // Analyze the operands of the call, assigning locations to each operand.
10230 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10231
10232 if (CallConv == CallingConv::GHC)
10233 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
10234 else
10235 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
10236
10237 // Check if it's really possible to do a tail call.
10238 if (IsTailCall)
10239 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
10240
10241 if (IsTailCall)
10242 ++NumTailCalls;
10243 else if (CLI.CB && CLI.CB->isMustTailCall())
10244 report_fatal_error("failed to perform tail call elimination on a call "
10245 "site marked musttail");
10246
10247 // Get a count of how many bytes are to be pushed on the stack.
10248 unsigned NumBytes = ArgCCInfo.getStackSize();
10249
10250 // Create local copies for byval args.
10251 SmallVector<SDValue> ByValArgs;
10252 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10253 ISD::ArgFlagsTy Flags = Outs[i].Flags;
10254 if (!Flags.isByVal())
10255 continue;
10256
10257 SDValue Arg = OutVals[i];
10258 unsigned Size = Flags.getByValSize();
10259 Align Alignment = Flags.getNonZeroByValAlign();
10260
10261 int FI =
10262 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
10263 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10264 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
10265
10266 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
10267 /*IsVolatile=*/false,
10268 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
10270 ByValArgs.push_back(FIPtr);
10271 }
10272
10273 if (!IsTailCall)
10274 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
10275
10276 // Copy argument values to their designated locations.
10278 SmallVector<SDValue> MemOpChains;
10279 SDValue StackPtr;
10280 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
10281 ++i, ++OutIdx) {
10282 CCValAssign &VA = ArgLocs[i];
10283 SDValue ArgValue = OutVals[OutIdx];
10284 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
10285
10286 // Handle passing f64 on LA32D with a soft float ABI as a special case.
10287 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10288 assert(VA.isRegLoc() && "Expected register VA assignment");
10289 assert(VA.needsCustom());
10290 SDValue SplitF64 =
10291 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10292 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
10293 SDValue Lo = SplitF64.getValue(0);
10294 SDValue Hi = SplitF64.getValue(1);
10295
10296 Register RegLo = VA.getLocReg();
10297 RegsToPass.push_back(std::make_pair(RegLo, Lo));
10298
10299 // Get the CCValAssign for the Hi part.
10300 CCValAssign &HiVA = ArgLocs[++i];
10301
10302 if (HiVA.isMemLoc()) {
10303 // Second half of f64 is passed on the stack.
10304 if (!StackPtr.getNode())
10305 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10307 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10308 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
10309 // Emit the store.
10310 MemOpChains.push_back(DAG.getStore(
10311 Chain, DL, Hi, Address,
10313 } else {
10314 // Second half of f64 is passed in another GPR.
10315 Register RegHigh = HiVA.getLocReg();
10316 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
10317 }
10318 continue;
10319 }
10320
10321 // Promote the value if needed.
10322 // For now, only handle fully promoted and indirect arguments.
10323 if (VA.getLocInfo() == CCValAssign::Indirect) {
10324 // For musttail calls, reuse incoming indirect pointers instead of
10325 // creating new stack temporaries. The incoming pointers point to the
10326 // caller's caller's frame, which remains valid after a tail call.
10327 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
10330 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
10331
10332 // Resolve which formal parameter is being passed at this call
10333 // position.
10334 //
10335 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
10336 // but Outs[].OrigArgIndex is an index into a filtered arg list
10337 // (empty types removed, via CallLoweringInfo in the target-
10338 // independent layer). IncomingIndirectArgs is keyed by the
10339 // caller's unfiltered Argument::getArgNo(), so we have to walk
10340 // the caller's formals (same filter) to translate the index.
10341 // This target-independent asymmetry should be normalized so
10342 // backends do not need to re-derive the mapping.
10343 //
10344 // Steps:
10345 // 1. Find the call operand at filtered position CallArgIdx.
10346 // 2. If it is an Argument, use getArgNo() directly (same filter
10347 // for caller formals and call operands).
10348 // 3. Otherwise (computed value), walk the caller's formals and
10349 // skip empty types to map the filtered index to getArgNo().
10350 const Argument *FormalArg = nullptr;
10351 unsigned FilteredIdx = 0;
10352 for (const auto &CallArg : CLI.CB->args()) {
10353 if (CallArg->getType()->isEmptyTy())
10354 continue;
10355 if (FilteredIdx == CallArgIdx) {
10356 FormalArg = dyn_cast<Argument>(CallArg);
10357 break;
10358 }
10359 ++FilteredIdx;
10360 }
10361
10362 // For forwarded args, getArgNo() gives the unfiltered index directly.
10363 // For computed args, walk the caller's formals to resolve it.
10364 unsigned FormalArgIdx = CallArgIdx;
10365 if (FormalArg) {
10366 FormalArgIdx = FormalArg->getArgNo();
10367 } else {
10368 FilteredIdx = 0;
10369 for (const auto &Arg : MF.getFunction().args()) {
10370 if (Arg.getType()->isEmptyTy())
10371 continue;
10372 if (FilteredIdx == CallArgIdx) {
10373 FormalArgIdx = Arg.getArgNo();
10374 break;
10375 }
10376 ++FilteredIdx;
10377 }
10378 }
10379
10380 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
10381 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
10382 // Thread the CopyFromReg output chain through MemOpChains so the
10383 // TokenFactor below sequences the copy with any stores we emit
10384 // for this argument.
10385 MemOpChains.push_back(CopyOp.getValue(1));
10386 SDValue IncomingPtr = CopyOp;
10387
10388 if (!FormalArg) {
10389 // Computed value: store into the incoming indirect pointer for the
10390 // same-position formal parameter (musttail guarantees matching
10391 // prototypes, so types match). The pointer survives the tail call
10392 // since it points to the caller's caller's frame.
10393 //
10394 // The data-flow edge through IncomingPtr already prevents the
10395 // store from being scheduled before the CopyFromReg. Threading
10396 // CopyOp.getValue(1) (the copy's output chain) into the store
10397 // makes that ordering explicit on the chain edge as well, which
10398 // is the convention for memory ops chaining off their producers.
10399 MemOpChains.push_back(
10400 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
10402 // Store any split parts at their respective offsets.
10403 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10404 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10405 SDValue PartValue = OutVals[OutIdx + 1];
10406 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10407 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10408 SDValue Addr =
10409 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
10410 MemOpChains.push_back(
10411 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
10413 ++i;
10414 ++OutIdx;
10415 }
10416 }
10417 ArgValue = IncomingPtr;
10418
10419 // Skip any remaining split parts (for forwarded args, they are
10420 // covered by the forwarded pointer).
10421 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10422 ++i;
10423 ++OutIdx;
10424 }
10425 } else {
10426 // Store the argument in a stack slot and pass its address.
10427 Align StackAlign =
10428 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
10429 getPrefTypeAlign(ArgValue.getValueType(), DAG));
10430 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
10431 // If the original argument was split and passed by reference, we need
10432 // to store the required parts of it here (and pass just one address).
10433 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
10434 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10435 assert(ArgPartOffset == 0);
10436 // Calculate the total size to store. We don't have access to what we're
10437 // actually storing other than performing the loop and collecting the
10438 // info.
10440 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
10441 SDValue PartValue = OutVals[OutIdx + 1];
10442 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10443 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10444 EVT PartVT = PartValue.getValueType();
10445 StoredSize += PartVT.getStoreSize();
10446 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
10447 Parts.push_back(std::make_pair(PartValue, Offset));
10448 ++i;
10449 ++OutIdx;
10450 }
10451 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
10452 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
10453 MemOpChains.push_back(
10454 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
10456 for (const auto &Part : Parts) {
10457 SDValue PartValue = Part.first;
10458 SDValue PartOffset = Part.second;
10460 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
10461 MemOpChains.push_back(
10462 DAG.getStore(Chain, DL, PartValue, Address,
10464 }
10465 ArgValue = SpillSlot;
10466 }
10467 } else {
10468 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
10469 }
10470
10471 // Use local copy if it is a byval arg.
10472 if (Flags.isByVal())
10473 ArgValue = ByValArgs[j++];
10474
10475 if (VA.isRegLoc()) {
10476 // Queue up the argument copies and emit them at the end.
10477 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
10478 } else {
10479 assert(VA.isMemLoc() && "Argument not register or memory");
10480 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
10481 "Tail call not allowed if stack is used for passing parameters");
10482
10483 // Work out the address of the stack slot.
10484 if (!StackPtr.getNode())
10485 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10487 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10489
10490 // Emit the store.
10491 MemOpChains.push_back(
10492 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
10493 }
10494 }
10495
10496 // Join the stores, which are independent of one another.
10497 if (!MemOpChains.empty())
10498 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
10499
10500 SDValue Glue;
10501
10502 // Build a sequence of copy-to-reg nodes, chained and glued together.
10503 for (auto &Reg : RegsToPass) {
10504 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
10505 Glue = Chain.getValue(1);
10506 }
10507
10508 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
10509 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
10510 // split it and then direct call can be matched by PseudoCALL_SMALL.
10512 const GlobalValue *GV = S->getGlobal();
10513 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
10516 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
10517 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
10518 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
10521 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
10522 }
10523
10524 // The first call operand is the chain and the second is the target address.
10526 Ops.push_back(Chain);
10527 Ops.push_back(Callee);
10528
10529 // Add argument registers to the end of the list so that they are
10530 // known live into the call.
10531 for (auto &Reg : RegsToPass)
10532 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
10533
10534 if (!IsTailCall) {
10535 // Add a register mask operand representing the call-preserved registers.
10536 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
10537 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
10538 assert(Mask && "Missing call preserved mask for calling convention");
10539 Ops.push_back(DAG.getRegisterMask(Mask));
10540 }
10541
10542 // Glue the call to the argument copies, if any.
10543 if (Glue.getNode())
10544 Ops.push_back(Glue);
10545
10546 // Emit the call.
10547 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
10548 unsigned Op;
10549 switch (DAG.getTarget().getCodeModel()) {
10550 default:
10551 report_fatal_error("Unsupported code model");
10552 case CodeModel::Small:
10553 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
10554 break;
10555 case CodeModel::Medium:
10556 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
10557 break;
10558 case CodeModel::Large:
10559 assert(Subtarget.is64Bit() && "Large code model requires LA64");
10560 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
10561 break;
10562 }
10563
10564 if (IsTailCall) {
10566 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
10567 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
10568 return Ret;
10569 }
10570
10571 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
10572 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
10573 Glue = Chain.getValue(1);
10574
10575 // Mark the end of the call, which is glued to the call itself.
10576 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
10577 Glue = Chain.getValue(1);
10578
10579 // Assign locations to each value returned by this call.
10581 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
10582 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
10583
10584 // Copy all of the result registers out of their specified physreg.
10585 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
10586 auto &VA = RVLocs[i];
10587 // Copy the value out.
10588 SDValue RetValue =
10589 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
10590 // Glue the RetValue to the end of the call sequence.
10591 Chain = RetValue.getValue(1);
10592 Glue = RetValue.getValue(2);
10593
10594 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10595 assert(VA.needsCustom());
10596 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
10597 MVT::i32, Glue);
10598 Chain = RetValue2.getValue(1);
10599 Glue = RetValue2.getValue(2);
10600 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
10601 RetValue, RetValue2);
10602 } else
10603 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
10604
10605 InVals.push_back(RetValue);
10606 }
10607
10608 return Chain;
10609}
10610
10612 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
10613 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
10614 const Type *RetTy) const {
10616 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
10617
10618 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10619 LoongArchABI::ABI ABI =
10620 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10621 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
10622 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
10623 return false;
10624 }
10625 return true;
10626}
10627
10629 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10631 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
10632 SelectionDAG &DAG) const {
10633 // Stores the assignment of the return value to a location.
10635
10636 // Info about the registers and stack slot.
10637 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
10638 *DAG.getContext());
10639
10640 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
10641 nullptr, CC_LoongArch);
10642 if (CallConv == CallingConv::GHC && !RVLocs.empty())
10643 report_fatal_error("GHC functions return void only");
10644 SDValue Glue;
10645 SmallVector<SDValue, 4> RetOps(1, Chain);
10646
10647 // Copy the result values into the output registers.
10648 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
10649 SDValue Val = OutVals[OutIdx];
10650 CCValAssign &VA = RVLocs[i];
10651 assert(VA.isRegLoc() && "Can only return in registers!");
10652
10653 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10654 // Handle returning f64 on LA32D with a soft float ABI.
10655 assert(VA.isRegLoc() && "Expected return via registers");
10656 assert(VA.needsCustom());
10657 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10658 DAG.getVTList(MVT::i32, MVT::i32), Val);
10659 SDValue Lo = SplitF64.getValue(0);
10660 SDValue Hi = SplitF64.getValue(1);
10661 Register RegLo = VA.getLocReg();
10662 Register RegHi = RVLocs[++i].getLocReg();
10663
10664 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
10665 Glue = Chain.getValue(1);
10666 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
10667 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
10668 Glue = Chain.getValue(1);
10669 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
10670 } else {
10671 // Handle a 'normal' return.
10672 Val = convertValVTToLocVT(DAG, Val, VA, DL);
10673 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
10674
10675 // Guarantee that all emitted copies are stuck together.
10676 Glue = Chain.getValue(1);
10677 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
10678 }
10679 }
10680
10681 RetOps[0] = Chain; // Update chain.
10682
10683 // Add the glue node if we have it.
10684 if (Glue.getNode())
10685 RetOps.push_back(Glue);
10686
10687 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
10688}
10689
10690// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
10691// Note: The following prefixes are excluded:
10692// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
10693// as they can be represented using [x]vrepli.[whb]
10695 const APInt &SplatValue, const unsigned SplatBitSize) const {
10696 uint64_t RequiredImm = 0;
10697 uint64_t V = SplatValue.getZExtValue();
10698 if (SplatBitSize == 16 && !(V & 0x00FF)) {
10699 // 4'b0101
10700 RequiredImm = (0b10101 << 8) | (V >> 8);
10701 return {true, RequiredImm};
10702 } else if (SplatBitSize == 32) {
10703 // 4'b0001
10704 if (!(V & 0xFFFF00FF)) {
10705 RequiredImm = (0b10001 << 8) | (V >> 8);
10706 return {true, RequiredImm};
10707 }
10708 // 4'b0010
10709 if (!(V & 0xFF00FFFF)) {
10710 RequiredImm = (0b10010 << 8) | (V >> 16);
10711 return {true, RequiredImm};
10712 }
10713 // 4'b0011
10714 if (!(V & 0x00FFFFFF)) {
10715 RequiredImm = (0b10011 << 8) | (V >> 24);
10716 return {true, RequiredImm};
10717 }
10718 // 4'b0110
10719 if ((V & 0xFFFF00FF) == 0xFF) {
10720 RequiredImm = (0b10110 << 8) | (V >> 8);
10721 return {true, RequiredImm};
10722 }
10723 // 4'b0111
10724 if ((V & 0xFF00FFFF) == 0xFFFF) {
10725 RequiredImm = (0b10111 << 8) | (V >> 16);
10726 return {true, RequiredImm};
10727 }
10728 // 4'b1010
10729 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
10730 RequiredImm =
10731 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
10732 return {true, RequiredImm};
10733 }
10734 } else if (SplatBitSize == 64) {
10735 // 4'b1011
10736 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
10737 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
10738 RequiredImm =
10739 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
10740 return {true, RequiredImm};
10741 }
10742 // 4'b1100
10743 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
10744 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
10745 RequiredImm =
10746 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
10747 return {true, RequiredImm};
10748 }
10749 // 4'b1001
10750 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
10751 uint8_t res = 0;
10752 for (int i = 0; i < 8; ++i) {
10753 uint8_t byte = x & 0xFF;
10754 if (byte == 0 || byte == 0xFF)
10755 res |= ((byte & 1) << i);
10756 else
10757 return {false, 0};
10758 x >>= 8;
10759 }
10760 return {true, res};
10761 };
10762 auto [IsSame, Suffix] = sameBitsPreByte(V);
10763 if (IsSame) {
10764 RequiredImm = (0b11001 << 8) | Suffix;
10765 return {true, RequiredImm};
10766 }
10767 }
10768 return {false, RequiredImm};
10769}
10770
10772 EVT VT) const {
10773 if (!Subtarget.hasExtLSX())
10774 return false;
10775
10776 if (VT == MVT::f32) {
10777 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
10778 return (masked == 0x3e000000 || masked == 0x40000000);
10779 }
10780
10781 if (VT == MVT::f64) {
10782 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
10783 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
10784 }
10785
10786 return false;
10787}
10788
10789bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
10790 bool ForCodeSize) const {
10791 // TODO: Maybe need more checks here after vector extension is supported.
10792 if (VT == MVT::f32 && !Subtarget.hasBasicF())
10793 return false;
10794 if (VT == MVT::f64 && !Subtarget.hasBasicD())
10795 return false;
10796 return (Imm.isZero() || Imm.isOne() || isFPImmVLDILegal(Imm, VT));
10797}
10798
10800 return true;
10801}
10802
10804 return true;
10805}
10806
10807bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
10808 const Instruction *I) const {
10809 if (!Subtarget.is64Bit())
10810 return isa<LoadInst>(I) || isa<StoreInst>(I);
10811
10812 if (isa<LoadInst>(I))
10813 return true;
10814
10815 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
10816 // require fences beacuse we can use amswap_db.[w/d].
10817 Type *Ty = I->getOperand(0)->getType();
10818 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
10819 unsigned Size = Ty->getIntegerBitWidth();
10820 return (Size == 8 || Size == 16);
10821 }
10822
10823 return false;
10824}
10825
10827 LLVMContext &Context,
10828 EVT VT) const {
10829 if (!VT.isVector())
10830 return getPointerTy(DL);
10832}
10833
10835 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
10836 // Do not merge to float value size (128 or 256 bits) if no implicit
10837 // float attribute is set.
10838 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
10839 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
10840 if (NoFloat)
10841 return MemVT.getSizeInBits() <= MaxIntSize;
10842
10843 // Make sure we don't merge greater than our maximum supported vector width.
10844 if (Subtarget.hasExtLASX())
10845 MaxIntSize = 256;
10846 else if (Subtarget.hasExtLSX())
10847 MaxIntSize = 128;
10848
10849 return MemVT.getSizeInBits() <= MaxIntSize;
10850}
10851
10853 EVT VT = Y.getValueType();
10854
10855 if (VT.isVector())
10856 return Subtarget.hasExtLSX() && VT.isInteger();
10857
10858 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
10859}
10860
10863 MachineFunction &MF, unsigned Intrinsic) const {
10864 switch (Intrinsic) {
10865 default:
10866 return;
10867 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
10868 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
10869 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
10870 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
10871 IntrinsicInfo Info;
10873 Info.memVT = MVT::i32;
10874 Info.ptrVal = I.getArgOperand(0);
10875 Info.offset = 0;
10876 Info.align = Align(4);
10879 Infos.push_back(Info);
10880 return;
10881 // TODO: Add more Intrinsics later.
10882 }
10883 }
10884}
10885
10886// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
10887// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
10888// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
10889// regression, we need to implement it manually.
10892
10894 Op == AtomicRMWInst::And) &&
10895 "Unable to expand");
10896 unsigned MinWordSize = 4;
10897
10898 IRBuilder<> Builder(AI);
10899 LLVMContext &Ctx = Builder.getContext();
10900 const DataLayout &DL = AI->getDataLayout();
10901 Type *ValueType = AI->getType();
10902 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
10903
10904 Value *Addr = AI->getPointerOperand();
10905 PointerType *PtrTy = cast<PointerType>(Addr->getType());
10906 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
10907
10908 Value *AlignedAddr = Builder.CreateIntrinsic(
10909 Intrinsic::ptrmask, {PtrTy, IntTy},
10910 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
10911 "AlignedAddr");
10912
10913 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
10914 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
10915 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
10916 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
10917 Value *Mask = Builder.CreateShl(
10918 ConstantInt::get(WordType,
10919 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
10920 ShiftAmt, "Mask");
10921 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
10922 Value *ValOperand_Shifted =
10923 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
10924 ShiftAmt, "ValOperand_Shifted");
10925 Value *NewOperand;
10926 if (Op == AtomicRMWInst::And)
10927 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
10928 else
10929 NewOperand = ValOperand_Shifted;
10930
10931 AtomicRMWInst *NewAI =
10932 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
10933 AI->getOrdering(), AI->getSyncScopeID());
10934
10935 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
10936 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
10937 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
10938 AI->replaceAllUsesWith(FinalOldResult);
10939 AI->eraseFromParent();
10940}
10941
10944 const AtomicRMWInst *AI) const {
10945 // TODO: Add more AtomicRMWInst that needs to be extended.
10946
10947 // Since floating-point operation requires a non-trivial set of data
10948 // operations, use CmpXChg to expand.
10949 if (AI->isFloatingPointOperation() ||
10955
10956 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
10959 AI->getOperation() == AtomicRMWInst::Sub)) {
10961 }
10962
10963 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
10964 if (Subtarget.hasLAMCAS()) {
10965 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
10969 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
10971 }
10972
10973 if (Size == 8 || Size == 16)
10976}
10977
10978static Intrinsic::ID
10980 AtomicRMWInst::BinOp BinOp) {
10981 if (GRLen == 64) {
10982 switch (BinOp) {
10983 default:
10984 llvm_unreachable("Unexpected AtomicRMW BinOp");
10986 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
10987 case AtomicRMWInst::Add:
10988 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
10989 case AtomicRMWInst::Sub:
10990 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
10992 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
10994 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
10996 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
10997 case AtomicRMWInst::Max:
10998 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
10999 case AtomicRMWInst::Min:
11000 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11001 // TODO: support other AtomicRMWInst.
11002 }
11003 }
11004
11005 if (GRLen == 32) {
11006 switch (BinOp) {
11007 default:
11008 llvm_unreachable("Unexpected AtomicRMW BinOp");
11010 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11011 case AtomicRMWInst::Add:
11012 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11013 case AtomicRMWInst::Sub:
11014 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11016 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11018 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11020 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11021 case AtomicRMWInst::Max:
11022 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11023 case AtomicRMWInst::Min:
11024 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11025 // TODO: support other AtomicRMWInst.
11026 }
11027 }
11028
11029 llvm_unreachable("Unexpected GRLen\n");
11030}
11031
11034 const AtomicCmpXchgInst *CI) const {
11035
11036 if (Subtarget.hasLAMCAS())
11038
11040 if (Size == 8 || Size == 16)
11043}
11044
11046 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11047 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11048 unsigned GRLen = Subtarget.getGRLen();
11049 AtomicOrdering FailOrd = CI->getFailureOrdering();
11050 Value *FailureOrdering =
11051 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11052 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11053 if (GRLen == 64) {
11054 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11055 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11056 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11057 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11058 }
11059 Type *Tys[] = {AlignedAddr->getType()};
11060 Value *Result = Builder.CreateIntrinsic(
11061 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11062 if (GRLen == 64)
11063 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11064 return Result;
11065}
11066
11068 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11069 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11070 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11071 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11072 // mask, as this produces better code than the LL/SC loop emitted by
11073 // int_loongarch_masked_atomicrmw_xchg.
11074 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11077 if (CVal->isZero())
11078 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11079 Builder.CreateNot(Mask, "Inv_Mask"),
11080 AI->getAlign(), Ord);
11081 if (CVal->isMinusOne())
11082 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11083 AI->getAlign(), Ord);
11084 }
11085
11086 unsigned GRLen = Subtarget.getGRLen();
11087 Value *Ordering =
11088 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11089 Type *Tys[] = {AlignedAddr->getType()};
11091 AI->getModule(),
11093
11094 if (GRLen == 64) {
11095 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11096 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11097 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11098 }
11099
11100 Value *Result;
11101
11102 // Must pass the shift amount needed to sign extend the loaded value prior
11103 // to performing a signed comparison for min/max. ShiftAmt is the number of
11104 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11105 // is the number of bits to left+right shift the value in order to
11106 // sign-extend.
11107 if (AI->getOperation() == AtomicRMWInst::Min ||
11109 const DataLayout &DL = AI->getDataLayout();
11110 unsigned ValWidth =
11111 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11112 Value *SextShamt =
11113 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11114 Result = Builder.CreateCall(LlwOpScwLoop,
11115 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11116 } else {
11117 Result =
11118 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11119 }
11120
11121 if (GRLen == 64)
11122 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11123 return Result;
11124}
11125
11127 const MachineFunction &MF, EVT VT) const {
11128 VT = VT.getScalarType();
11129
11130 if (!VT.isSimple())
11131 return false;
11132
11133 switch (VT.getSimpleVT().SimpleTy) {
11134 case MVT::f32:
11135 case MVT::f64:
11136 return true;
11137 default:
11138 break;
11139 }
11140
11141 return false;
11142}
11143
11145 const Constant *PersonalityFn) const {
11146 return LoongArch::R4;
11147}
11148
11150 const Constant *PersonalityFn) const {
11151 return LoongArch::R5;
11152}
11153
11154//===----------------------------------------------------------------------===//
11155// Target Optimization Hooks
11156//===----------------------------------------------------------------------===//
11157
11159 const LoongArchSubtarget &Subtarget) {
11160 // Feature FRECIPE instrucions relative accuracy is 2^-14.
11161 // IEEE float has 23 digits and double has 52 digits.
11162 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11163 return RefinementSteps;
11164}
11165
11166static bool
11168 assert(Subtarget.hasFrecipe() &&
11169 "Reciprocal estimate queried on unsupported target");
11170
11171 if (!VT.isSimple())
11172 return false;
11173
11174 switch (VT.getSimpleVT().SimpleTy) {
11175 case MVT::f32:
11176 // f32 is the base type for reciprocal estimate instructions.
11177 return true;
11178
11179 case MVT::f64:
11180 return Subtarget.hasBasicD();
11181
11182 case MVT::v4f32:
11183 case MVT::v2f64:
11184 return Subtarget.hasExtLSX();
11185
11186 case MVT::v8f32:
11187 case MVT::v4f64:
11188 return Subtarget.hasExtLASX();
11189
11190 default:
11191 return false;
11192 }
11193}
11194
11196 SelectionDAG &DAG, int Enabled,
11197 int &RefinementSteps,
11198 bool &UseOneConstNR,
11199 bool Reciprocal) const {
11201 "Enabled should never be Disabled here");
11202
11203 if (!Subtarget.hasFrecipe())
11204 return SDValue();
11205
11206 SDLoc DL(Operand);
11207 EVT VT = Operand.getValueType();
11208
11209 // Check supported types.
11210 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11211 return SDValue();
11212
11213 // Handle refinement steps.
11214 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11215 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11216
11217 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
11218 UseOneConstNR = false;
11219 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
11220
11221 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
11222 // are needed (which rely on the reciprocal form), return the raw reciprocal
11223 // estimate.
11224 if (Reciprocal || RefinementSteps > 0)
11225 return Rsqrt;
11226
11227 // Otherwise, return sqrt(x) by multiplying with the operand.
11228 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
11229}
11230
11232 SelectionDAG &DAG,
11233 int Enabled,
11234 int &RefinementSteps) const {
11236 "Enabled should never be Disabled here");
11237
11238 if (!Subtarget.hasFrecipe())
11239 return SDValue();
11240
11241 SDLoc DL(Operand);
11242 EVT VT = Operand.getValueType();
11243
11244 // Check supported types.
11245 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11246 return SDValue();
11247
11248 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11249 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11250
11251 // FRECIPE computes 1.0 / x.
11252 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
11253}
11254
11255//===----------------------------------------------------------------------===//
11256// LoongArch Inline Assembly Support
11257//===----------------------------------------------------------------------===//
11258
11260LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
11261 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
11262 //
11263 // 'f': A floating-point register (if available).
11264 // 'k': A memory operand whose address is formed by a base register and
11265 // (optionally scaled) index register.
11266 // 'l': A signed 16-bit constant.
11267 // 'm': A memory operand whose address is formed by a base register and
11268 // offset that is suitable for use in instructions with the same
11269 // addressing mode as st.w and ld.w.
11270 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
11271 // instruction)
11272 // 'I': A signed 12-bit constant (for arithmetic instructions).
11273 // 'J': Integer zero.
11274 // 'K': An unsigned 12-bit constant (for logic instructions).
11275 // "ZB": An address that is held in a general-purpose register. The offset is
11276 // zero.
11277 // "ZC": A memory operand whose address is formed by a base register and
11278 // offset that is suitable for use in instructions with the same
11279 // addressing mode as ll.w and sc.w.
11280 if (Constraint.size() == 1) {
11281 switch (Constraint[0]) {
11282 default:
11283 break;
11284 case 'f':
11285 case 'q':
11286 return C_RegisterClass;
11287 case 'l':
11288 case 'I':
11289 case 'J':
11290 case 'K':
11291 return C_Immediate;
11292 case 'k':
11293 return C_Memory;
11294 }
11295 }
11296
11297 if (Constraint == "ZC" || Constraint == "ZB")
11298 return C_Memory;
11299
11300 // 'm' is handled here.
11301 return TargetLowering::getConstraintType(Constraint);
11302}
11303
11304InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
11305 StringRef ConstraintCode) const {
11306 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
11310 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
11311}
11312
11313std::pair<unsigned, const TargetRegisterClass *>
11314LoongArchTargetLowering::getRegForInlineAsmConstraint(
11315 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
11316 // First, see if this is a constraint that directly corresponds to a LoongArch
11317 // register class.
11318 if (Constraint.size() == 1) {
11319 switch (Constraint[0]) {
11320 case 'r':
11321 // TODO: Support fixed vectors up to GRLen?
11322 if (VT.isVector())
11323 break;
11324 return std::make_pair(0U, &LoongArch::GPRRegClass);
11325 case 'q':
11326 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
11327 case 'f':
11328 if (Subtarget.hasBasicF() && VT == MVT::f32)
11329 return std::make_pair(0U, &LoongArch::FPR32RegClass);
11330 if (Subtarget.hasBasicD() && VT == MVT::f64)
11331 return std::make_pair(0U, &LoongArch::FPR64RegClass);
11332 if (Subtarget.hasExtLSX() &&
11333 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
11334 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11335 if (Subtarget.hasExtLASX() &&
11336 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
11337 return std::make_pair(0U, &LoongArch::LASX256RegClass);
11338 break;
11339 default:
11340 break;
11341 }
11342 }
11343
11344 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
11345 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
11346 // constraints while the official register name is prefixed with a '$'. So we
11347 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
11348 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
11349 // case insensitive, so no need to convert the constraint to upper case here.
11350 //
11351 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
11352 // decode the usage of register name aliases into their official names. And
11353 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
11354 // official register names.
11355 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
11356 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
11357 bool IsFP = Constraint[2] == 'f';
11358 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
11359 std::pair<unsigned, const TargetRegisterClass *> R;
11361 TRI, join_items("", Temp.first, Temp.second), VT);
11362 // Match those names to the widest floating point register type available.
11363 if (IsFP) {
11364 unsigned RegNo = R.first;
11365 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
11366 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
11367 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
11368 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
11369 }
11370 }
11371 }
11372 return R;
11373 }
11374
11375 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
11376}
11377
11378void LoongArchTargetLowering::LowerAsmOperandForConstraint(
11379 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
11380 SelectionDAG &DAG) const {
11381 // Currently only support length 1 constraints.
11382 if (Constraint.size() == 1) {
11383 switch (Constraint[0]) {
11384 case 'l':
11385 // Validate & create a 16-bit signed immediate operand.
11386 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11387 uint64_t CVal = C->getSExtValue();
11388 if (isInt<16>(CVal))
11389 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11390 Subtarget.getGRLenVT()));
11391 }
11392 return;
11393 case 'I':
11394 // Validate & create a 12-bit signed immediate operand.
11395 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11396 uint64_t CVal = C->getSExtValue();
11397 if (isInt<12>(CVal))
11398 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11399 Subtarget.getGRLenVT()));
11400 }
11401 return;
11402 case 'J':
11403 // Validate & create an integer zero operand.
11404 if (auto *C = dyn_cast<ConstantSDNode>(Op))
11405 if (C->getZExtValue() == 0)
11406 Ops.push_back(
11407 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
11408 return;
11409 case 'K':
11410 // Validate & create a 12-bit unsigned immediate operand.
11411 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11412 uint64_t CVal = C->getZExtValue();
11413 if (isUInt<12>(CVal))
11414 Ops.push_back(
11415 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
11416 }
11417 return;
11418 default:
11419 break;
11420 }
11421 }
11423}
11424
11425#define GET_REGISTER_MATCHER
11426#include "LoongArchGenAsmMatcher.inc"
11427
11430 const MachineFunction &MF) const {
11431 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
11432 std::string NewRegName = Name.second.str();
11433 Register Reg = MatchRegisterAltName(NewRegName);
11434 if (!Reg)
11435 Reg = MatchRegisterName(NewRegName);
11436 if (!Reg)
11437 return Reg;
11438 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
11439 if (!ReservedRegs.test(Reg))
11440 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
11441 StringRef(RegName) + "\"."));
11442 return Reg;
11443}
11444
11446 EVT VT, SDValue C) const {
11447 // TODO: Support vectors.
11448 if (!VT.isScalarInteger())
11449 return false;
11450
11451 // Omit the optimization if the data size exceeds GRLen.
11452 if (VT.getSizeInBits() > Subtarget.getGRLen())
11453 return false;
11454
11455 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
11456 const APInt &Imm = ConstNode->getAPIntValue();
11457 // Break MUL into (SLLI + ADD/SUB) or ALSL.
11458 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
11459 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
11460 return true;
11461 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
11462 if (ConstNode->hasOneUse() &&
11463 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
11464 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
11465 return true;
11466 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
11467 // in which the immediate has two set bits. Or Break (MUL x, imm)
11468 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
11469 // equals to (1 << s0) - (1 << s1).
11470 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
11471 unsigned Shifts = Imm.countr_zero();
11472 // Reject immediates which can be composed via a single LUI.
11473 if (Shifts >= 12)
11474 return false;
11475 // Reject multiplications can be optimized to
11476 // (SLLI (ALSL x, x, 1/2/3/4), s).
11477 APInt ImmPop = Imm.ashr(Shifts);
11478 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
11479 return false;
11480 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
11481 // since it needs one more instruction than other 3 cases.
11482 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
11483 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
11484 (ImmSmall - Imm).isPowerOf2())
11485 return true;
11486 }
11487 }
11488
11489 return false;
11490}
11491
11493 const AddrMode &AM,
11494 Type *Ty, unsigned AS,
11495 Instruction *I) const {
11496 // LoongArch has four basic addressing modes:
11497 // 1. reg
11498 // 2. reg + 12-bit signed offset
11499 // 3. reg + 14-bit signed offset left-shifted by 2
11500 // 4. reg1 + reg2
11501 // TODO: Add more checks after support vector extension.
11502
11503 // No global is ever allowed as a base.
11504 if (AM.BaseGV)
11505 return false;
11506
11507 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
11508 // with `UAL` feature.
11509 if (!isInt<12>(AM.BaseOffs) &&
11510 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
11511 return false;
11512
11513 switch (AM.Scale) {
11514 case 0:
11515 // "r+i" or just "i", depending on HasBaseReg.
11516 break;
11517 case 1:
11518 // "r+r+i" is not allowed.
11519 if (AM.HasBaseReg && AM.BaseOffs)
11520 return false;
11521 // Otherwise we have "r+r" or "r+i".
11522 break;
11523 case 2:
11524 // "2*r+r" or "2*r+i" is not allowed.
11525 if (AM.HasBaseReg || AM.BaseOffs)
11526 return false;
11527 // Allow "2*r" as "r+r".
11528 break;
11529 default:
11530 return false;
11531 }
11532
11533 return true;
11534}
11535
11537 return isInt<12>(Imm);
11538}
11539
11541 return isInt<12>(Imm);
11542}
11543
11545 // Zexts are free if they can be combined with a load.
11546 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
11547 // poorly with type legalization of compares preferring sext.
11548 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
11549 EVT MemVT = LD->getMemoryVT();
11550 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
11551 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
11552 LD->getExtensionType() == ISD::ZEXTLOAD))
11553 return true;
11554 }
11555
11556 return TargetLowering::isZExtFree(Val, VT2);
11557}
11558
11560 EVT DstVT) const {
11561 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
11562}
11563
11565 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
11566}
11567
11569 // TODO: Support vectors.
11570 if (Y.getValueType().isVector())
11571 return false;
11572
11573 return !isa<ConstantSDNode>(Y);
11574}
11575
11577 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
11578 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
11579}
11580
11582 Type *Ty, bool IsSigned) const {
11583 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
11584 return true;
11585
11586 return IsSigned;
11587}
11588
11590 // Return false to suppress the unnecessary extensions if the LibCall
11591 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
11592 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
11593 Type.getSizeInBits() < Subtarget.getGRLen()))
11594 return false;
11595 return true;
11596}
11597
11598// memcpy, and other memory intrinsics, typically tries to use wider load/store
11599// if the source/dest is aligned and the copy size is large enough. We therefore
11600// want to align such objects passed to memory intrinsics.
11602 unsigned &MinSize,
11603 Align &PrefAlign) const {
11604 if (!isa<MemIntrinsic>(CI))
11605 return false;
11606
11607 if (Subtarget.is64Bit()) {
11608 MinSize = 8;
11609 PrefAlign = Align(8);
11610 } else {
11611 MinSize = 4;
11612 PrefAlign = Align(4);
11613 }
11614
11615 return true;
11616}
11617
11620 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
11621 VT.getVectorElementType() != MVT::i1)
11622 return TypeWidenVector;
11623
11625}
11626
11627bool LoongArchTargetLowering::splitValueIntoRegisterParts(
11628 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
11629 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
11630 bool IsABIRegCopy = CC.has_value();
11631 EVT ValueVT = Val.getValueType();
11632
11633 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11634 PartVT == MVT::f32) {
11635 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
11636 // nan, and cast to f32.
11637 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
11638 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
11639 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
11640 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
11641 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
11642 Parts[0] = Val;
11643 return true;
11644 }
11645
11646 return false;
11647}
11648
11649SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
11650 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
11651 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
11652 bool IsABIRegCopy = CC.has_value();
11653
11654 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11655 PartVT == MVT::f32) {
11656 SDValue Val = Parts[0];
11657
11658 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
11659 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
11660 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
11661 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
11662 return Val;
11663 }
11664
11665 return SDValue();
11666}
11667
11668MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
11669 CallingConv::ID CC,
11670 EVT VT) const {
11671 // Use f32 to pass f16.
11672 if (VT == MVT::f16 && Subtarget.hasBasicF())
11673 return MVT::f32;
11674
11676}
11677
11678unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
11679 LLVMContext &Context, CallingConv::ID CC, EVT VT) const {
11680 // Use f32 to pass f16.
11681 if (VT == MVT::f16 && Subtarget.hasBasicF())
11682 return 1;
11683
11685}
11686
11688 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
11689 const SelectionDAG &DAG, unsigned Depth) const {
11690 unsigned Opc = Op.getOpcode();
11691 Known.resetAll();
11692 switch (Opc) {
11693 default:
11694 break;
11695 case LoongArchISD::VPICK_ZEXT_ELT: {
11696 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
11697 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
11698 unsigned VTBits = VT.getScalarSizeInBits();
11699 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
11700 Known.Zero.setBitsFrom(VTBits);
11701 break;
11702 }
11703 }
11704}
11705
11707 SDValue Op, const APInt &OriginalDemandedBits,
11708 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
11709 unsigned Depth) const {
11710 EVT VT = Op.getValueType();
11711 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
11712 unsigned Opc = Op.getOpcode();
11713 switch (Opc) {
11714 default:
11715 break;
11716 case LoongArchISD::CRC_W_B_W:
11717 case LoongArchISD::CRC_W_H_W:
11718 case LoongArchISD::CRCC_W_B_W:
11719 case LoongArchISD::CRCC_W_H_W: {
11720 KnownBits KnownSrc;
11721 APInt DemandedSrcBits =
11722 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
11723 Opc == LoongArchISD::CRCC_W_B_W)
11724 ? 8
11725 : 16);
11726 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
11727 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
11728 }
11729 case LoongArchISD::VMSKLTZ:
11730 case LoongArchISD::XVMSKLTZ: {
11731 SDValue Src = Op.getOperand(0);
11732 MVT SrcVT = Src.getSimpleValueType();
11733 unsigned SrcBits = SrcVT.getScalarSizeInBits();
11734 unsigned NumElts = SrcVT.getVectorNumElements();
11735
11736 // If we don't need the sign bits at all just return zero.
11737 if (OriginalDemandedBits.countr_zero() >= NumElts)
11738 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
11739
11740 // Only demand the vector elements of the sign bits we need.
11741 APInt KnownUndef, KnownZero;
11742 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
11743 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
11744 TLO, Depth + 1))
11745 return true;
11746
11747 Known.Zero = KnownZero.zext(BitWidth);
11748 Known.Zero.setHighBits(BitWidth - NumElts);
11749
11750 // [X]VMSKLTZ only uses the MSB from each vector element.
11751 KnownBits KnownSrc;
11752 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
11753 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
11754 Depth + 1))
11755 return true;
11756
11757 if (KnownSrc.One[SrcBits - 1])
11758 Known.One.setLowBits(NumElts);
11759 else if (KnownSrc.Zero[SrcBits - 1])
11760 Known.Zero.setLowBits(NumElts);
11761
11762 // Attempt to avoid multi-use ops if we don't need anything from it.
11764 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
11765 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
11766 return false;
11767 }
11768 }
11769
11771 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
11772}
11773
11775 unsigned Opc = VecOp.getOpcode();
11776
11777 // Assume target opcodes can't be scalarized.
11778 // TODO - do we have any exceptions?
11779 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
11780 return false;
11781
11782 // If the vector op is not supported, try to convert to scalar.
11783 EVT VecVT = VecOp.getValueType();
11785 return true;
11786
11787 // If the vector op is supported, but the scalar op is not, the transform may
11788 // not be worthwhile.
11789 EVT ScalarVT = VecVT.getScalarType();
11790 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
11791}
11792
11794 unsigned Index) const {
11796 return false;
11797
11798 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
11799 return Index == 0;
11800}
11801
11803 unsigned Index) const {
11804 EVT EltVT = VT.getScalarType();
11805
11806 // Extract a scalar FP value from index 0 of a vector is free.
11807 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
11808}
11809
11811 const MachineFunction &MF) const {
11812
11813 // If the function specifically requests inline stack probes, emit them.
11814 if (MF.getFunction().hasFnAttribute("probe-stack"))
11815 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
11816 "inline-asm";
11817
11818 return false;
11819}
11820
11822 Align StackAlign) const {
11823 // The default stack probe size is 4096 if the function has no
11824 // stack-probe-size attribute.
11825 const Function &Fn = MF.getFunction();
11826 unsigned StackProbeSize =
11827 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
11828 // Round down to the stack alignment.
11829 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
11830 return StackProbeSize ? StackProbeSize : StackAlign.value();
11831}
11832
11833SDValue
11834LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
11835 SelectionDAG &DAG) const {
11837 if (!hasInlineStackProbe(MF))
11838 return SDValue();
11839
11840 const MVT GRLenVT = Subtarget.getGRLenVT();
11841 // Get the inputs.
11842 SDValue Chain = Op.getOperand(0);
11843 SDValue Size = Op.getOperand(1);
11844
11845 const MaybeAlign Align =
11846 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
11847 const SDLoc dl(Op);
11848 const EVT VT = Op.getValueType();
11849
11850 // Construct the new SP value in a GPR.
11851 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
11852 Chain = SP.getValue(1);
11853 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
11854 if (Align)
11855 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
11856 DAG.getSignedConstant(-Align->value(), dl, VT));
11857
11858 // Set the real SP to the new value with a probing loop.
11859 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
11860 return DAG.getMergeValues({SP, Chain}, dl);
11861}
11862
11865 MachineBasicBlock *MBB) const {
11866 MachineFunction &MF = *MBB->getParent();
11867 MachineBasicBlock::iterator MBBI = MI.getIterator();
11868 DebugLoc DL = MBB->findDebugLoc(MBBI);
11869 const Register TargetReg = MI.getOperand(0).getReg();
11870
11871 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
11872 const bool IsLA64 = Subtarget.is64Bit();
11873 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
11874 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
11875 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
11876
11877 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
11878 MachineBasicBlock *const LoopTestMBB =
11879 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
11880 MF.insert(MBBInsertPoint, LoopTestMBB);
11881 MachineBasicBlock *const ExitMBB =
11882 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
11883 MF.insert(MBBInsertPoint, ExitMBB);
11884 const Register SPReg = LoongArch::R3;
11885 const Register ScratchReg =
11886 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
11887
11888 // ScratchReg = ProbeSize
11889 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
11890
11891 // LoopTest:
11892 // sub.{w/d} $sp, $sp, ScratchReg
11893 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
11894 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
11895 .addReg(SPReg)
11896 .addReg(ScratchReg);
11897
11898 // st.{w/d} $zero, $sp, 0
11899 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
11900 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
11901 .addReg(LoongArch::R0)
11902 .addReg(SPReg)
11903 .addImm(0);
11904
11905 // bltu TargetReg, $sp, LoopTest
11906 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
11907 .addReg(TargetReg)
11908 .addReg(SPReg)
11909 .addMBB(LoopTestMBB);
11910
11911 // move $sp, TargetReg
11912 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
11913 .addReg(TargetReg)
11914 .addReg(LoongArch::R0);
11915
11916 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
11918
11919 LoopTestMBB->addSuccessor(ExitMBB);
11920 LoopTestMBB->addSuccessor(LoopTestMBB);
11921 MBB->addSuccessor(LoopTestMBB);
11922
11923 MI.eraseFromParent();
11924 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
11925 return ExitMBB->begin()->getParent();
11926}
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)
return SDValue()
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSELECT_CCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
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:856
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 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 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 lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKEV (if possible).
static MachineBasicBlock * emitPseudoVMSKCOND(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performVANDNCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
Do target-specific dag combines on LoongArchISD::VANDN nodes.
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
static cl::opt< MaterializeFPImm > MaterializeFPImmInsNum("loongarch-materialize-float-imm", cl::Hidden, cl::desc("Maximum number of instructions used (including code sequence " "to generate the value and moving the value to FPR) when " "materializing floating-point immediates (default = 3)"), cl::init(MaterializeFPImm3Ins), cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"), clEnumValN(MaterializeFPImm2Ins, "2", "Materialize FP immediate within 2 instructions"), clEnumValN(MaterializeFPImm3Ins, "3", "Materialize FP immediate within 3 instructions"), clEnumValN(MaterializeFPImm4Ins, "4", "Materialize FP immediate within 4 instructions"), clEnumValN(MaterializeFPImm5Ins, "5", "Materialize FP immediate within 5 instructions"), clEnumValN(MaterializeFPImm6Ins, "6", "Materialize FP immediate within 6 instructions " "(behaves same as 5 on loongarch64)")))
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
const MCPhysReg ArgXRs[]
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
static unsigned getLoongArchWOpcode(unsigned Opcode)
const MCPhysReg ArgFPR64s[]
static MachineBasicBlock * emitPseudoCTPOP(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performMOVGR2FR_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKOD (if possible).
static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL)
static SDValue isNOT(SDValue V, SelectionDAG &DAG)
static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 256-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
const MCPhysReg PreserveNoneArgGPRs[]
static void fillVector(ArrayRef< SDValue > Ops, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, SDValue &Vector, EVT ResTy)
static SDValue fillSubVectorFromBuildVector(BuildVectorSDNode *Node, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, EVT ResTy, unsigned first)
static bool isSelectPseudo(MachineInstr &MI)
static SDValue 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_XVPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode, unsigned ScalarSizeInBits, ArrayRef< int > Mask, int MaskOffset, const APInt &Zeroable)
Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI instruction.
static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVL (if possible).
static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG)
static MachineBasicBlock * emitBuildPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
static void replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
#define CSR_CASE(ID)
static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode, unsigned BlockBits)
static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKOD (if possible).
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS, ISD::CondCode &CC, SelectionDAG &DAG)
static Register allocateArgGPR(CCState &State)
static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT, ArrayRef< int > Mask, SmallVectorImpl< int > &RepeatedMask)
Test whether a shuffle mask is equivalent within each sub-lane.
static SDValue convertRMEncoding(SelectionDAG &DAG, const SDLoc &DL, MVT GRLenVT, SDValue RMValue)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO)
static constexpr MCPhysReg SPReg
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue, bool AllowSymbol=false)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool isSequentialOrUndefInRange(ArrayRef< int > Mask, unsigned Pos, unsigned Size, int Low, int Step=1)
Return true if every element in Mask, beginning from position Pos and ending in Pos + Size,...
Value * RHS
Value * LHS
bool isZero() const
Definition APFloat.h:1561
LLVM_READONLY bool isOne() const
Definition APFloat.h:1643
APInt bitcastToAPInt() const
Definition APFloat.h:1457
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:235
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1055
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:230
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1565
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1076
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:968
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1355
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:372
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:381
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1692
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1664
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:436
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1266
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:307
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:201
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
Definition APInt.h:287
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1587
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:858
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:43
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:211
iterator_range< arg_iterator > args()
Definition Function.h:866
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:758
uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const
For a string attribute Kind, parse attribute as an integer.
Definition Function.cpp:770
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:272
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
Argument * getArg(unsigned i) const
Definition Function.h:860
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:723
bool isDSOLocal() const
Common base class shared among various IRBuilders.
Definition IRBuilder.h:114
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2893
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:68
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 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...
SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps, bool &UseOneConstNR, bool Reciprocal) const override
Hooks for building estimates in place of slower divisions and square roots.
bool isLegalICmpImmediate(int64_t Imm) const override
Return true if the specified immediate is legal icmp immediate, that is the target has icmp instructi...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< bool, uint64_t > isImmVLDILegalForMode1(const APInt &SplatValue, const unsigned SplatBitSize) const
Check if a constant splat can be generated using [x]vldi, where imm[12] is 1.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this function.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
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 isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, unsigned Index) const override
Return true if EXTRACT_SUBVECTOR is cheap for extracting this result type from this source type with ...
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...
Register getExceptionPointerRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
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
Register getExceptionSelectorRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
bool isImplicitDef() const
LLVM_ABI void collectDebugValues(SmallVectorImpl< MachineInstr * > &DbgValues)
Scan instructions immediately following MI and collect any matching DBG_VALUEs.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Align getAlign() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const MachinePointerInfo & getPointerInfo() const
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
Class to represent pointers.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
LLVM_ABI bool isOnlyUserOf(const SDNode *N) const
Return true if this node is the only use of N.
size_t use_size() const
Return the number of uses of this node.
MVT getSimpleValueType(unsigned ResNo) const
Return the type of a specified result as a simple type.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
MVT getSimpleValueType() const
Return the simple ValueType of the referenced return value.
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
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 AAMDNodes &AAInfo=AAMDNodes())
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget=false, bool IsOpaque=false)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getFreeze(SDValue V)
Return a freeze using the SDLoc of the value operand.
bool isSafeToSpeculativelyExecute(unsigned Opcode) const
Some opcodes may create immediate undefined behavior when used with some values (integer division-by-...
SDValue getExtractSubvector(const SDLoc &DL, EVT VT, SDValue Vec, unsigned Idx)
Return the VT typed sub-vector of Vec at Idx.
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr)
Loads are not normal binary operators: their result type is not determined by their operands,...
SDValue getInsertSubvector(const SDLoc &DL, SDValue Vec, SDValue SubVec, unsigned Idx)
Insert SubVec at the Idx element of Vec.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
LLVM_ABI SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align DstAlign, Align SrcAlign, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
const TargetLowering & getTargetLoweringInfo() const
static constexpr unsigned MaxRecursionDepth
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI bool isSplatValue(SDValue V, const APInt &DemandedElts, APInt &UndefElts, unsigned Depth=0) const
Test whether V has a splatted value for all the demanded elements.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
LLVM_ABI SDValue getNegative(SDValue Val, const SDLoc &DL, EVT VT)
Create negative operation as (SUB 0, Val).
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
LLVM_ABI SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT VT)
Return the expression required to zero extend the Op value assuming it was the smaller SrcTy value.
const DataLayout & getDataLayout() const
LLVM_ABI SDValue 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 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 getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
Helper function to build ISD::STORE nodes.
LLVM_ABI 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 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)
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 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:30
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.
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.
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:197
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:313
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:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
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:41
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:829
@ 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:513
@ DELETED_NODE
DELETED_NODE - This is an illegal value that is used to catch errors.
Definition ISDOpcodes.h:45
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:275
@ INSERT_SUBVECTOR
INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector with VECTOR2 inserted into VECTOR1.
Definition ISDOpcodes.h:602
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:789
@ 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:264
@ 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:863
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:520
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:220
@ GlobalAddress
Definition ISDOpcodes.h:88
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:890
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:586
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:417
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:749
@ 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:920
@ 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:254
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:89
@ SET_ROUNDING
Set rounding mode.
Definition ISDOpcodes.h:985
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:854
@ AVGCEILS
AVGCEILS/AVGCEILU - Rounding averaging add - Add two integers using an integer of type i[N+2],...
Definition ISDOpcodes.h:717
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:667
@ 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:543
@ IS_FPCLASS
Performs a check of floating point class property, defined by IEEE-754.
Definition ISDOpcodes.h:550
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:374
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:806
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:233
@ 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:980
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:706
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:771
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:651
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:616
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Perform floating-point minimumNumber or maximumNumber on two values,...
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition ISDOpcodes.h:139
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:578
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:224
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:860
@ 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:821
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ FMINNUM
FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values, following IEEE-754 definition...
@ 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:898
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:729
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:988
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:815
@ EH_DWARF_CFA
EH_DWARF_CFA - This node represents the pointer to the DWARF Canonical Frame Address (CFA),...
Definition ISDOpcodes.h:150
@ 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:110
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:936
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:741
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:205
@ AVGFLOORS
AVGFLOORS/AVGFLOORU - Averaging add - Add two integers using an integer of type i[N+1],...
Definition ISDOpcodes.h:712
@ FREEZE
FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or is evaluated to UNDEF),...
Definition ISDOpcodes.h:241
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:567
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:53
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:969
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:931
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:866
@ 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:843
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition ISDOpcodes.h:62
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:365
@ ABDS
ABDS/ABDU - Absolute difference - Return the absolute difference between two numbers interpreted as s...
Definition ISDOpcodes.h:724
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:213
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:558
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:55
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:383
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:573
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:1739
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:165
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Known
Known to have no common set bits.
@ Kill
The last use of a register.
@ 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
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:284
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:337
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:273
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:1746
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:279
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:261
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
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
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:182
constexpr unsigned BitWidth
std::string join_items(Sep Separator, Args &&... Items)
Joins the strings in the parameter pack Items, adding Separator between the elements....
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
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:862
#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:77
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
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:307
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:323
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:155
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:230
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition ValueTypes.h:55
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:235
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:484
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:160
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:106
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...