LLVM 24.0.0git
LoongArchISelLowering.cpp
Go to the documentation of this file.
1//=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the interfaces that LoongArch uses to lower LLVM code into
10// a selection DAG.
11//
12//===----------------------------------------------------------------------===//
13
15#include "LoongArch.h"
19#include "LoongArchSubtarget.h"
23#include "llvm/ADT/SmallSet.h"
24#include "llvm/ADT/Statistic.h"
30#include "llvm/IR/IRBuilder.h"
32#include "llvm/IR/IntrinsicsLoongArch.h"
34#include "llvm/Support/Debug.h"
39
40using namespace llvm;
41
42#define DEBUG_TYPE "loongarch-isel-lowering"
43
44STATISTIC(NumTailCalls, "Number of tail calls");
45
54
56 "loongarch-materialize-float-imm", cl::Hidden,
57 cl::desc("Maximum number of instructions used (including code sequence "
58 "to generate the value and moving the value to FPR) when "
59 "materializing floating-point immediates (default = 3)"),
61 cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"),
63 "Materialize FP immediate within 2 instructions"),
65 "Materialize FP immediate within 3 instructions"),
67 "Materialize FP immediate within 4 instructions"),
69 "Materialize FP immediate within 5 instructions"),
71 "Materialize FP immediate within 6 instructions "
72 "(behaves same as 5 on loongarch64)")));
73
74static cl::opt<bool> ZeroDivCheck("loongarch-check-zero-division", cl::Hidden,
75 cl::desc("Trap on integer division by zero."),
76 cl::init(false));
77
79 const LoongArchSubtarget &STI)
80 : TargetLowering(TM, STI), Subtarget(STI) {
81
82 MVT GRLenVT = Subtarget.getGRLenVT();
83
84 // Set up the register classes.
85
86 addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
87 if (Subtarget.hasBasicF())
88 addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
89 if (Subtarget.hasBasicD())
90 addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
91
92 static const MVT::SimpleValueType LSXVTs[] = {
93 MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64};
94 static const MVT::SimpleValueType LASXVTs[] = {
95 MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v8f32, MVT::v4f64};
96
97 if (Subtarget.hasExtLSX())
98 for (MVT VT : LSXVTs)
99 addRegisterClass(VT, &LoongArch::LSX128RegClass);
100
101 if (Subtarget.hasExtLASX())
102 for (MVT VT : LASXVTs)
103 addRegisterClass(VT, &LoongArch::LASX256RegClass);
104
105 // Set operations for LA32 and LA64.
106
108 MVT::i1, Promote);
109
114 if (Subtarget.hasBasicF())
118
121 GRLenVT, Custom);
122
124
129
131 setOperationAction(ISD::TRAP, MVT::Other, Legal);
132
136
138
139 // BITREV/REVB requires the 32S feature.
140 if (STI.has32S()) {
141 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
142 // we get to know which of sll and revb.2h is faster.
145
146 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
147 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
148 // and i32 could still be byte-swapped relatively cheaply.
150 } else {
158 }
159
166
169
170 // Set operations for LA64 only.
171
172 if (Subtarget.is64Bit()) {
190
194 Custom);
196 }
197
198 // Set operations for LA32 only.
199
200 if (!Subtarget.is64Bit()) {
206 if (Subtarget.hasBasicD())
208 }
209
211
212 static const ISD::CondCode FPCCToExpand[] = {
215
216 // Set operations for 'F' feature.
217
218 if (Subtarget.hasBasicF()) {
219 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
220 setTruncStoreAction(MVT::f32, MVT::f16, Expand);
221 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::bf16, Expand);
222 setTruncStoreAction(MVT::f32, MVT::bf16, Expand);
223 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
224
243 Subtarget.isSoftFPABI() ? LibCall : Custom);
245 Subtarget.isSoftFPABI() ? LibCall : Custom);
248 Subtarget.isSoftFPABI() ? LibCall : Custom);
251
252 if (Subtarget.is64Bit())
254
255 if (!Subtarget.hasBasicD()) {
257 if (Subtarget.is64Bit()) {
260 }
261 }
262 }
263
264 // Set operations for 'D' feature.
265
266 if (Subtarget.hasBasicD()) {
267 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
268 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
269 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::bf16, Expand);
270 setTruncStoreAction(MVT::f64, MVT::bf16, Expand);
271 setTruncStoreAction(MVT::f64, MVT::f16, Expand);
272 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
273 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
274
294 Subtarget.isSoftFPABI() ? LibCall : Custom);
297 Subtarget.isSoftFPABI() ? LibCall : Custom);
298
299 if (Subtarget.is64Bit())
301 }
302
303 // Set operations for 'LSX' feature.
304
305 if (Subtarget.hasExtLSX()) {
307 // Expand all truncating stores and extending loads.
308 for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
309 setTruncStoreAction(VT, InnerVT, Expand);
312 setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
313 }
314 // By default everything must be expanded. Then we will selectively turn
315 // on ones that can be effectively codegen'd.
316 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
318 }
319
320 for (MVT VT : LSXVTs) {
324
328
333 }
334 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
337 Legal);
339 VT, Legal);
346 Expand);
361 }
362 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
364 for (MVT VT : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
366 for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
370 }
372 for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
380 VT, Expand);
388 }
390 setOperationAction(ISD::FCEIL, {MVT::f32, MVT::f64}, Legal);
391 setOperationAction(ISD::FFLOOR, {MVT::f32, MVT::f64}, Legal);
392 setOperationAction(ISD::FTRUNC, {MVT::f32, MVT::f64}, Legal);
393 setOperationAction(ISD::FROUNDEVEN, {MVT::f32, MVT::f64}, Legal);
394
395 for (MVT VT :
396 {MVT::v16i8, MVT::v8i8, MVT::v4i8, MVT::v2i8, MVT::v8i16, MVT::v4i16,
397 MVT::v2i16, MVT::v4i32, MVT::v2i32, MVT::v2i64}) {
407 }
410 // We want to legalize this to an f64 load rather than an i64 load.
411 setOperationAction(ISD::LOAD, MVT::v2f32, Custom);
412 for (MVT VT : {MVT::v2i64, MVT::v4i32, MVT::v8i16})
414 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v16i32, MVT::v8i64,
415 MVT::v16i64})
417 }
418
419 // Set operations for 'LASX' feature.
420
421 if (Subtarget.hasExtLASX()) {
422 for (MVT VT : LASXVTs) {
426
432
436 }
437 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
440 Legal);
442 VT, Legal);
449 Expand);
465 }
466 for (MVT VT : {MVT::v32i8, MVT::v16i16, MVT::v8i32})
468 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64})
470 for (MVT VT : {MVT::v8i32, MVT::v4i64})
472 for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
476 }
477 for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
485 VT, Expand);
493 }
496 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
500 }
501 for (MVT VT :
502 {MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
505 }
506 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
508 }
509
510 // Set DAG combine for LA32 and LA64.
511 if (Subtarget.hasBasicF()) {
513 }
514
522
523 // On targets with the 32S feature, `select` is expanded into
524 // maskeqz + masknez + or (3 instructions), which is more expensive than
525 // on most other architectures where a single cmov-like instruction
526 // suffices. Enable a combine that can turn
527 // select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
528 // select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
529 // for binop in {add, or, xor, sub}, replacing the 3-insn select (plus
530 // the original binop) with a single mask instruction plus the binop.
531 if (Subtarget.has32S())
533
534 // Set DAG combine for 'LSX' feature.
535
536 if (Subtarget.hasExtLSX()) {
549 }
550
551 // Set DAG combine for 'LASX' feature.
552 if (Subtarget.hasExtLASX()) {
555 }
556
557 // Compute derived properties from the register classes.
558 computeRegisterProperties(Subtarget.getRegisterInfo());
559
561
564
565 setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
566
568
569 // Function alignments.
571 // Set preferred alignments.
572 setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
573 setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
574 setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
575
576 // cmpxchg sizes down to 8 bits become legal if LAMCAS is available.
577 if (Subtarget.hasLAMCAS())
579
580 if (Subtarget.hasSCQ()) {
583 }
584
585 // Disable strict node mutation.
586 IsStrictFPEnabled = true;
587}
588
590 const GlobalAddressSDNode *GA) const {
591 // In order to maximise the opportunity for common subexpression elimination,
592 // keep a separate ADD node for the global address offset instead of folding
593 // it in the global address node. Later peephole optimisations may choose to
594 // fold it back in when profitable.
595 return false;
596}
597
599 SelectionDAG &DAG) const {
600 switch (Op.getOpcode()) {
602 return lowerATOMIC_FENCE(Op, DAG);
604 return lowerEH_DWARF_CFA(Op, DAG);
606 return lowerGlobalAddress(Op, DAG);
608 return lowerGlobalTLSAddress(Op, DAG);
610 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
612 return lowerINTRINSIC_W_CHAIN(Op, DAG);
614 return lowerINTRINSIC_VOID(Op, DAG);
616 return lowerBlockAddress(Op, DAG);
617 case ISD::JumpTable:
618 return lowerJumpTable(Op, DAG);
619 case ISD::SHL_PARTS:
620 return lowerShiftLeftParts(Op, DAG);
621 case ISD::SRA_PARTS:
622 return lowerShiftRightParts(Op, DAG, true);
623 case ISD::SRL_PARTS:
624 return lowerShiftRightParts(Op, DAG, false);
626 return lowerConstantPool(Op, DAG);
627 case ISD::FP_TO_SINT:
628 return lowerFP_TO_SINT(Op, DAG);
629 case ISD::FP_TO_UINT:
630 return lowerFP_TO_UINT(Op, DAG);
632 return lowerFP_TO_SINT_SAT(Op, DAG);
633 case ISD::BITCAST:
634 return lowerBITCAST(Op, DAG);
635 case ISD::UINT_TO_FP:
636 return lowerUINT_TO_FP(Op, DAG);
637 case ISD::SINT_TO_FP:
638 return lowerSINT_TO_FP(Op, DAG);
639 case ISD::VASTART:
640 return lowerVASTART(Op, DAG);
641 case ISD::FRAMEADDR:
642 return lowerFRAMEADDR(Op, DAG);
643 case ISD::RETURNADDR:
644 return lowerRETURNADDR(Op, DAG);
646 return lowerSET_ROUNDING(Op, DAG);
648 return lowerGET_ROUNDING(Op, DAG);
650 return lowerWRITE_REGISTER(Op, DAG);
652 return lowerINSERT_VECTOR_ELT(Op, DAG);
654 return lowerEXTRACT_VECTOR_ELT(Op, DAG);
656 return lowerBUILD_VECTOR(Op, DAG);
658 return lowerCONCAT_VECTORS(Op, DAG);
660 return lowerVECTOR_SHUFFLE(Op, DAG);
661 case ISD::BITREVERSE:
662 return lowerBITREVERSE(Op, DAG);
664 return lowerSCALAR_TO_VECTOR(Op, DAG);
665 case ISD::PREFETCH:
666 return lowerPREFETCH(Op, DAG);
667 case ISD::SELECT:
668 return lowerSELECT(Op, DAG);
669 case ISD::BRCOND:
670 return lowerBRCOND(Op, DAG);
671 case ISD::FP_TO_FP16:
672 return lowerFP_TO_FP16(Op, DAG);
673 case ISD::FP16_TO_FP:
674 return lowerFP16_TO_FP(Op, DAG);
675 case ISD::FP_TO_BF16:
676 return lowerFP_TO_BF16(Op, DAG);
677 case ISD::BF16_TO_FP:
678 return lowerBF16_TO_FP(Op, DAG);
680 return lowerVECREDUCE_ADD(Op, DAG);
681 case ISD::ROTL:
682 case ISD::ROTR:
683 return lowerRotate(Op, DAG);
691 return lowerVECREDUCE(Op, DAG);
692 case ISD::ConstantFP:
693 return lowerConstantFP(Op, DAG);
694 case ISD::SETCC:
695 return lowerSETCC(Op, DAG);
696 case ISD::FP_ROUND:
697 return lowerFP_ROUND(Op, DAG);
698 case ISD::FP_EXTEND:
699 return lowerFP_EXTEND(Op, DAG);
701 return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
703 return lowerDYNAMIC_STACKALLOC(Op, DAG);
704 case ISD::ANY_EXTEND:
705 return lowerANY_EXTEND(Op, DAG);
706 case ISD::VSELECT:
707 return lowerVSELECT(Op, DAG);
708 }
709 return SDValue();
710}
711
712// Helper to attempt to return a cheaper, bit-inverted version of \p V.
714 // TODO: don't always ignore oneuse constraints.
716 EVT VT = V.getValueType();
717
718 // Match not(xor X, -1) -> X.
719 if (V.getOpcode() == ISD::XOR &&
720 (ISD::isBuildVectorAllOnes(V.getOperand(1).getNode()) ||
721 isAllOnesConstant(V.getOperand(1))))
722 return V.getOperand(0);
723
724 // Match not(extract_subvector(not(X)) -> extract_subvector(X).
725 if (V.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
726 (isNullConstant(V.getOperand(1)) || V.getOperand(0).hasOneUse())) {
727 if (SDValue Not = isNOT(V.getOperand(0), DAG)) {
728 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
729 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(Not), VT, Not,
730 V.getOperand(1));
731 }
732 }
733
734 // Match not(SplatVector(not(X)) -> SplatVector(X).
735 if (V.getOpcode() == ISD::BUILD_VECTOR) {
736 if (SDValue SplatValue =
737 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
738 if (!V->isOnlyUserOf(SplatValue.getNode()))
739 return SDValue();
740
741 if (SDValue Not = isNOT(SplatValue, DAG)) {
742 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
743 return DAG.getSplat(VT, SDLoc(Not), Not);
744 }
745 }
746 }
747
748 // Match not(or(not(X),not(Y))) -> and(X, Y).
749 if (V.getOpcode() == ISD::OR && DAG.getTargetLoweringInfo().isTypeLegal(VT) &&
750 V.getOperand(0).hasOneUse() && V.getOperand(1).hasOneUse()) {
751 // TODO: Handle cases with single NOT operand -> VANDN
752 if (SDValue Op1 = isNOT(V.getOperand(1), DAG))
753 if (SDValue Op0 = isNOT(V.getOperand(0), DAG))
754 return DAG.getNode(ISD::AND, SDLoc(V), VT, DAG.getBitcast(VT, Op0),
755 DAG.getBitcast(VT, Op1));
756 }
757
758 // TODO: Add more matching patterns. Such as,
759 // not(concat_vectors(not(X), not(Y))) -> concat_vectors(X, Y).
760 // not(slt(C, X)) -> slt(X - 1, C)
761 return SDValue();
762}
763
764// Combine two ISD::FP_ROUND / LoongArchISD::VFCVT nodes with same type to
765// LoongArchISD::VFCVT. For example:
766// x1 = fp_round x, 0
767// y1 = fp_round y, 0
768// z = concat_vectors x1, y1
769// Or
770// x1 = LoongArch::VFCVT undef, x
771// y1 = LoongArch::VFCVT undef, y
772// z = LoongArchISD::VPACKEV y1, x1; or LoongArchISD::VPERMI y1, x1, 68
773// can be combined to:
774// z = LoongArch::VFCVT y, x
777 assert(((N->getOpcode() == ISD::CONCAT_VECTORS && N->getNumOperands() == 2) ||
778 (N->getOpcode() == LoongArchISD::VPACKEV) ||
779 (N->getOpcode() == LoongArchISD::VPERMI)) &&
780 "Invalid Node");
781
782 SDValue Op0 = peekThroughBitcasts(N->getOperand(0));
783 SDValue Op1 = peekThroughBitcasts(N->getOperand(1));
784 unsigned Opcode0 = Op0.getOpcode();
785 unsigned Opcode1 = Op1.getOpcode();
786 if (Opcode0 != Opcode1)
787 return SDValue();
788
789 if (Opcode0 != ISD::FP_ROUND && Opcode0 != LoongArchISD::VFCVT)
790 return SDValue();
791
792 // Check if two nodes have only one use.
793 if (!Op0.hasOneUse() || !Op1.hasOneUse())
794 return SDValue();
795
796 EVT VT = N.getValueType();
797 EVT SVT0 = Op0.getValueType();
798 EVT SVT1 = Op1.getValueType();
799 // Check if two nodes have the same result type.
800 if (SVT0 != SVT1)
801 return SDValue();
802
803 // Check if two nodes have the same operand type.
804 EVT SSVT0 = Op0.getOperand(0).getValueType();
805 EVT SSVT1 = Op1.getOperand(0).getValueType();
806 if (SSVT0 != SSVT1)
807 return SDValue();
808
809 if (N->getOpcode() == ISD::CONCAT_VECTORS && Opcode0 == ISD::FP_ROUND) {
810 if (Subtarget.hasExtLASX() && VT.is256BitVector() && SVT0 == MVT::v4f32 &&
811 SSVT0 == MVT::v4f64) {
812 // A vector_shuffle is required in the final step, as xvfcvt instruction
813 // operates on each 128-bit segament as a lane.
814 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v8f32,
815 Op1.getOperand(0), Op0.getOperand(0));
816 SDValue Undef = DAG.getUNDEF(Res.getValueType());
817 // After VFCVT, the high part of Res comes from the high parts of Op0 and
818 // Op1, and the low part comes from the low parts of Op0 and Op1. However,
819 // the desired order requires Op0 to fully occupy the lower half and Op1
820 // the upper half of Res. The Mask reorders the elements of Res to achieve
821 // this:
822 // - The first four elements (0, 1, 4, 5) come from Op0.
823 // - The next four elements (2, 3, 6, 7) come from Op1.
824 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
825 Res = DAG.getVectorShuffle(Res.getValueType(), DL, Res, Undef, Mask);
826 return DAG.getBitcast(VT, Res);
827 }
828 }
829
830 if ((N->getOpcode() == LoongArchISD::VPACKEV ||
831 N->getOpcode() == LoongArchISD::VPERMI) &&
832 Opcode0 == LoongArchISD::VFCVT) {
833 // For VPACKEV or VPERMI, check if the first operation of VFCVT is undef.
834 if (!Op0.getOperand(0).isUndef() || !Op1.getOperand(0).isUndef())
835 return SDValue();
836
837 if (!Subtarget.hasExtLSX() || SVT0 != MVT::v4f32 || SSVT0 != MVT::v2f64)
838 return SDValue();
839
840 if (N->getOpcode() == LoongArchISD::VPACKEV &&
841 (VT == MVT::v2i64 || VT == MVT::v2f64)) {
842 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32,
843 Op0.getOperand(1), Op1.getOperand(1));
844 return DAG.getBitcast(VT, Res);
845 }
846
847 if (N->getOpcode() == LoongArchISD::VPERMI && VT == MVT::v4f32) {
848 int64_t Imm = cast<ConstantSDNode>(N->getOperand(2))->getSExtValue();
849 if (Imm != 68)
850 return SDValue();
851 return DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Op0.getOperand(1),
852 Op1.getOperand(1));
853 }
854 }
855
856 return SDValue();
857}
858
859SDValue LoongArchTargetLowering::lowerFP_ROUND(SDValue Op,
860 SelectionDAG &DAG) const {
861 SDLoc DL(Op);
862 SDValue In = Op.getOperand(0);
863 MVT VT = Op.getSimpleValueType();
864 MVT SVT = In.getSimpleValueType();
865
866 if (VT == MVT::v4f32 && SVT == MVT::v4f64) {
867 SDValue Lo, Hi;
868 std::tie(Lo, Hi) = DAG.SplitVector(In, DL);
869 return DAG.getNode(LoongArchISD::VFCVT, DL, VT, Hi, Lo);
870 }
871
872 return SDValue();
873}
874
875SDValue LoongArchTargetLowering::lowerFP_EXTEND(SDValue Op,
876 SelectionDAG &DAG) const {
877
878 SDLoc DL(Op);
879 EVT VT = Op.getValueType();
880 SDValue Src = Op->getOperand(0);
881 EVT SVT = Src.getValueType();
882
883 bool V2F32ToV2F64 =
884 VT == MVT::v2f64 && SVT == MVT::v2f32 && Subtarget.hasExtLSX();
885 bool V4F32ToV4F64 =
886 VT == MVT::v4f64 && SVT == MVT::v4f32 && Subtarget.hasExtLASX();
887 if (!V2F32ToV2F64 && !V4F32ToV4F64)
888 return SDValue();
889
890 // Check if Op is the high part of vector.
891 auto CheckVecHighPart = [](SDValue Op) {
893 if (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
894 SDValue SOp = Op.getOperand(0);
895 EVT SVT = SOp.getValueType();
896 if (!SVT.isVector() || (SVT.getVectorNumElements() % 2 != 0))
897 return SDValue();
898
899 const uint64_t Imm = Op.getConstantOperandVal(1);
900 if (Imm == SVT.getVectorNumElements() / 2)
901 return SOp;
902 return SDValue();
903 }
904 return SDValue();
905 };
906
907 unsigned Opcode;
908 SDValue VFCVTOp;
909 EVT WideOpVT = SVT.getSimpleVT().getDoubleNumVectorElementsVT();
910 SDValue ZeroIdx = DAG.getVectorIdxConstant(0, DL);
911
912 // If the operand of ISD::FP_EXTEND comes from the high part of vector,
913 // generate LoongArchISD::VFCVTH, otherwise LoongArchISD::VFCVTL.
914 if (SDValue V = CheckVecHighPart(Src)) {
915 assert(V.getValueSizeInBits() == WideOpVT.getSizeInBits() &&
916 "Unexpected wide vector");
917 Opcode = LoongArchISD::VFCVTH;
918 VFCVTOp = DAG.getBitcast(WideOpVT, V);
919 } else {
920 Opcode = LoongArchISD::VFCVTL;
921 VFCVTOp = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideOpVT,
922 DAG.getUNDEF(WideOpVT), Src, ZeroIdx);
923 }
924
925 // v2f64 = fp_extend v2f32
926 if (V2F32ToV2F64)
927 return DAG.getNode(Opcode, DL, VT, VFCVTOp);
928
929 // v4f64 = fp_extend v4f32
930 if (V4F32ToV4F64) {
931 // XVFCVT instruction operates on each 128-bit segment as a lane, so a
932 // vector_shuffle is required firstly.
933 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
934 SDValue Res = DAG.getVectorShuffle(WideOpVT, DL, VFCVTOp,
935 DAG.getUNDEF(WideOpVT), Mask);
936 Res = DAG.getNode(Opcode, DL, VT, Res);
937 return Res;
938 }
939
940 return SDValue();
941}
942
943SDValue LoongArchTargetLowering::lowerVSELECT(SDValue Op,
944 SelectionDAG &DAG) const {
945 SDValue Cond = Op.getOperand(0);
946 SDValue LHS = Op.getOperand(1);
947 SDValue RHS = Op.getOperand(2);
948 MVT VT = Op.getSimpleValueType();
949 SDLoc DL(Op);
950
951 // Try to lower vselect to vector_shuffle. All cases with constant
952 // build_vector condition will be handled. NOTE: On 32-bit platform, vselect
953 // with v2i64/v4i64 type condition will never enter this because of the extra
954 // bitcast. It can be considered separately later.
956 BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Cond.getNode());
957 APInt SplatValue, SplatUndef;
958 unsigned SplatBitSize;
959 bool HasAnyUndefs;
960
961 // If the Cond is a BUILD_VECTOR with splat constants, using a vldi or
962 // constant broadcast instruction and a vbitsel is better.
963 if (BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
964 /*MinSplatBits=*/8) &&
965 (SplatBitSize == 8 || SplatBitSize == 16 || SplatBitSize == 32 ||
966 SplatBitSize == 64))
967 return Op;
968
970 EVT CondVT = Cond.getValueType();
971 int NumElts = CondVT.getVectorNumElements();
972 Mask.resize(NumElts, -1);
973 for (int i = 0; i < NumElts; ++i) {
974 SDValue CondOp = Cond.getOperand(i);
975 if (CondOp.isUndef())
976 continue;
977 auto *CondElt = dyn_cast<ConstantSDNode>(CondOp);
978 if (CondElt->getZExtValue() == 0)
979 Mask[i] = i + NumElts;
980 else
981 Mask[i] = i;
982 }
983
984 return DAG.getVectorShuffle(VT, DL, LHS, RHS, Mask);
985 }
986
987 // Fallback to match patterns in tablegen.
988 return Op;
989}
990
991SDValue LoongArchTargetLowering::lowerConstantFP(SDValue Op,
992 SelectionDAG &DAG) const {
993 EVT VT = Op.getValueType();
994 ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
995 const APFloat &FPVal = CFP->getValueAPF();
996 SDLoc DL(CFP);
997
998 assert((VT == MVT::f32 && Subtarget.hasBasicF()) ||
999 (VT == MVT::f64 && Subtarget.hasBasicD()));
1000
1001 // If value is 0.0 or -0.0, just ignore it.
1002 if (FPVal.isZero())
1003 return SDValue();
1004
1005 // If lsx enabled, use cheaper 'vldi' instruction if possible.
1006 if (isFPImmVLDILegal(FPVal, VT))
1007 return SDValue();
1008
1009 // The legalizer builds immediates the size of a GPR from their bits. Fall
1010 // back to a load from the constant pool for expensive immediates.
1011 if (VT.getSizeInBits() == Subtarget.getGRLen() ||
1012 !isFPImmCheapInGPR(FPVal, VT))
1013 return SDValue();
1014
1015 // Construct as integer, and move to float register.
1016 APInt INTVal = FPVal.bitcastToAPInt();
1017 if (VT == MVT::f32) {
1018 assert(Subtarget.is64Bit());
1019 SDValue NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
1020 DAG.getConstant(INTVal, DL, MVT::i32));
1021 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, VT, NewVal);
1022 }
1023
1024 assert(VT == MVT::f64 && !Subtarget.is64Bit());
1025 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
1026 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
1027 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
1028}
1029
1030// Ensure SETCC result and operand have the same bit width; isel does not
1031// support mismatched widths.
1032SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
1033 SelectionDAG &DAG) const {
1034 SDLoc DL(Op);
1035 EVT ResultVT = Op.getValueType();
1036 EVT OperandVT = Op.getOperand(0).getValueType();
1037
1038 EVT SetCCResultVT =
1039 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
1040
1041 if (ResultVT == SetCCResultVT)
1042 return Op;
1043
1044 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
1045 "SETCC operands must have the same type!");
1046
1047 SDValue SetCCNode =
1048 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
1049 Op.getOperand(1), Op.getOperand(2));
1050
1051 if (ResultVT.bitsGT(SetCCResultVT))
1052 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
1053 else if (ResultVT.bitsLT(SetCCResultVT))
1054 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
1055
1056 return SetCCNode;
1057}
1058
1059// Lower SIGN_EXTEND_VECTOR_INREG with VSLLWIL, which sign-extends the low half
1060// of the source elements (and shifts them left by 0).
1061// For example:
1062// %b = sext <8 x i8> %a to <8 x i16>
1063// can be lowered to:
1064// VSLLWIL.H.B vr1, vr1, 0
1065//
1066// VSLLWIL is slower than VILVL and VSRAI, so a 4x extension instead
1067// replicates each source element across its destination element by
1068// interleaving the source with itself twice, then shifts the copy in the top
1069// bits down arithmetically:
1070// %b = sext <4 x i8> %a to <4 x i32>
1071// can be lowered to:
1072// VILVL.B vr1, vr1, vr1
1073// VILVL.H vr1, vr1, vr1
1074// VSRAI.W vr1, vr1, 24
1075//
1076// If every extended source element is already all-ones or all-zeros, e.g. a
1077// comparison result, the interleaves alone produce the sign extension, so
1078// neither VSLLWIL nor the VSRAI is needed:
1079// %b = sext <8 x i8> %mask to <8 x i16>
1080// can be lowered to:
1081// VILVL.B vr1, vr1, vr1
1082SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1083 SDValue Op, SelectionDAG &DAG) const {
1084 SDLoc DL(Op);
1085 SDValue Src = Op.getOperand(0);
1086 MVT SrcVT = Src.getSimpleValueType();
1087 MVT DstVT = Op.getSimpleValueType();
1088 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
1089 unsigned DstEltBits = DstVT.getScalarSizeInBits();
1090
1091 // Leave larger ratios to the generic shuffle + shift expansion, which only
1092 // needs a single VEXTRINS to move the second element into place.
1093 unsigned Ratio = DstEltBits / SrcEltBits;
1094 if (!SrcVT.is128BitVector() || Ratio > 4)
1095 return SDValue();
1096
1097 // Only the low elements of the source are extended.
1098 APInt DemandedElts = APInt::getLowBitsSet(SrcVT.getVectorNumElements(),
1099 DstVT.getVectorNumElements());
1100 bool IsSignSplat = DAG.ComputeNumSignBits(Src, DemandedElts) == SrcEltBits;
1101
1102 if (Ratio == 2 && !IsSignSplat)
1103 return DAG.getNode(LoongArchISD::VSLLWIL, DL, DstVT, Src,
1104 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1105
1106 SDValue Res = Src;
1107 for (unsigned EltBits = SrcEltBits; EltBits < DstEltBits; EltBits *= 2) {
1108 MVT VT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), 128 / EltBits);
1109 Res = DAG.getBitcast(VT, Res);
1110 Res = DAG.getNode(LoongArchISD::VILVL, DL, VT, Res, Res);
1111 }
1112 Res = DAG.getBitcast(DstVT, Res);
1113 if (IsSignSplat)
1114 return Res;
1115 return DAG.getNode(ISD::SRA, DL, DstVT, Res,
1116 DAG.getConstant(DstEltBits - SrcEltBits, DL, DstVT));
1117}
1118
1119// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1120SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1121 SelectionDAG &DAG) const {
1122 assert(Subtarget.hasExtLASX());
1123 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1124 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1125 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1126 Op.getOperand(0));
1127}
1128
1129// Lower vecreduce_add using vhaddw instructions.
1130// For Example:
1131// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1132// can be lowered to:
1133// VHADDW_D_W vr0, vr0, vr0
1134// VHADDW_Q_D vr0, vr0, vr0
1135// VPICKVE2GR_D a0, vr0, 0
1136// ADDI_W a0, a0, 0
1137SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1138 SelectionDAG &DAG) const {
1139
1140 SDLoc DL(Op);
1141 MVT OpVT = Op.getSimpleValueType();
1142 SDValue Val = Op.getOperand(0);
1143
1144 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1145 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1146 unsigned ResBits = OpVT.getScalarSizeInBits();
1147
1148 unsigned LegalVecSize = 128;
1149 bool isLASX256Vector =
1150 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1151
1152 // Ensure operand type legal or enable it legal.
1153 while (!isTypeLegal(Val.getSimpleValueType())) {
1154 Val = DAG.WidenVector(Val, DL);
1155 }
1156
1157 // NumEles is designed for iterations count, v4i32 for LSX
1158 // and v8i32 for LASX should have the same count.
1159 if (isLASX256Vector) {
1160 NumEles /= 2;
1161 LegalVecSize = 256;
1162 }
1163
1164 EleBits *= 2;
1165 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1166 EleBits = std::min(EleBits, 64u);
1167 MVT IntTy = MVT::getIntegerVT(EleBits);
1168 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1169 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1170 }
1171
1172 if (isLASX256Vector) {
1173 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1174 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1175 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1176 }
1177
1178 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1179 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1180 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1181}
1182
1183// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1184// For Example:
1185// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1186// can be lowered to:
1187// VBSRL_V vr1, vr0, 8
1188// VMAX_W vr0, vr1, vr0
1189// VBSRL_V vr1, vr0, 4
1190// VMAX_W vr0, vr1, vr0
1191// VPICKVE2GR_W a0, vr0, 0
1192// For 256 bit vector, it is illegal and will be spilt into
1193// two 128 bit vector by default then processed by this.
1194SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1195 SelectionDAG &DAG) const {
1196 SDLoc DL(Op);
1197
1198 MVT OpVT = Op.getSimpleValueType();
1199 SDValue Val = Op.getOperand(0);
1200
1201 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1202 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1203
1204 // Ensure operand type legal or enable it legal.
1205 while (!isTypeLegal(Val.getSimpleValueType())) {
1206 Val = DAG.WidenVector(Val, DL);
1207 }
1208
1209 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1210 MVT VecTy = Val.getSimpleValueType();
1211 MVT GRLenVT = Subtarget.getGRLenVT();
1212
1213 for (int i = NumEles; i > 1; i /= 2) {
1214 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1215 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1216 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1217 }
1218
1219 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1220 DAG.getConstant(0, DL, GRLenVT));
1221}
1222
1223SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1224 SelectionDAG &DAG) const {
1225 unsigned IsData = Op.getConstantOperandVal(4);
1226
1227 // We don't support non-data prefetch.
1228 // Just preserve the chain.
1229 if (!IsData)
1230 return Op.getOperand(0);
1231
1232 return Op;
1233}
1234
1235SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1236 SelectionDAG &DAG) const {
1237 MVT VT = Op.getSimpleValueType();
1238 assert(VT.isVector() && "Unexpected type");
1239
1240 SDLoc DL(Op);
1241 SDValue R = Op.getOperand(0);
1242 SDValue Amt = Op.getOperand(1);
1243 unsigned Opcode = Op.getOpcode();
1244 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1245
1246 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1247 if (V.getOpcode() != ISD::BUILD_VECTOR)
1248 return false;
1249 if (SDValue SplatValue =
1250 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1251 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1252 CstSplatValue = C->getAPIntValue();
1253 return true;
1254 }
1255 }
1256 return false;
1257 };
1258
1259 // Check for constant splat rotation amount.
1260 APInt CstSplatValue;
1261 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1262 bool isROTL = Opcode == ISD::ROTL;
1263
1264 // Check for splat rotate by zero.
1265 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1266 return R;
1267
1268 // LoongArch targets always prefer ISD::ROTR.
1269 if (isROTL) {
1270 SDValue Zero = DAG.getConstant(0, DL, VT);
1271 return DAG.getNode(ISD::ROTR, DL, VT, R,
1272 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1273 }
1274
1275 // Rotate by a immediate.
1276 if (IsCstSplat) {
1277 // ISD::ROTR: Attemp to rotate by a positive immediate.
1278 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1279 if (SDValue Urem =
1280 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1281 return DAG.getNode(Opcode, DL, VT, R, Urem);
1282 }
1283
1284 return Op;
1285}
1286
1287// Return true if Val is equal to (setcc LHS, RHS, CC).
1288// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1289// Otherwise, return std::nullopt.
1290static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1291 ISD::CondCode CC, SDValue Val) {
1292 assert(Val->getOpcode() == ISD::SETCC);
1293 SDValue LHS2 = Val.getOperand(0);
1294 SDValue RHS2 = Val.getOperand(1);
1295 ISD::CondCode CC2 = Val.getOperandCondCode(2);
1296
1297 if (LHS == LHS2 && RHS == RHS2) {
1298 if (CC == CC2)
1299 return true;
1300 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1301 return false;
1302 } else if (LHS == RHS2 && RHS == LHS2) {
1304 if (CC == CC2)
1305 return true;
1306 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1307 return false;
1308 }
1309
1310 return std::nullopt;
1311}
1312
1315 SDValue CondV = N->getOperand(0);
1316 SDValue TrueV = N->getOperand(1);
1317 SDValue FalseV = N->getOperand(2);
1318 MVT VT = N->getSimpleValueType(0);
1319 SDLoc DL(N);
1320
1321 // (select c, -1, y) -> -c | y
1322 if (isAllOnesConstant(TrueV)) {
1323 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1324 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1325 }
1326 // (select c, y, -1) -> (c-1) | y
1327 if (isAllOnesConstant(FalseV)) {
1328 SDValue Neg =
1329 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1330 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1331 }
1332
1333 // (select c, 0, y) -> (c-1) & y
1334 if (isNullConstant(TrueV)) {
1335 SDValue Neg =
1336 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1337 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1338 }
1339 // (select c, y, 0) -> -c & y
1340 if (isNullConstant(FalseV)) {
1341 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1342 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1343 }
1344
1345 // select c, ~x, x --> xor -c, x
1346 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1347 const APInt &TrueVal = TrueV->getAsAPIntVal();
1348 const APInt &FalseVal = FalseV->getAsAPIntVal();
1349 if (~TrueVal == FalseVal) {
1350 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1351 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1352 }
1353 }
1354
1355 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1356 // when both truev and falsev are also setcc.
1357 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1358 FalseV.getOpcode() == ISD::SETCC) {
1359 SDValue LHS = CondV.getOperand(0);
1360 SDValue RHS = CondV.getOperand(1);
1362
1363 // (select x, x, y) -> x | y
1364 // (select !x, x, y) -> x & y
1365 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1366 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1367 DAG.getFreeze(FalseV));
1368 }
1369 // (select x, y, x) -> x & y
1370 // (select !x, y, x) -> x | y
1371 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1372 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1373 DAG.getFreeze(TrueV), FalseV);
1374 }
1375 }
1376
1377 return SDValue();
1378}
1379
1380// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1381// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1382// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1383// being `0` or `-1`. In such cases we can replace `select` with `and`.
1384// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1385// than `c0`?
1386static SDValue
1389 unsigned SelOpNo = 0;
1390 SDValue Sel = BO->getOperand(0);
1391 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1392 SelOpNo = 1;
1393 Sel = BO->getOperand(1);
1394 }
1395
1396 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1397 return SDValue();
1398
1399 unsigned ConstSelOpNo = 1;
1400 unsigned OtherSelOpNo = 2;
1401 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1402 ConstSelOpNo = 2;
1403 OtherSelOpNo = 1;
1404 }
1405 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1406 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1407 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1408 return SDValue();
1409
1410 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1411 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1412 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1413 return SDValue();
1414
1415 SDLoc DL(Sel);
1416 EVT VT = BO->getValueType(0);
1417
1418 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1419 if (SelOpNo == 1)
1420 std::swap(NewConstOps[0], NewConstOps[1]);
1421
1422 SDValue NewConstOp =
1423 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1424 if (!NewConstOp)
1425 return SDValue();
1426
1427 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1428 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1429 return SDValue();
1430
1431 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1432 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1433 if (SelOpNo == 1)
1434 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1435 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1436
1437 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1438 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1439 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1440}
1441
1442// Changes the condition code and swaps operands if necessary, so the SetCC
1443// operation matches one of the comparisons supported directly by branches
1444// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1445// compare with 1/-1.
1447 ISD::CondCode &CC, SelectionDAG &DAG) {
1448 // If this is a single bit test that can't be handled by ANDI, shift the
1449 // bit to be tested to the MSB and perform a signed compare with 0.
1450 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1451 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1452 isa<ConstantSDNode>(LHS.getOperand(1))) {
1453 uint64_t Mask = LHS.getConstantOperandVal(1);
1454 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1455 unsigned ShAmt = 0;
1456 if (isPowerOf2_64(Mask)) {
1458 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1459 } else {
1460 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1461 }
1462
1463 LHS = LHS.getOperand(0);
1464 if (ShAmt != 0)
1465 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1466 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1467 return;
1468 }
1469 }
1470
1471 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1472 int64_t C = RHSC->getSExtValue();
1473 switch (CC) {
1474 default:
1475 break;
1476 case ISD::SETGT:
1477 // Convert X > -1 to X >= 0.
1478 if (C == -1) {
1479 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1480 CC = ISD::SETGE;
1481 return;
1482 }
1483 break;
1484 case ISD::SETLT:
1485 // Convert X < 1 to 0 >= X.
1486 if (C == 1) {
1487 RHS = LHS;
1488 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1489 CC = ISD::SETGE;
1490 return;
1491 }
1492 break;
1493 }
1494 }
1495
1496 switch (CC) {
1497 default:
1498 break;
1499 case ISD::SETGT:
1500 case ISD::SETLE:
1501 case ISD::SETUGT:
1502 case ISD::SETULE:
1504 std::swap(LHS, RHS);
1505 break;
1506 }
1507}
1508
1509SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1510 SelectionDAG &DAG) const {
1511 SDValue CondV = Op.getOperand(0);
1512 SDValue TrueV = Op.getOperand(1);
1513 SDValue FalseV = Op.getOperand(2);
1514 SDLoc DL(Op);
1515 MVT VT = Op.getSimpleValueType();
1516 MVT GRLenVT = Subtarget.getGRLenVT();
1517
1518 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1519 return V;
1520
1521 if (Op.hasOneUse()) {
1522 unsigned UseOpc = Op->user_begin()->getOpcode();
1523 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1524 SDNode *BinOp = *Op->user_begin();
1525 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1526 DAG, Subtarget)) {
1527 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1528 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1529 // may return a constant node and cause crash in lowerSELECT.
1530 if (NewSel.getOpcode() == ISD::SELECT)
1531 return lowerSELECT(NewSel, DAG);
1532 return NewSel;
1533 }
1534 }
1535 }
1536
1537 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1538 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1539 // (select condv, truev, falsev)
1540 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1541 if (CondV.getOpcode() != ISD::SETCC ||
1542 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1543 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1544 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1545
1546 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1547
1548 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1549 }
1550
1551 // If the CondV is the output of a SETCC node which operates on GRLenVT
1552 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1553 // to take advantage of the integer compare+branch instructions. i.e.: (select
1554 // (setcc lhs, rhs, cc), truev, falsev)
1555 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1556 SDValue LHS = CondV.getOperand(0);
1557 SDValue RHS = CondV.getOperand(1);
1558 ISD::CondCode CCVal = CondV.getOperandCondCode(2);
1559
1560 // Special case for a select of 2 constants that have a difference of 1.
1561 // Normally this is done by DAGCombine, but if the select is introduced by
1562 // type legalization or op legalization, we miss it. Restricting to SETLT
1563 // case for now because that is what signed saturating add/sub need.
1564 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1565 // but we would probably want to swap the true/false values if the condition
1566 // is SETGE/SETLE to avoid an XORI.
1567 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1568 CCVal == ISD::SETLT) {
1569 const APInt &TrueVal = TrueV->getAsAPIntVal();
1570 const APInt &FalseVal = FalseV->getAsAPIntVal();
1571 if (TrueVal - 1 == FalseVal)
1572 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1573 if (TrueVal + 1 == FalseVal)
1574 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1575 }
1576
1577 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1578 // 1 < x ? x : 1 -> 0 < x ? x : 1
1579 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1580 RHS == TrueV && LHS == FalseV) {
1581 LHS = DAG.getConstant(0, DL, VT);
1582 // 0 <u x is the same as x != 0.
1583 if (CCVal == ISD::SETULT) {
1584 std::swap(LHS, RHS);
1585 CCVal = ISD::SETNE;
1586 }
1587 }
1588
1589 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1590 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1591 RHS == FalseV) {
1592 RHS = DAG.getConstant(0, DL, VT);
1593 }
1594
1595 SDValue TargetCC = DAG.getCondCode(CCVal);
1596
1597 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1598 // (select (setcc lhs, rhs, CC), constant, falsev)
1599 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1600 std::swap(TrueV, FalseV);
1601 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1602 }
1603
1604 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1605 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1606}
1607
1608SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1609 SelectionDAG &DAG) const {
1610 SDValue CondV = Op.getOperand(1);
1611 SDLoc DL(Op);
1612 MVT GRLenVT = Subtarget.getGRLenVT();
1613
1614 if (CondV.getOpcode() == ISD::SETCC) {
1615 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1616 SDValue LHS = CondV.getOperand(0);
1617 SDValue RHS = CondV.getOperand(1);
1618 ISD::CondCode CCVal = CondV.getOperandCondCode(2);
1619
1620 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1621
1622 SDValue TargetCC = DAG.getCondCode(CCVal);
1623 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1624 Op.getOperand(0), LHS, RHS, TargetCC,
1625 Op.getOperand(2));
1626 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1627 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1628 Op.getOperand(0), CondV, Op.getOperand(2));
1629 }
1630 }
1631
1632 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1633 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1634 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1635}
1636
1637SDValue
1638LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1639 SelectionDAG &DAG) const {
1640 SDLoc DL(Op);
1641 MVT OpVT = Op.getSimpleValueType();
1642
1643 SDValue Vector = DAG.getUNDEF(OpVT);
1644 SDValue Val = Op.getOperand(0);
1645 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1646
1647 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1648}
1649
1650SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1651 SelectionDAG &DAG) const {
1652 EVT ResTy = Op->getValueType(0);
1653 SDValue Src = Op->getOperand(0);
1654 SDLoc DL(Op);
1655
1656 // LoongArchISD::BITREV_8B is not supported on LA32.
1657 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1658 return SDValue();
1659
1660 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1661 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1662 unsigned int NewEltNum = NewVT.getVectorNumElements();
1663
1664 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1665
1667 for (unsigned int i = 0; i < NewEltNum; i++) {
1668 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1669 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1670 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1671 ? (unsigned)LoongArchISD::BITREV_8B
1672 : (unsigned)ISD::BITREVERSE;
1673 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1674 }
1675 SDValue Res =
1676 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1677
1678 switch (ResTy.getSimpleVT().SimpleTy) {
1679 default:
1680 return SDValue();
1681 case MVT::v16i8:
1682 case MVT::v32i8:
1683 return Res;
1684 case MVT::v8i16:
1685 case MVT::v16i16:
1686 case MVT::v4i32:
1687 case MVT::v8i32: {
1689 for (unsigned int i = 0; i < NewEltNum; i++)
1690 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1691 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1692 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1693 }
1694 }
1695}
1696
1697// Widen element type to get a new mask value (if possible).
1698// For example:
1699// shufflevector <4 x i32> %a, <4 x i32> %b,
1700// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1701// is equivalent to:
1702// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1703// can be lowered to:
1704// VPACKOD_D vr0, vr0, vr1
1706 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1707 unsigned EltBits = VT.getScalarSizeInBits();
1708
1709 if (EltBits > 32 || EltBits == 1)
1710 return SDValue();
1711
1712 SmallVector<int, 8> NewMask;
1713 if (widenShuffleMaskElts(Mask, NewMask)) {
1714 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1715 : MVT::getIntegerVT(EltBits * 2);
1716 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1717 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1718 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1719 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1720 return DAG.getBitcast(
1721 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1722 }
1723 }
1724
1725 return SDValue();
1726}
1727
1728/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1729/// instruction.
1730// The funciton matches elements from one of the input vector shuffled to the
1731// left or right with zeroable elements 'shifted in'. It handles both the
1732// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1733// lane.
1734// Mostly copied from X86.
1735static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1736 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1737 int MaskOffset, const APInt &Zeroable) {
1738 int Size = Mask.size();
1739 unsigned SizeInBits = Size * ScalarSizeInBits;
1740
1741 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1742 for (int i = 0; i < Size; i += Scale)
1743 for (int j = 0; j < Shift; ++j)
1744 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1745 return false;
1746
1747 return true;
1748 };
1749
1750 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1751 int Step = 1) {
1752 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1753 if (!(Mask[i] == -1 || Mask[i] == Low))
1754 return false;
1755 return true;
1756 };
1757
1758 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1759 for (int i = 0; i != Size; i += Scale) {
1760 unsigned Pos = Left ? i + Shift : i;
1761 unsigned Low = Left ? i : i + Shift;
1762 unsigned Len = Scale - Shift;
1763 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1764 return -1;
1765 }
1766
1767 int ShiftEltBits = ScalarSizeInBits * Scale;
1768 bool ByteShift = ShiftEltBits > 64;
1769 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1770 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1771 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1772
1773 // Normalize the scale for byte shifts to still produce an i64 element
1774 // type.
1775 Scale = ByteShift ? Scale / 2 : Scale;
1776
1777 // We need to round trip through the appropriate type for the shift.
1778 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1779 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1780 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1781 return (int)ShiftAmt;
1782 };
1783
1784 unsigned MaxWidth = 128;
1785 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1786 for (int Shift = 1; Shift != Scale; ++Shift)
1787 for (bool Left : {true, false})
1788 if (CheckZeros(Shift, Scale, Left)) {
1789 int ShiftAmt = MatchShift(Shift, Scale, Left);
1790 if (0 < ShiftAmt)
1791 return ShiftAmt;
1792 }
1793
1794 // no match
1795 return -1;
1796}
1797
1798/// Lower VECTOR_SHUFFLE as shift (if possible).
1799///
1800/// For example:
1801/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1802/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1803/// is lowered to:
1804/// (VBSLL_V $v0, $v0, 4)
1805///
1806/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1807/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1808/// is lowered to:
1809/// (VSLLI_D $v0, $v0, 32)
1811 MVT VT, SDValue V1, SDValue V2,
1812 SelectionDAG &DAG,
1814 const APInt &Zeroable) {
1815 int Size = Mask.size();
1816 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1817
1818 MVT ShiftVT;
1819 SDValue V = V1;
1820 unsigned Opcode;
1821
1822 // Try to match shuffle against V1 shift.
1823 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1824 Mask, 0, Zeroable);
1825
1826 // If V1 failed, try to match shuffle against V2 shift.
1827 if (ShiftAmt < 0) {
1828 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1829 Mask, Size, Zeroable);
1830 V = V2;
1831 }
1832
1833 if (ShiftAmt < 0)
1834 return SDValue();
1835
1836 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1837 "Illegal integer vector type");
1838 V = DAG.getBitcast(ShiftVT, V);
1839 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1840 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1841 return DAG.getBitcast(VT, V);
1842}
1843
1844/// Determine whether a range fits a regular pattern of values.
1845/// This function accounts for the possibility of jumping over the End iterator.
1846template <typename ValType>
1847static bool
1849 unsigned CheckStride,
1851 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1852 auto &I = Begin;
1853
1854 while (I != End) {
1855 if (*I != -1 && *I != ExpectedIndex)
1856 return false;
1857 ExpectedIndex += ExpectedIndexStride;
1858
1859 // Incrementing past End is undefined behaviour so we must increment one
1860 // step at a time and check for End at each step.
1861 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1862 ; // Empty loop body.
1863 }
1864 return true;
1865}
1866
1867/// Compute whether each element of a shuffle is zeroable.
1868///
1869/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1871 SDValue V2, APInt &KnownUndef,
1872 APInt &KnownZero) {
1873 int Size = Mask.size();
1874 KnownUndef = KnownZero = APInt::getZero(Size);
1875
1877 V2 = peekThroughBitcasts(V2);
1878
1879 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1880 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1881
1882 int VectorSizeInBits = V1.getValueSizeInBits();
1883 int ScalarSizeInBits = VectorSizeInBits / Size;
1884 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1885 (void)ScalarSizeInBits;
1886
1887 for (int i = 0; i < Size; ++i) {
1888 int M = Mask[i];
1889 if (M < 0) {
1890 KnownUndef.setBit(i);
1891 continue;
1892 }
1893 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1894 KnownZero.setBit(i);
1895 continue;
1896 }
1897 }
1898}
1899
1900/// Test whether a shuffle mask is equivalent within each sub-lane.
1901///
1902/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1903/// non-trivial to compute in the face of undef lanes. The representation is
1904/// suitable for use with existing 128-bit shuffles as entries from the second
1905/// vector have been remapped to [LaneSize, 2*LaneSize).
1906static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1907 ArrayRef<int> Mask,
1908 SmallVectorImpl<int> &RepeatedMask) {
1909 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1910 RepeatedMask.assign(LaneSize, -1);
1911 int Size = Mask.size();
1912 for (int i = 0; i < Size; ++i) {
1913 assert(Mask[i] == -1 || Mask[i] >= 0);
1914 if (Mask[i] < 0)
1915 continue;
1916 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1917 // This entry crosses lanes, so there is no way to model this shuffle.
1918 return false;
1919
1920 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1921 // Adjust second vector indices to start at LaneSize instead of Size.
1922 int LocalM =
1923 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1924 if (RepeatedMask[i % LaneSize] < 0)
1925 // This is the first non-undef entry in this slot of a 128-bit lane.
1926 RepeatedMask[i % LaneSize] = LocalM;
1927 else if (RepeatedMask[i % LaneSize] != LocalM)
1928 // Found a mismatch with the repeated mask.
1929 return false;
1930 }
1931 return true;
1932}
1933
1934/// Attempts to match vector shuffle as byte rotation.
1936 ArrayRef<int> Mask) {
1937
1938 SDValue Lo, Hi;
1939 SmallVector<int, 16> RepeatedMask;
1940
1941 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1942 return -1;
1943
1944 int NumElts = RepeatedMask.size();
1945 int Rotation = 0;
1946 int Scale = 16 / NumElts;
1947
1948 for (int i = 0; i < NumElts; ++i) {
1949 int M = RepeatedMask[i];
1950 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1951 "Unexpected mask index.");
1952 if (M < 0)
1953 continue;
1954
1955 // Determine where a rotated vector would have started.
1956 int StartIdx = i - (M % NumElts);
1957 if (StartIdx == 0)
1958 return -1;
1959
1960 // If we found the tail of a vector the rotation must be the missing
1961 // front. If we found the head of a vector, it must be how much of the
1962 // head.
1963 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1964
1965 if (Rotation == 0)
1966 Rotation = CandidateRotation;
1967 else if (Rotation != CandidateRotation)
1968 return -1;
1969
1970 // Compute which value this mask is pointing at.
1971 SDValue MaskV = M < NumElts ? V1 : V2;
1972
1973 // Compute which of the two target values this index should be assigned
1974 // to. This reflects whether the high elements are remaining or the low
1975 // elements are remaining.
1976 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1977
1978 // Either set up this value if we've not encountered it before, or check
1979 // that it remains consistent.
1980 if (!TargetV)
1981 TargetV = MaskV;
1982 else if (TargetV != MaskV)
1983 return -1;
1984 }
1985
1986 // Check that we successfully analyzed the mask, and normalize the results.
1987 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1988 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1989 if (!Lo)
1990 Lo = Hi;
1991 else if (!Hi)
1992 Hi = Lo;
1993
1994 V1 = Lo;
1995 V2 = Hi;
1996
1997 return Rotation * Scale;
1998}
1999
2000/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
2001///
2002/// For example:
2003/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
2004/// <2 x i32> <i32 3, i32 0>
2005/// is lowered to:
2006/// (VBSRL_V $v1, $v1, 8)
2007/// (VBSLL_V $v0, $v0, 8)
2008/// (VOR_V $v0, $V0, $v1)
2009static SDValue
2011 SDValue V1, SDValue V2, SelectionDAG &DAG,
2013
2014 SDValue Lo = V1, Hi = V2;
2015 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
2016 if (ByteRotation <= 0)
2017 return SDValue();
2018
2019 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
2020 Lo = DAG.getBitcast(ByteVT, Lo);
2021 Hi = DAG.getBitcast(ByteVT, Hi);
2022
2023 int LoByteShift = 16 - ByteRotation;
2024 int HiByteShift = ByteRotation;
2025 MVT GRLenVT = Subtarget.getGRLenVT();
2026
2027 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
2028 DAG.getConstant(LoByteShift, DL, GRLenVT));
2029 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
2030 DAG.getConstant(HiByteShift, DL, GRLenVT));
2031 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
2032}
2033
2034/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
2035///
2036/// For example:
2037/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
2038/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
2039/// %3 = bitcast <4 x i32> %2 to <2 x i64>
2040/// is lowered to:
2041/// (VREPLI $v1, 0)
2042/// (VILVL $v0, $v1, $v0)
2044 ArrayRef<int> Mask, MVT VT,
2045 SDValue V1, SDValue V2,
2046 SelectionDAG &DAG,
2047 const APInt &Zeroable) {
2048 int Bits = VT.getSizeInBits();
2049 int EltBits = VT.getScalarSizeInBits();
2050 int NumElements = VT.getVectorNumElements();
2051
2052 if (Zeroable.isAllOnes())
2053 return DAG.getConstant(0, DL, VT);
2054
2055 // Define a helper function to check a particular ext-scale and lower to it if
2056 // valid.
2057 auto Lower = [&](int Scale) -> SDValue {
2058 SDValue InputV;
2059 bool AnyExt = true;
2060 int Offset = 0;
2061 for (int i = 0; i < NumElements; i++) {
2062 int M = Mask[i];
2063 if (M < 0)
2064 continue;
2065 if (i % Scale != 0) {
2066 // Each of the extended elements need to be zeroable.
2067 if (!Zeroable[i])
2068 return SDValue();
2069
2070 AnyExt = false;
2071 continue;
2072 }
2073
2074 // Each of the base elements needs to be consecutive indices into the
2075 // same input vector.
2076 SDValue V = M < NumElements ? V1 : V2;
2077 M = M % NumElements;
2078 if (!InputV) {
2079 InputV = V;
2080 Offset = M - (i / Scale);
2081
2082 // These offset can't be handled
2083 if (Offset % (NumElements / Scale))
2084 return SDValue();
2085 } else if (InputV != V)
2086 return SDValue();
2087
2088 if (M != (Offset + (i / Scale)))
2089 return SDValue(); // Non-consecutive strided elements.
2090 }
2091
2092 // If we fail to find an input, we have a zero-shuffle which should always
2093 // have already been handled.
2094 if (!InputV)
2095 return SDValue();
2096
2097 do {
2098 unsigned VilVLoHi = LoongArchISD::VILVL;
2099 if (Offset >= (NumElements / 2)) {
2100 VilVLoHi = LoongArchISD::VILVH;
2101 Offset -= (NumElements / 2);
2102 }
2103
2104 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2105 SDValue Ext =
2106 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2107 InputV = DAG.getBitcast(InputVT, InputV);
2108 Ext = DAG.getBitcast(InputVT, Ext);
2109 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2110 Scale /= 2;
2111 EltBits *= 2;
2112 NumElements /= 2;
2113 } while (Scale > 1);
2114 return DAG.getBitcast(VT, InputV);
2115 };
2116
2117 // Each iteration, try extending the elements half as much, but into twice as
2118 // many elements.
2119 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2120 NumExtElements *= 2) {
2121 if (SDValue V = Lower(NumElements / NumExtElements))
2122 return V;
2123 }
2124 return SDValue();
2125}
2126
2127/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2128///
2129/// VREPLVEI performs vector broadcast based on an element specified by an
2130/// integer immediate, with its mask being similar to:
2131/// <x, x, x, ...>
2132/// where x is any valid index.
2133///
2134/// When undef's appear in the mask they are treated as if they were whatever
2135/// value is necessary in order to fit the above form.
2136static SDValue
2138 SDValue V1, SelectionDAG &DAG,
2140 int SplatIndex = -1;
2141 for (const auto &M : Mask) {
2142 if (M != -1) {
2143 SplatIndex = M;
2144 break;
2145 }
2146 }
2147
2148 if (SplatIndex == -1)
2149 return DAG.getUNDEF(VT);
2150
2151 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2152 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2153 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2154 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2155 }
2156
2157 return SDValue();
2158}
2159
2160/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2161///
2162/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2163/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2164///
2165/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2166/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2167/// When undef's appear they are treated as if they were whatever value is
2168/// necessary in order to fit the above forms.
2169///
2170/// For example:
2171/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2172/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2173/// i32 7, i32 6, i32 5, i32 4>
2174/// is lowered to:
2175/// (VSHUF4I_H $v0, $v1, 27)
2176/// where the 27 comes from:
2177/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2178static SDValue
2180 SDValue V1, SDValue V2, SelectionDAG &DAG,
2182
2183 unsigned SubVecSize = 4;
2184 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2185 SubVecSize = 2;
2186
2187 int SubMask[4] = {-1, -1, -1, -1};
2188 for (unsigned i = 0; i < SubVecSize; ++i) {
2189 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2190 int M = Mask[j];
2191
2192 // Convert from vector index to 4-element subvector index
2193 // If an index refers to an element outside of the subvector then give up
2194 if (M != -1) {
2195 M -= 4 * (j / SubVecSize);
2196 if (M < 0 || M >= 4)
2197 return SDValue();
2198 }
2199
2200 // If the mask has an undef, replace it with the current index.
2201 // Note that it might still be undef if the current index is also undef
2202 if (SubMask[i] == -1)
2203 SubMask[i] = M;
2204 // Check that non-undef values are the same as in the mask. If they
2205 // aren't then give up
2206 else if (M != -1 && M != SubMask[i])
2207 return SDValue();
2208 }
2209 }
2210
2211 // Calculate the immediate. Replace any remaining undefs with zero
2212 int Imm = 0;
2213 for (int i = SubVecSize - 1; i >= 0; --i) {
2214 int M = SubMask[i];
2215
2216 if (M == -1)
2217 M = 0;
2218
2219 Imm <<= 2;
2220 Imm |= M & 0x3;
2221 }
2222
2223 MVT GRLenVT = Subtarget.getGRLenVT();
2224
2225 // Return vshuf4i.d
2226 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2227 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2228 DAG.getConstant(Imm, DL, GRLenVT));
2229
2230 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2231 DAG.getConstant(Imm, DL, GRLenVT));
2232}
2233
2234/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2235///
2236/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2237/// reverse whose mask likes:
2238/// <7, 6, 5, 4, 3, 2, 1, 0>
2239///
2240/// When undef's appear in the mask they are treated as if they were whatever
2241/// value is necessary in order to fit the above forms.
2242static SDValue
2244 SDValue V1, SelectionDAG &DAG,
2246 // Only vectors with i8/i16 elements which cannot match other patterns
2247 // directly needs to do this.
2248 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2249 VT != MVT::v16i16)
2250 return SDValue();
2251
2252 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2253 return SDValue();
2254
2255 int WidenNumElts = VT.getVectorNumElements() / 4;
2256 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2257 for (int i = 0; i < WidenNumElts; ++i)
2258 WidenMask[i] = WidenNumElts - 1 - i;
2259
2260 MVT WidenVT = MVT::getVectorVT(
2261 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2262 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2263 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2264 DAG.getUNDEF(WidenVT), WidenMask);
2265
2266 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2267 DAG.getBitcast(VT, WidenRev),
2268 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2269}
2270
2271/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2272///
2273/// VPACKEV interleaves the even elements from each vector.
2274///
2275/// It is possible to lower into VPACKEV when the mask consists of two of the
2276/// following forms interleaved:
2277/// <0, 2, 4, ...>
2278/// <n, n+2, n+4, ...>
2279/// where n is the number of elements in the vector.
2280/// For example:
2281/// <0, 0, 2, 2, 4, 4, ...>
2282/// <0, n, 2, n+2, 4, n+4, ...>
2283///
2284/// When undef's appear in the mask they are treated as if they were whatever
2285/// value is necessary in order to fit the above forms.
2287 MVT VT, SDValue V1, SDValue V2,
2288 SelectionDAG &DAG) {
2289
2290 const auto &Begin = Mask.begin();
2291 const auto &End = Mask.end();
2292 SDValue OriV1 = V1, OriV2 = V2;
2293
2294 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2295 V1 = OriV1;
2296 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2297 V1 = OriV2;
2298 else
2299 return SDValue();
2300
2301 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2302 V2 = OriV1;
2303 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2304 V2 = OriV2;
2305 else
2306 return SDValue();
2307
2308 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2309}
2310
2311/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2312///
2313/// VPACKOD interleaves the odd elements from each vector.
2314///
2315/// It is possible to lower into VPACKOD when the mask consists of two of the
2316/// following forms interleaved:
2317/// <1, 3, 5, ...>
2318/// <n+1, n+3, n+5, ...>
2319/// where n is the number of elements in the vector.
2320/// For example:
2321/// <1, 1, 3, 3, 5, 5, ...>
2322/// <1, n+1, 3, n+3, 5, n+5, ...>
2323///
2324/// When undef's appear in the mask they are treated as if they were whatever
2325/// value is necessary in order to fit the above forms.
2327 MVT VT, SDValue V1, SDValue V2,
2328 SelectionDAG &DAG) {
2329
2330 const auto &Begin = Mask.begin();
2331 const auto &End = Mask.end();
2332 SDValue OriV1 = V1, OriV2 = V2;
2333
2334 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2335 V1 = OriV1;
2336 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2337 V1 = OriV2;
2338 else
2339 return SDValue();
2340
2341 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2342 V2 = OriV1;
2343 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2344 V2 = OriV2;
2345 else
2346 return SDValue();
2347
2348 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2349}
2350
2351/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2352///
2353/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2354/// of each vector.
2355///
2356/// It is possible to lower into VILVH when the mask consists of two of the
2357/// following forms interleaved:
2358/// <x, x+1, x+2, ...>
2359/// <n+x, n+x+1, n+x+2, ...>
2360/// where n is the number of elements in the vector and x is half n.
2361/// For example:
2362/// <x, x, x+1, x+1, x+2, x+2, ...>
2363/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2364///
2365/// When undef's appear in the mask they are treated as if they were whatever
2366/// value is necessary in order to fit the above forms.
2368 MVT VT, SDValue V1, SDValue V2,
2369 SelectionDAG &DAG) {
2370
2371 const auto &Begin = Mask.begin();
2372 const auto &End = Mask.end();
2373 unsigned HalfSize = Mask.size() / 2;
2374 SDValue OriV1 = V1, OriV2 = V2;
2375
2376 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2377 V1 = OriV1;
2378 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2379 V1 = OriV2;
2380 else
2381 return SDValue();
2382
2383 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2384 V2 = OriV1;
2385 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2386 1))
2387 V2 = OriV2;
2388 else
2389 return SDValue();
2390
2391 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2392}
2393
2394/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2395///
2396/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2397/// of each vector.
2398///
2399/// It is possible to lower into VILVL when the mask consists of two of the
2400/// following forms interleaved:
2401/// <0, 1, 2, ...>
2402/// <n, n+1, n+2, ...>
2403/// where n is the number of elements in the vector.
2404/// For example:
2405/// <0, 0, 1, 1, 2, 2, ...>
2406/// <0, n, 1, n+1, 2, n+2, ...>
2407///
2408/// When undef's appear in the mask they are treated as if they were whatever
2409/// value is necessary in order to fit the above forms.
2411 MVT VT, SDValue V1, SDValue V2,
2412 SelectionDAG &DAG) {
2413
2414 const auto &Begin = Mask.begin();
2415 const auto &End = Mask.end();
2416 SDValue OriV1 = V1, OriV2 = V2;
2417
2418 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2419 V1 = OriV1;
2420 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2421 V1 = OriV2;
2422 else
2423 return SDValue();
2424
2425 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2426 V2 = OriV1;
2427 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2428 V2 = OriV2;
2429 else
2430 return SDValue();
2431
2432 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2433}
2434
2435/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2436///
2437/// VPICKEV copies the even elements of each vector into the result vector.
2438///
2439/// It is possible to lower into VPICKEV when the mask consists of two of the
2440/// following forms concatenated:
2441/// <0, 2, 4, ...>
2442/// <n, n+2, n+4, ...>
2443/// where n is the number of elements in the vector.
2444/// For example:
2445/// <0, 2, 4, ..., 0, 2, 4, ...>
2446/// <0, 2, 4, ..., n, n+2, n+4, ...>
2447///
2448/// When undef's appear in the mask they are treated as if they were whatever
2449/// value is necessary in order to fit the above forms.
2451 MVT VT, SDValue V1, SDValue V2,
2452 SelectionDAG &DAG) {
2453
2454 const auto &Begin = Mask.begin();
2455 const auto &Mid = Mask.begin() + Mask.size() / 2;
2456 const auto &End = Mask.end();
2457 SDValue OriV1 = V1, OriV2 = V2;
2458
2459 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2460 V1 = OriV1;
2461 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2462 V1 = OriV2;
2463 else
2464 return SDValue();
2465
2466 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2467 V2 = OriV1;
2468 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2469 V2 = OriV2;
2470
2471 else
2472 return SDValue();
2473
2474 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2475}
2476
2477/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2478///
2479/// VPICKOD copies the odd elements of each vector into the result vector.
2480///
2481/// It is possible to lower into VPICKOD when the mask consists of two of the
2482/// following forms concatenated:
2483/// <1, 3, 5, ...>
2484/// <n+1, n+3, n+5, ...>
2485/// where n is the number of elements in the vector.
2486/// For example:
2487/// <1, 3, 5, ..., 1, 3, 5, ...>
2488/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2489///
2490/// When undef's appear in the mask they are treated as if they were whatever
2491/// value is necessary in order to fit the above forms.
2493 MVT VT, SDValue V1, SDValue V2,
2494 SelectionDAG &DAG) {
2495
2496 const auto &Begin = Mask.begin();
2497 const auto &Mid = Mask.begin() + Mask.size() / 2;
2498 const auto &End = Mask.end();
2499 SDValue OriV1 = V1, OriV2 = V2;
2500
2501 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2502 V1 = OriV1;
2503 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2504 V1 = OriV2;
2505 else
2506 return SDValue();
2507
2508 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2509 V2 = OriV1;
2510 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2511 V2 = OriV2;
2512 else
2513 return SDValue();
2514
2515 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2516}
2517
2518/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2519///
2520/// VEXTRINS copies one element of a vector into any place of the result
2521/// vector and makes no change to the rest elements of the result vector.
2522///
2523/// It is possible to lower into VEXTRINS when the mask takes the form:
2524/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2525/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2526/// where n is the number of elements in the vector and i is in [0, n).
2527/// For example:
2528/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2529/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2530///
2531/// When undef's appear in the mask they are treated as if they were whatever
2532/// value is necessary in order to fit the above forms.
2533static SDValue
2535 SDValue V1, SDValue V2, SelectionDAG &DAG,
2537 unsigned NumElts = VT.getVectorNumElements();
2538 MVT EltVT = VT.getVectorElementType();
2539 MVT GRLenVT = Subtarget.getGRLenVT();
2540
2541 if (Mask.size() != NumElts)
2542 return SDValue();
2543
2544 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2545 int DiffCount = 0;
2546 int DiffPos = -1;
2547 for (unsigned i = 0; i < NumElts; ++i) {
2548 if (Mask[i] == -1)
2549 continue;
2550 if (Mask[i] != int(Base + i)) {
2551 ++DiffCount;
2552 DiffPos = int(i);
2553 if (DiffCount > 1)
2554 return SDValue();
2555 }
2556 }
2557
2558 // Need exactly one differing element to lower into VEXTRINS.
2559 if (DiffCount != 1)
2560 return SDValue();
2561
2562 // DiffMask must be in [0, 2N).
2563 int DiffMask = Mask[DiffPos];
2564 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2565 return SDValue();
2566
2567 // Determine source vector and source index.
2568 SDValue SrcVec;
2569 unsigned SrcIdx;
2570 if (unsigned(DiffMask) < NumElts) {
2571 SrcVec = V1;
2572 SrcIdx = unsigned(DiffMask);
2573 } else {
2574 SrcVec = V2;
2575 SrcIdx = unsigned(DiffMask) - NumElts;
2576 }
2577
2578 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2579 // patterns of VEXTRINS in tablegen.
2580 SDValue Extracted = DAG.getNode(
2581 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2582 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2583 SDValue Result =
2584 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2585 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2586
2587 return Result;
2588 };
2589
2590 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2591 if (SDValue Result = tryLowerToExtrAndIns(0))
2592 return Result;
2593 return tryLowerToExtrAndIns(NumElts);
2594}
2595
2596// Check the Mask and then build SrcVec and MaskImm infos which will
2597// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2598// On success, return true. Otherwise, return false.
2601 unsigned &MaskImm) {
2602 unsigned MaskSize = Mask.size();
2603
2604 auto isValid = [&](int M, int Off) {
2605 return (M == -1) || (M >= Off && M < Off + 4);
2606 };
2607
2608 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2609 auto immPart = [&](int M, unsigned Off) {
2610 return (M == -1 ? 0 : (M - Off)) & 0x3;
2611 };
2612 MaskImm |= immPart(MLo, Off) << (I * 2);
2613 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2614 };
2615
2616 for (unsigned i = 0; i < 4; i += 2) {
2617 int MLo = Mask[i];
2618 int MHi = Mask[i + 1];
2619
2620 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2621 auto isValid2 = [&](int &M, int M2) {
2622 // If high half index is undef, it's always valid.
2623 if (M2 == -1)
2624 return true;
2625 if (M == -1) {
2626 // If low half index is undef, use index from high half,
2627 // remapped to low half.
2628 if ((M2 % MaskSize) < 4)
2629 return false;
2630 M = M2 - 4;
2631 return true;
2632 }
2633 // Index in low half must be same as index in high half.
2634 return M2 == M + 4;
2635 };
2636 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2637 return false;
2638 }
2639
2640 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2641 SrcVec.push_back(V1);
2642 buildImm(MLo, MHi, 0, i);
2643 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2644 SrcVec.push_back(V2);
2645 buildImm(MLo, MHi, MaskSize, i);
2646 } else {
2647 return false;
2648 }
2649 }
2650
2651 return true;
2652}
2653
2654/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2655///
2656/// VPERMI selects two elements from each of the two vectors based on the
2657/// mask and places them in the corresponding positions of the result vector
2658/// in order. Only v4i32 and v4f32 types are allowed.
2659///
2660/// It is possible to lower into VPERMI when the mask consists of two of the
2661/// following forms concatenated:
2662/// <i, j, u, v>
2663/// <u, v, i, j>
2664/// where i,j are in [0,4) and u,v are in [4, 8).
2665/// For example:
2666/// <2, 3, 4, 5>
2667/// <5, 7, 0, 2>
2668///
2669/// When undef's appear in the mask they are treated as if they were whatever
2670/// value is necessary in order to fit the above forms.
2672 MVT VT, SDValue V1, SDValue V2,
2673 SelectionDAG &DAG,
2675 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2676 Mask.size() != VT.getVectorNumElements())
2677 return SDValue();
2678
2680 unsigned MaskImm = 0;
2681 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2682 return SDValue();
2683
2684 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2685 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2686}
2687
2688/// Lower VECTOR_SHUFFLE into VSHUF.
2689///
2690/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2691/// adding it as an operand to the resulting VSHUF.
2693 MVT VT, SDValue V1, SDValue V2,
2694 SelectionDAG &DAG,
2696
2698 for (auto M : Mask)
2699 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2700
2701 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2702 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2703
2704 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2705 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2706 // VSHF concatenates the vectors in a bitwise fashion:
2707 // <0b00, 0b01> + <0b10, 0b11> ->
2708 // 0b0100 + 0b1110 -> 0b01001110
2709 // <0b10, 0b11, 0b00, 0b01>
2710 // We must therefore swap the operands to get the correct result.
2711 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2712}
2713
2714/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2715///
2716/// This routine breaks down the specific type of 128-bit shuffle and
2717/// dispatches to the lowering routines accordingly.
2719 SDValue V1, SDValue V2, SelectionDAG &DAG,
2721 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2722 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2723 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2724 "Vector type is unsupported for lsx!");
2725 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2726 "Two operands have different types!");
2727 assert(VT.getVectorNumElements() == Mask.size() &&
2728 "Unexpected mask size for shuffle!");
2729 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2730
2731 APInt KnownUndef, KnownZero;
2732 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2733 APInt Zeroable = KnownUndef | KnownZero;
2734
2735 SDValue Result;
2736 // TODO: Add more comparison patterns.
2737 if (V2.isUndef()) {
2738 if ((Result =
2739 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2740 return Result;
2741 if ((Result =
2742 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2743 return Result;
2744 if ((Result =
2745 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2746 return Result;
2747
2748 // TODO: This comment may be enabled in the future to better match the
2749 // pattern for instruction selection.
2750 /* V2 = V1; */
2751 }
2752
2753 // It is recommended not to change the pattern comparison order for better
2754 // performance.
2755 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2756 return Result;
2757 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2758 return Result;
2759 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2760 return Result;
2761 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2762 return Result;
2763 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2764 return Result;
2765 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2766 return Result;
2767 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2768 (Result =
2769 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2770 return Result;
2771 if ((Result =
2772 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2773 return Result;
2774 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2775 Zeroable)))
2776 return Result;
2777 if ((Result =
2778 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2779 return Result;
2780 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2781 Zeroable)))
2782 return Result;
2783 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2784 Subtarget)))
2785 return Result;
2786 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2787 return NewShuffle;
2788 if ((Result =
2789 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2790 return Result;
2791 return SDValue();
2792}
2793
2794/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2795///
2796/// It is a XVREPLVEI when the mask is:
2797/// <x, x, x, ..., x+n, x+n, x+n, ...>
2798/// where the number of x is equal to n and n is half the length of vector.
2799///
2800/// When undef's appear in the mask they are treated as if they were whatever
2801/// value is necessary in order to fit the above form.
2802static SDValue
2804 SDValue V1, SelectionDAG &DAG,
2806 int SplatIndex = -1;
2807 for (const auto &M : Mask) {
2808 if (M != -1) {
2809 SplatIndex = M;
2810 break;
2811 }
2812 }
2813
2814 if (SplatIndex == -1)
2815 return DAG.getUNDEF(VT);
2816
2817 const auto &Begin = Mask.begin();
2818 const auto &End = Mask.end();
2819 int HalfSize = Mask.size() / 2;
2820
2821 if (SplatIndex >= HalfSize)
2822 return SDValue();
2823
2824 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2825 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2826 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2827 0)) {
2828 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2829 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2830 }
2831
2832 return SDValue();
2833}
2834
2835/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2836static SDValue
2838 SDValue V1, SDValue V2, SelectionDAG &DAG,
2840 // XVSHUF4I_D must be handled separately because it is different from other
2841 // types of [X]VSHUF4I instructions.
2842 if (Mask.size() == 4) {
2843 unsigned MaskImm = 0;
2844 for (int i = 1; i >= 0; --i) {
2845 int MLo = Mask[i];
2846 int MHi = Mask[i + 2];
2847 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2848 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2849 return SDValue();
2850 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2851 return SDValue();
2852
2853 MaskImm <<= 2;
2854 if (MLo != -1)
2855 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2856 else if (MHi != -1)
2857 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2858 }
2859
2860 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2861 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2862 }
2863
2864 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2865}
2866
2867/// Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
2868///
2869/// It is a XVREPLVE0 when the VECTOR_SHUFFLE is a broadcast of element 0,
2870/// i.e. the mask is:
2871/// <0, 0, 0, ...>
2872///
2873/// When undef's appear in the mask they are treated as if they were whatever
2874/// value is necessary in order to fit the above form.
2876 ArrayRef<int> Mask, MVT VT,
2877 SDValue V1, SelectionDAG &DAG) {
2878 if (!ShuffleVectorInst::isZeroEltSplatMask(Mask, Mask.size()))
2879 return SDValue();
2880
2881 return DAG.getNode(LoongArchISD::XVREPLVE0, DL, VT, V1);
2882}
2883
2884/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2885static SDValue
2887 SDValue V1, SDValue V2, SelectionDAG &DAG,
2889 MVT GRLenVT = Subtarget.getGRLenVT();
2890 unsigned MaskSize = Mask.size();
2891 if (MaskSize != VT.getVectorNumElements())
2892 return SDValue();
2893
2894 // Consider XVPERMI_W.
2895 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2897 unsigned MaskImm = 0;
2898 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2899 return SDValue();
2900
2901 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2902 DAG.getConstant(MaskImm, DL, GRLenVT));
2903 }
2904
2905 // Consider XVPERMI_D.
2906 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2907 unsigned MaskImm = 0;
2908 for (unsigned i = 0; i < MaskSize; ++i) {
2909 if (Mask[i] == -1)
2910 continue;
2911 if (Mask[i] >= (int)MaskSize)
2912 return SDValue();
2913 MaskImm |= Mask[i] << (i * 2);
2914 }
2915
2916 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2917 DAG.getConstant(MaskImm, DL, GRLenVT));
2918 }
2919
2920 return SDValue();
2921}
2922
2923/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2925 MVT VT, SDValue V1, SelectionDAG &DAG,
2927 // LoongArch LASX only have XVPERM_W.
2928 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2929 return SDValue();
2930
2931 unsigned NumElts = VT.getVectorNumElements();
2932 unsigned HalfSize = NumElts / 2;
2933 bool FrontLo = true, FrontHi = true;
2934 bool BackLo = true, BackHi = true;
2935
2936 auto inRange = [](int val, int low, int high) {
2937 return (val == -1) || (val >= low && val < high);
2938 };
2939
2940 for (unsigned i = 0; i < HalfSize; ++i) {
2941 int Fronti = Mask[i];
2942 int Backi = Mask[i + HalfSize];
2943
2944 FrontLo &= inRange(Fronti, 0, HalfSize);
2945 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2946 BackLo &= inRange(Backi, 0, HalfSize);
2947 BackHi &= inRange(Backi, HalfSize, NumElts);
2948 }
2949
2950 // If both the lower and upper 128-bit parts access only one half of the
2951 // vector (either lower or upper), avoid using xvperm.w. The latency of
2952 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2953 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2954 return SDValue();
2955
2957 MVT GRLenVT = Subtarget.getGRLenVT();
2958 for (unsigned i = 0; i < NumElts; ++i)
2959 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2960 : DAG.getConstant(Mask[i], DL, GRLenVT));
2961 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2962
2963 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2964}
2965
2966/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2968 MVT VT, SDValue V1, SDValue V2,
2969 SelectionDAG &DAG) {
2970 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2971}
2972
2973/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2975 MVT VT, SDValue V1, SDValue V2,
2976 SelectionDAG &DAG) {
2977 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2978}
2979
2980/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2982 MVT VT, SDValue V1, SDValue V2,
2983 SelectionDAG &DAG) {
2984
2985 const auto &Begin = Mask.begin();
2986 const auto &End = Mask.end();
2987 unsigned HalfSize = Mask.size() / 2;
2988 unsigned LeftSize = HalfSize / 2;
2989 SDValue OriV1 = V1, OriV2 = V2;
2990
2991 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2992 1) &&
2993 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2994 V1 = OriV1;
2995 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2996 Mask.size() + HalfSize - LeftSize, 1) &&
2997 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2998 Mask.size() + HalfSize + LeftSize, 1))
2999 V1 = OriV2;
3000 else
3001 return SDValue();
3002
3003 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
3004 1) &&
3005 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
3006 1))
3007 V2 = OriV1;
3008 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
3009 Mask.size() + HalfSize - LeftSize, 1) &&
3010 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
3011 Mask.size() + HalfSize + LeftSize, 1))
3012 V2 = OriV2;
3013 else
3014 return SDValue();
3015
3016 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
3017}
3018
3019/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
3021 MVT VT, SDValue V1, SDValue V2,
3022 SelectionDAG &DAG) {
3023
3024 const auto &Begin = Mask.begin();
3025 const auto &End = Mask.end();
3026 unsigned HalfSize = Mask.size() / 2;
3027 SDValue OriV1 = V1, OriV2 = V2;
3028
3029 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
3030 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
3031 V1 = OriV1;
3032 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
3033 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
3034 Mask.size() + HalfSize, 1))
3035 V1 = OriV2;
3036 else
3037 return SDValue();
3038
3039 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
3040 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
3041 V2 = OriV1;
3042 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
3043 1) &&
3044 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
3045 Mask.size() + HalfSize, 1))
3046 V2 = OriV2;
3047 else
3048 return SDValue();
3049
3050 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
3051}
3052
3053/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
3055 MVT VT, SDValue V1, SDValue V2,
3056 SelectionDAG &DAG) {
3057
3058 const auto &Begin = Mask.begin();
3059 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3060 const auto &Mid = Mask.begin() + Mask.size() / 2;
3061 const auto &RightMid = Mask.end() - Mask.size() / 4;
3062 const auto &End = Mask.end();
3063 unsigned HalfSize = Mask.size() / 2;
3064 SDValue OriV1 = V1, OriV2 = V2;
3065
3066 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
3067 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
3068 V1 = OriV1;
3069 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
3070 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
3071 V1 = OriV2;
3072 else
3073 return SDValue();
3074
3075 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
3076 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
3077 V2 = OriV1;
3078 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
3079 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
3080 V2 = OriV2;
3081
3082 else
3083 return SDValue();
3084
3085 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
3086}
3087
3088/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
3090 MVT VT, SDValue V1, SDValue V2,
3091 SelectionDAG &DAG) {
3092
3093 const auto &Begin = Mask.begin();
3094 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3095 const auto &Mid = Mask.begin() + Mask.size() / 2;
3096 const auto &RightMid = Mask.end() - Mask.size() / 4;
3097 const auto &End = Mask.end();
3098 unsigned HalfSize = Mask.size() / 2;
3099 SDValue OriV1 = V1, OriV2 = V2;
3100
3101 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
3102 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
3103 V1 = OriV1;
3104 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3105 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3106 2))
3107 V1 = OriV2;
3108 else
3109 return SDValue();
3110
3111 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3112 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3113 V2 = OriV1;
3114 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3115 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3116 2))
3117 V2 = OriV2;
3118 else
3119 return SDValue();
3120
3121 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3122}
3123
3124/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3125static SDValue
3127 SDValue V1, SDValue V2, SelectionDAG &DAG,
3129 int NumElts = VT.getVectorNumElements();
3130 int HalfSize = NumElts / 2;
3131 MVT EltVT = VT.getVectorElementType();
3132 MVT GRLenVT = Subtarget.getGRLenVT();
3133
3134 if ((int)Mask.size() != NumElts)
3135 return SDValue();
3136
3137 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3138 SmallVector<int> DiffPos;
3139 for (int i = 0; i < NumElts; ++i) {
3140 if (Mask[i] == -1)
3141 continue;
3142 if (Mask[i] != Base + i) {
3143 DiffPos.push_back(i);
3144 if (DiffPos.size() > 2)
3145 return SDValue();
3146 }
3147 }
3148
3149 // Need exactly two differing element to lower into XVEXTRINS.
3150 // If only one differing element, the element at a distance of
3151 // HalfSize from it must be undef.
3152 if (DiffPos.size() == 1) {
3153 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3154 DiffPos.push_back(DiffPos[0] + HalfSize);
3155 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3156 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3157 else
3158 return SDValue();
3159 }
3160 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3161 return SDValue();
3162
3163 // DiffMask must be in its low or high part.
3164 int DiffMaskLo = Mask[DiffPos[0]];
3165 int DiffMaskHi = Mask[DiffPos[1]];
3166 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3167 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3168 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3169 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3170 return SDValue();
3171 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3172 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3173 return SDValue();
3174 if (DiffMaskHi != DiffMaskLo + HalfSize)
3175 return SDValue();
3176
3177 // Determine source vector and source index.
3178 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3179 int SrcIdxLo =
3180 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3181 bool IsEltFP = EltVT.isFloatingPoint();
3182
3183 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3184 // the patterns of XVEXTRINS in tablegen.
3185 SDValue BaseVec = (Base == 0) ? V1 : V2;
3186 SDValue EltLo =
3187 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3188 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3189 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3190 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3191 SDValue EltHi =
3192 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3193 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3194 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3195 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3196
3197 return Result;
3198 };
3199
3200 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3201 if (SDValue Result = tryLowerToExtrAndIns(0))
3202 return Result;
3203 return tryLowerToExtrAndIns(NumElts);
3204}
3205
3206/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3207static SDValue
3209 SDValue V1, SDValue V2, SelectionDAG &DAG,
3211 // LoongArch LASX only supports xvinsve0.{w/d}.
3212 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3213 VT != MVT::v4f64)
3214 return SDValue();
3215
3216 MVT GRLenVT = Subtarget.getGRLenVT();
3217 int MaskSize = Mask.size();
3218 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3219
3220 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3221 // all other elements are either 'Base + i' or undef (-1). On success, return
3222 // the index of the replaced element. Otherwise, just return -1.
3223 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3224 int Idx = -1;
3225 for (int i = 0; i < MaskSize; ++i) {
3226 if (Mask[i] == Base + i || Mask[i] == -1)
3227 continue;
3228 if (Mask[i] != Replaced)
3229 return -1;
3230 if (Idx == -1)
3231 Idx = i;
3232 else
3233 return -1;
3234 }
3235 return Idx;
3236 };
3237
3238 // Case 1: the lowest element of V2 replaces one element in V1.
3239 int Idx = checkReplaceOne(0, MaskSize);
3240 if (Idx != -1)
3241 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3242 DAG.getConstant(Idx, DL, GRLenVT));
3243
3244 // Case 2: the lowest element of V1 replaces one element in V2.
3245 Idx = checkReplaceOne(MaskSize, 0);
3246 if (Idx != -1)
3247 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3248 DAG.getConstant(Idx, DL, GRLenVT));
3249
3250 return SDValue();
3251}
3252
3253/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3255 MVT VT, SDValue V1, SDValue V2,
3256 SelectionDAG &DAG) {
3257
3258 int MaskSize = Mask.size();
3259 int HalfSize = Mask.size() / 2;
3260 const auto &Begin = Mask.begin();
3261 const auto &Mid = Mask.begin() + HalfSize;
3262 const auto &End = Mask.end();
3263
3264 // VECTOR_SHUFFLE concatenates the vectors:
3265 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3266 // shuffling ->
3267 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3268 //
3269 // XVSHUF concatenates the vectors:
3270 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3271 // shuffling ->
3272 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3273 SmallVector<SDValue, 8> MaskAlloc;
3274 for (auto it = Begin; it < Mid; it++) {
3275 if (*it < 0) // UNDEF
3276 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3277 else if ((*it >= 0 && *it < HalfSize) ||
3278 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3279 int M = *it < HalfSize ? *it : *it - HalfSize;
3280 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3281 } else
3282 return SDValue();
3283 }
3284 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3285
3286 for (auto it = Mid; it < End; it++) {
3287 if (*it < 0) // UNDEF
3288 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3289 else if ((*it >= HalfSize && *it < MaskSize) ||
3290 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3291 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3292 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3293 } else
3294 return SDValue();
3295 }
3296 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3297
3298 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3299 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3300 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3301}
3302
3303/// Shuffle vectors by lane to generate more optimized instructions.
3304/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3305///
3306/// Therefore, except for the following four cases, other cases are regarded
3307/// as cross-lane shuffles, where optimization is relatively limited.
3308///
3309/// - Shuffle high, low lanes of two inputs vector
3310/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3311/// - Shuffle low, high lanes of two inputs vector
3312/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3313/// - Shuffle low, low lanes of two inputs vector
3314/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3315/// - Shuffle high, high lanes of two inputs vector
3316/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3317///
3318/// The first case is the closest to LoongArch instructions and the other
3319/// cases need to be converted to it for processing.
3320///
3321/// This function will return true for the last three cases above and will
3322/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3323/// cross-lane shuffle cases.
3325 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3327
3328 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3329
3330 int MaskSize = Mask.size();
3331 int HalfSize = Mask.size() / 2;
3332 MVT GRLenVT = Subtarget.getGRLenVT();
3333
3334 HalfMaskType preMask = None, postMask = None;
3335
3336 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3337 return M < 0 || (M >= 0 && M < HalfSize) ||
3338 (M >= MaskSize && M < MaskSize + HalfSize);
3339 }))
3340 preMask = HighLaneTy;
3341 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3342 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3343 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3344 }))
3345 preMask = LowLaneTy;
3346
3347 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3348 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3349 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3350 }))
3351 postMask = LowLaneTy;
3352 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3353 return M < 0 || (M >= 0 && M < HalfSize) ||
3354 (M >= MaskSize && M < MaskSize + HalfSize);
3355 }))
3356 postMask = HighLaneTy;
3357
3358 // The pre-half of mask is high lane type, and the post-half of mask
3359 // is low lane type, which is closest to the LoongArch instructions.
3360 //
3361 // Note: In the LoongArch architecture, the high lane of mask corresponds
3362 // to the lower 128-bit of vector register, and the low lane of mask
3363 // corresponds the higher 128-bit of vector register.
3364 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3365 return false;
3366 }
3367 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3368 V1 = DAG.getBitcast(MVT::v4i64, V1);
3369 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3370 DAG.getConstant(0b01001110, DL, GRLenVT));
3371 V1 = DAG.getBitcast(VT, V1);
3372
3373 if (!V2.isUndef()) {
3374 V2 = DAG.getBitcast(MVT::v4i64, V2);
3375 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3376 DAG.getConstant(0b01001110, DL, GRLenVT));
3377 V2 = DAG.getBitcast(VT, V2);
3378 }
3379
3380 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3381 *it = *it < 0 ? *it : *it - HalfSize;
3382 }
3383 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3384 *it = *it < 0 ? *it : *it + HalfSize;
3385 }
3386 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3387 V1 = DAG.getBitcast(MVT::v4i64, V1);
3388 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3389 DAG.getConstant(0b11101110, DL, GRLenVT));
3390 V1 = DAG.getBitcast(VT, V1);
3391
3392 if (!V2.isUndef()) {
3393 V2 = DAG.getBitcast(MVT::v4i64, V2);
3394 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3395 DAG.getConstant(0b11101110, DL, GRLenVT));
3396 V2 = DAG.getBitcast(VT, V2);
3397 }
3398
3399 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3400 *it = *it < 0 ? *it : *it - HalfSize;
3401 }
3402 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3403 V1 = DAG.getBitcast(MVT::v4i64, V1);
3404 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3405 DAG.getConstant(0b01000100, DL, GRLenVT));
3406 V1 = DAG.getBitcast(VT, V1);
3407
3408 if (!V2.isUndef()) {
3409 V2 = DAG.getBitcast(MVT::v4i64, V2);
3410 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3411 DAG.getConstant(0b01000100, DL, GRLenVT));
3412 V2 = DAG.getBitcast(VT, V2);
3413 }
3414
3415 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3416 *it = *it < 0 ? *it : *it + HalfSize;
3417 }
3418 } else { // cross-lane
3419 return false;
3420 }
3421
3422 return true;
3423}
3424
3425/// Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
3426///
3427/// For example:
3428/// %2 = shufflevector <4 x i64> %0, <4 x i64> %1,
3429/// <4 x i32> <i32 2, i32 3, i32 4, i32 5>
3430/// is lowered to:
3431/// (XVPERMI_Q $xr1, $xr0, 33)
3432static SDValue
3434 SDValue V1, SDValue V2, SelectionDAG &DAG,
3436 // Each 128-bit lane of the result must be a whole lane of V1 or V2.
3437 SmallVector<int, 2> LaneMask;
3438 if (!widenShuffleMaskElts(Mask.size() / 2, Mask, LaneMask))
3439 return SDValue();
3440
3441 // Lanes 0-3 are V1.lo, V1.hi, V2.lo and V2.hi, the same as the XVPERMI_Q
3442 // selector with xj = V1 and xd = V2.
3443 int Lo = LaneMask[0] < 0 ? 0 : LaneMask[0];
3444 int Hi = LaneMask[1] < 0 ? 1 : LaneMask[1];
3445 return DAG.getNode(
3446 LoongArchISD::XVPERMIQ, DL, VT, V2, V1,
3447 DAG.getConstant(Lo | (Hi << 4), DL, Subtarget.getGRLenVT()));
3448}
3449
3450/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3451/// Only for 256-bit vector.
3452///
3453/// Each 128-bit lane of the result may use at most two lanes of the inputs.
3454/// These lanes are first moved into place, then shuffled within the lane.
3455///
3456/// For example:
3457/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3458/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3459/// is lowerded to:
3460/// (XVPERMI $xr2, $xr0, 78)
3461/// (XVSHUF $xr1, $xr2, $xr0)
3462/// (XVORI $xr0, $xr1, 0)
3463///
3464/// and the splice:
3465/// %2 = shufflevector <8 x i32> %0, <8 x i32> %1,
3466/// <8 x i32> <i32 7, i32 8, i32 9, i32 10,
3467/// i32 11, i32 12, i32 13, i32 14>
3468/// is lowered to:
3469/// (XVBSLL_V $xr2, $xr1, 4)
3470/// (XVPERMI_Q $xr1, $xr0, 33)
3471/// (XVBSRL_V $xr0, $xr1, 12)
3472/// (XVOR_V $xr0, $xr2, $xr0)
3474 ArrayRef<int> Mask,
3475 MVT VT, SDValue V1,
3476 SDValue V2,
3477 SelectionDAG &DAG) {
3478 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3479 int Size = Mask.size();
3480 int LaneSize = Size / 2;
3481
3482 // For each result lane, the input lanes (0/1: V1, 2/3: V2) used by the two
3483 // operands of the in-lane shuffle.
3484 int LaneSrcs[2][2] = {{-1, -1}, {-1, -1}};
3485 SmallVector<int, 32> InLaneMask(Size, -1);
3486 bool LaneCrossing = false;
3487 for (int i = 0; i < Size; ++i) {
3488 int M = Mask[i];
3489 if (M < 0)
3490 continue;
3491 int Lane = i / LaneSize;
3492 int SrcLane = M / LaneSize;
3493
3494 // Put lanes that stay in place in the first operand and the others in the
3495 // second one, so a single input becomes V1 and V1 with lanes swapped.
3496 int Op = (SrcLane % 2) != Lane;
3497 LaneCrossing |= Op;
3498 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3499 Op ^= 1;
3500 if (LaneSrcs[Lane][Op] >= 0 && LaneSrcs[Lane][Op] != SrcLane)
3501 return SDValue();
3502 LaneSrcs[Lane][Op] = SrcLane;
3503 InLaneMask[i] = Op * Size + Lane * LaneSize + M % LaneSize;
3504 }
3505
3506 if (!LaneCrossing)
3507 return SDValue();
3508
3509 // Swap the operands of the high lane if that makes both lanes use the same
3510 // in-lane mask, which more patterns (e.g. XVPICKEV) can match.
3511 SmallVector<int, 16> RepeatedMask;
3512 if (!isRepeatedShuffleMask(128, VT, InLaneMask, RepeatedMask)) {
3513 SmallVector<int, 32> SwappedMask(InLaneMask);
3514 for (int i = LaneSize; i < Size; ++i)
3515 if (SwappedMask[i] >= 0)
3516 SwappedMask[i] = (SwappedMask[i] + Size) % (2 * Size);
3517 if (isRepeatedShuffleMask(128, VT, SwappedMask, RepeatedMask)) {
3518 std::swap(LaneSrcs[1][0], LaneSrcs[1][1]);
3519 InLaneMask = SwappedMask;
3520 }
3521 }
3522
3523 // Move the input lanes of each operand into place.
3524 SDValue Ops[2];
3525 for (int Op = 0; Op < 2; ++Op) {
3526 SmallVector<int, 32> LaneMask(Size, -1);
3527 for (int Lane = 0; Lane < 2; ++Lane)
3528 if (LaneSrcs[Lane][Op] >= 0)
3529 for (int i = 0; i < LaneSize; ++i)
3530 LaneMask[Lane * LaneSize + i] = LaneSrcs[Lane][Op] * LaneSize + i;
3531 Ops[Op] = DAG.getVectorShuffle(VT, DL, V1, V2, LaneMask);
3532
3533 // Exit if we got back the shuffle we started with, to avoid infinite
3534 // recursion.
3535 if (auto *SVN = dyn_cast<ShuffleVectorSDNode>(Ops[Op]))
3536 if (SVN->getMask() == Mask)
3537 return SDValue();
3538 }
3539 return DAG.getVectorShuffle(VT, DL, Ops[0], Ops[1], InLaneMask);
3540}
3541
3542/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3543///
3544/// This routine breaks down the specific type of 256-bit shuffle and
3545/// dispatches to the lowering routines accordingly.
3547 SDValue V1, SDValue V2, SelectionDAG &DAG,
3549 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3550 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3551 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3552 "Vector type is unsupported for lasx!");
3553 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3554 "Two operands have different types!");
3555 assert(VT.getVectorNumElements() == Mask.size() &&
3556 "Unexpected mask size for shuffle!");
3557 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3558 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3559
3560 APInt KnownUndef, KnownZero;
3561 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3562 APInt Zeroable = KnownUndef | KnownZero;
3563
3564 SDValue Result;
3565 // TODO: Add more comparison patterns.
3566 if (V2.isUndef()) {
3567 if ((Result =
3568 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3569 return Result;
3570 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3571 Subtarget)))
3572 return Result;
3573 if ((Result = lowerVECTOR_SHUFFLE_XVREPLVE0(DL, Mask, VT, V1, DAG)))
3574 return Result;
3575 // Try to widen vectors to gain more optimization opportunities.
3576 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3577 return NewShuffle;
3578 if ((Result =
3579 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3580 return Result;
3581 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3582 return Result;
3583 if ((Result =
3584 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3585 return Result;
3586
3587 // TODO: This comment may be enabled in the future to better match the
3588 // pattern for instruction selection.
3589 /* V2 = V1; */
3590 }
3591
3592 // It is recommended not to change the pattern comparison order for better
3593 // performance.
3594 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3595 return Result;
3596 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3597 return Result;
3598 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3599 return Result;
3600 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3601 return Result;
3602 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3603 return Result;
3604 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3605 return Result;
3606 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3607 (Result =
3608 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3609 return Result;
3610 if ((Result =
3611 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3612 return Result;
3613 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3614 Zeroable)))
3615 return Result;
3616 if ((Result =
3617 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3618 return Result;
3619 if ((Result =
3620 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3621 return Result;
3622 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3623 Subtarget)))
3624 return Result;
3625
3626 if ((Result =
3627 lowerVECTOR_SHUFFLE_XVPERMIQ(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3628 return Result;
3629
3630 // canonicalize non cross-lane shuffle vector
3631 SmallVector<int> NewMask(Mask);
3632 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3633 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3634
3635 // FIXME: Handling the remaining cases earlier can degrade performance
3636 // in some situations. Further analysis is required to enable more
3637 // effective optimizations.
3638 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT, V1,
3639 V2, DAG)))
3640 return Result;
3641
3642 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3643 return NewShuffle;
3644 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3645 return Result;
3646
3647 return SDValue();
3648}
3649
3650SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3651 SelectionDAG &DAG) const {
3652 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3653 ArrayRef<int> OrigMask = SVOp->getMask();
3654 SDValue V1 = Op.getOperand(0);
3655 SDValue V2 = Op.getOperand(1);
3656 MVT VT = Op.getSimpleValueType();
3657 int NumElements = VT.getVectorNumElements();
3658 SDLoc DL(Op);
3659
3660 bool V1IsUndef = V1.isUndef();
3661 bool V2IsUndef = V2.isUndef();
3662 if (V1IsUndef && V2IsUndef)
3663 return DAG.getUNDEF(VT);
3664
3665 // When we create a shuffle node we put the UNDEF node to second operand,
3666 // but in some cases the first operand may be transformed to UNDEF.
3667 // In this case we should just commute the node.
3668 if (V1IsUndef)
3669 return DAG.getCommutedVectorShuffle(*SVOp);
3670
3671 // Check for non-undef masks pointing at an undef vector and make the masks
3672 // undef as well. This makes it easier to match the shuffle based solely on
3673 // the mask.
3674 if (V2IsUndef &&
3675 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3676 SmallVector<int, 8> NewMask(OrigMask);
3677 for (int &M : NewMask)
3678 if (M >= NumElements)
3679 M = -1;
3680 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3681 }
3682
3683 // Check for illegal shuffle mask element index values.
3684 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3685 (void)MaskUpperLimit;
3686 assert(llvm::all_of(OrigMask,
3687 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3688 "Out of bounds shuffle index");
3689
3690 // For each vector width, delegate to a specialized lowering routine.
3691 if (VT.is128BitVector())
3692 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3693
3694 if (VT.is256BitVector())
3695 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3696
3697 return SDValue();
3698}
3699
3700SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3701 SelectionDAG &DAG) const {
3702 // Custom lower to ensure the libcall return is passed in an FPR on hard
3703 // float ABIs.
3704 SDLoc DL(Op);
3705 MakeLibCallOptions CallOptions;
3706 SDValue Op0 = Op.getOperand(0);
3707 SDValue Chain = SDValue();
3708 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3709 SDValue Res;
3710 std::tie(Res, Chain) =
3711 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3712 if (Subtarget.is64Bit())
3713 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3714 return DAG.getBitcast(MVT::i32, Res);
3715}
3716
3717SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3718 SelectionDAG &DAG) const {
3719 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3720 // float ABIs.
3721 SDLoc DL(Op);
3722 MakeLibCallOptions CallOptions;
3723 SDValue Op0 = Op.getOperand(0);
3724 SDValue Chain = SDValue();
3725 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3726 DL, MVT::f32, Op0)
3727 : DAG.getBitcast(MVT::f32, Op0);
3728 SDValue Res;
3729 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3730 CallOptions, DL, Chain);
3731 return Res;
3732}
3733
3734SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3735 SelectionDAG &DAG) const {
3736 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3737 SDLoc DL(Op);
3738 MakeLibCallOptions CallOptions;
3739 RTLIB::Libcall LC =
3740 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3741 SDValue Res =
3742 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3743 if (Subtarget.is64Bit())
3744 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3745 return DAG.getBitcast(MVT::i32, Res);
3746}
3747
3748SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3749 SelectionDAG &DAG) const {
3750 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3751 MVT VT = Op.getSimpleValueType();
3752 SDLoc DL(Op);
3753 Op = DAG.getNode(
3754 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3755 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3756 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3757 DL, MVT::f32, Op)
3758 : DAG.getBitcast(MVT::f32, Op);
3759 if (VT != MVT::f32)
3760 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3761 return Res;
3762}
3763
3764// Lower BUILD_VECTOR as broadcast load (if possible).
3765// For example:
3766// %a = load i8, ptr %ptr
3767// %b = build_vector %a, %a, %a, %a
3768// is lowered to :
3769// (VLDREPL_B $a0, 0)
3771 const SDLoc &DL,
3772 SelectionDAG &DAG) {
3773 MVT VT = BVOp->getSimpleValueType(0);
3774 int NumOps = BVOp->getNumOperands();
3775
3776 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3777 "Unsupported vector type for broadcast.");
3778
3779 SDValue IdentitySrc;
3780 bool IsIdeneity = true;
3781
3782 for (int i = 0; i != NumOps; i++) {
3783 SDValue Op = BVOp->getOperand(i);
3784 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3785 IsIdeneity = false;
3786 break;
3787 }
3788 IdentitySrc = BVOp->getOperand(0);
3789 }
3790
3791 // make sure that this load is valid and only has one user.
3792 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3793 return SDValue();
3794
3795 auto *LN = cast<LoadSDNode>(IdentitySrc);
3796 auto ExtType = LN->getExtensionType();
3797
3798 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3799 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3800 // Indexed loads and stores are not supported on LoongArch.
3801 assert(LN->isUnindexed() && "Unexpected indexed load.");
3802
3803 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3804 // The offset operand of unindexed load is always undefined, so there is
3805 // no need to pass it to VLDREPL.
3806 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3807 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3808 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3809 return BCast;
3810 }
3811 return SDValue();
3812}
3813
3814// Sequentially insert elements from Ops into Vector, from low to high indices.
3815// Note: Ops can have fewer elements than Vector.
3818 EVT ResTy) {
3819 assert(Ops.size() <= ResTy.getVectorNumElements());
3820
3821 SDValue Op0 = Ops[0];
3822 if (!Op0.isUndef())
3823 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3824 for (unsigned i = 1; i < Ops.size(); ++i) {
3825 SDValue Opi = Ops[i];
3826 if (Opi.isUndef())
3827 continue;
3828 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3829 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3830 }
3831}
3832
3833// Build a ResTy subvector from Node, taking NumElts elements starting at index
3834// 'first'.
3836 SelectionDAG &DAG, SDLoc DL,
3838 EVT ResTy, unsigned first) {
3839 unsigned NumElts = ResTy.getVectorNumElements();
3840
3841 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3842
3843 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3844 Node->op_begin() + first + NumElts);
3845 SDValue Vector = DAG.getUNDEF(ResTy);
3846 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3847 return Vector;
3848}
3849
3850SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3851 SelectionDAG &DAG) const {
3852 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3853 MVT VT = Node->getSimpleValueType(0);
3854 EVT ResTy = Op->getValueType(0);
3855 unsigned NumElts = ResTy.getVectorNumElements();
3856 SDLoc DL(Op);
3857 APInt SplatValue, SplatUndef;
3858 unsigned SplatBitSize;
3859 bool HasAnyUndefs;
3860 bool IsConstant = false;
3861 bool UseSameConstant = true;
3862 SDValue ConstantValue;
3863 bool Is128Vec = ResTy.is128BitVector();
3864 bool Is256Vec = ResTy.is256BitVector();
3865
3866 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3867 (!Subtarget.hasExtLASX() || !Is256Vec))
3868 return SDValue();
3869
3870 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3871 return Result;
3872
3873 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3874 /*MinSplatBits=*/8) &&
3875 SplatBitSize <= 64) {
3876 // We can only cope with 8, 16, 32, or 64-bit elements.
3877 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3878 SplatBitSize != 64)
3879 return SDValue();
3880
3881 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3882 // We can only handle 64-bit elements that are within
3883 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3884 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3885 if (!SplatValue.isSignedIntN(10) &&
3886 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3887 return SDValue();
3888 if ((Is128Vec && ResTy == MVT::v4i32) ||
3889 (Is256Vec && ResTy == MVT::v8i32))
3890 return Op;
3891 }
3892
3893 EVT ViaVecTy;
3894
3895 switch (SplatBitSize) {
3896 default:
3897 return SDValue();
3898 case 8:
3899 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3900 break;
3901 case 16:
3902 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3903 break;
3904 case 32:
3905 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3906 break;
3907 case 64:
3908 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3909 break;
3910 }
3911
3912 // SelectionDAG::getConstant will promote SplatValue appropriately.
3913 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3914
3915 // Bitcast to the type we originally wanted.
3916 if (ViaVecTy != ResTy)
3917 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3918
3919 return Result;
3920 }
3921
3922 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3923 return Op;
3924
3925 for (unsigned i = 0; i < NumElts; ++i) {
3926 SDValue Opi = Node->getOperand(i);
3927 if (isIntOrFPConstant(Opi)) {
3928 IsConstant = true;
3929 if (!ConstantValue.getNode())
3930 ConstantValue = Opi;
3931 else if (ConstantValue != Opi)
3932 UseSameConstant = false;
3933 }
3934 }
3935
3936 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3937 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3938 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3939 for (unsigned i = 0; i < NumElts; ++i) {
3940 SDValue Opi = Node->getOperand(i);
3941 if (!isIntOrFPConstant(Opi))
3942 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3943 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3944 }
3945 return Result;
3946 }
3947
3948 if (!IsConstant) {
3949 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3950 // the sub-sequence of the vector and then broadcast the sub-sequence.
3951 //
3952 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3953 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3954 // generates worse code in some cases. This could be further optimized
3955 // with more consideration.
3957 BitVector UndefElements;
3958 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3959 UndefElements.count() == 0) {
3960 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3961 // because the high part can be simply treated as undef.
3962 SDValue Vector = DAG.getUNDEF(ResTy);
3963 EVT FillTy = Is256Vec
3965 : ResTy;
3966 SDValue FillVec =
3967 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3968
3969 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3970
3971 unsigned SeqLen = Sequence.size();
3972 unsigned SplatLen = NumElts / SeqLen;
3973 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3974 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3975
3976 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3977 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3978 if (SplatEltTy == MVT::i128)
3979 SplatTy = MVT::v4i64;
3980
3981 SDValue SplatVec;
3982 SDValue SrcVec = DAG.getBitcast(
3983 SplatTy,
3984 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3985 if (Is256Vec) {
3986 SplatVec =
3987 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3988 : LoongArchISD::XVREPLVE0,
3989 DL, SplatTy, SrcVec);
3990 } else {
3991 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3992 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3993 }
3994
3995 return DAG.getBitcast(ResTy, SplatVec);
3996 }
3997
3998 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3999 // using memory operations is much lower.
4000 //
4001 // For 256-bit vectors, normally split into two halves and concatenate.
4002 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
4003 // one non-undef element, skip spliting to avoid a worse result.
4004 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
4005 ResTy == MVT::v4f64) {
4006 unsigned NonUndefCount = 0;
4007 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
4008 if (!Node->getOperand(i).isUndef()) {
4009 ++NonUndefCount;
4010 if (NonUndefCount > 1)
4011 break;
4012 }
4013 }
4014 if (NonUndefCount == 1)
4015 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
4016 }
4017
4018 EVT VecTy =
4019 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
4020 SDValue Vector =
4021 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
4022
4023 if (Is128Vec)
4024 return Vector;
4025
4026 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
4027 VecTy, NumElts / 2);
4028
4029 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
4030 }
4031
4032 return SDValue();
4033}
4034
4035SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
4036 SelectionDAG &DAG) const {
4037 SDLoc DL(Op);
4038 MVT ResVT = Op.getSimpleValueType();
4039 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
4040
4041 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
4042 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
4043 return Op;
4044
4045 unsigned NumOperands = Op.getNumOperands();
4046 unsigned NumFreezeUndef = 0;
4047 unsigned NumZero = 0;
4048 unsigned NumNonZero = 0;
4049 unsigned NonZeros = 0;
4050 SmallSet<SDValue, 4> Undefs;
4051 for (unsigned i = 0; i != NumOperands; ++i) {
4052 SDValue SubVec = Op.getOperand(i);
4053 if (SubVec.isUndef())
4054 continue;
4055 if (ISD::isFreezeUndef(SubVec.getNode())) {
4056 // If the freeze(undef) has multiple uses then we must fold to zero.
4057 if (SubVec.hasOneUse()) {
4058 ++NumFreezeUndef;
4059 } else {
4060 ++NumZero;
4061 Undefs.insert(SubVec);
4062 }
4063 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
4064 ++NumZero;
4065 else {
4066 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
4067 NonZeros |= 1 << i;
4068 ++NumNonZero;
4069 }
4070 }
4071
4072 // If we have more than 2 non-zeros, build each half separately.
4073 if (NumNonZero > 2) {
4074 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
4075 ArrayRef<SDUse> Ops = Op->ops();
4076 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
4077 Ops.slice(0, NumOperands / 2));
4078 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
4079 Ops.slice(NumOperands / 2));
4080 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
4081 }
4082
4083 // Otherwise, build it up through insert_subvectors.
4084 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
4085 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
4086 : DAG.getUNDEF(ResVT));
4087
4088 // Replace Undef operands with ZeroVector.
4089 for (SDValue U : Undefs)
4090 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
4091
4092 MVT SubVT = Op.getOperand(0).getSimpleValueType();
4093 unsigned NumSubElems = SubVT.getVectorNumElements();
4094 for (unsigned i = 0; i != NumOperands; ++i) {
4095 if ((NonZeros & (1 << i)) == 0)
4096 continue;
4097
4098 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
4099 DAG.getVectorIdxConstant(i * NumSubElems, DL));
4100 }
4101
4102 return Vec;
4103}
4104
4105SDValue
4106LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
4107 SelectionDAG &DAG) const {
4108 MVT EltVT = Op.getSimpleValueType();
4109 SDValue Vec = Op->getOperand(0);
4110 EVT VecTy = Vec->getValueType(0);
4111 SDValue Idx = Op->getOperand(1);
4112 SDLoc DL(Op);
4113 MVT GRLenVT = Subtarget.getGRLenVT();
4114
4115 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
4116
4117 if (isa<ConstantSDNode>(Idx))
4118 return Op;
4119
4120 switch (VecTy.getSimpleVT().SimpleTy) {
4121 default:
4122 llvm_unreachable("Unexpected type");
4123 case MVT::v32i8:
4124 case MVT::v16i16:
4125 case MVT::v4i64:
4126 case MVT::v4f64: {
4127 // Extract the high half subvector and place it to the low half of a new
4128 // vector. It doesn't matter what the high half of the new vector is.
4129 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
4130 SDValue VecHi =
4131 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
4132 SDValue TmpVec =
4133 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
4134 VecHi, DAG.getConstant(0, DL, GRLenVT));
4135
4136 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
4137 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
4138 // desired element.
4139 SDValue IdxCp =
4140 Subtarget.is64Bit()
4141 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
4142 : DAG.getBitcast(MVT::f32, Idx);
4143 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
4144 SDValue MaskVec =
4145 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
4146 SDValue ResVec =
4147 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
4148
4149 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
4150 DAG.getConstant(0, DL, GRLenVT));
4151 }
4152 case MVT::v8i32:
4153 case MVT::v8f32: {
4154 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
4155 SDValue SplatValue =
4156 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
4157
4158 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
4159 DAG.getConstant(0, DL, GRLenVT));
4160 }
4161 }
4162}
4163
4164SDValue
4165LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
4166 SelectionDAG &DAG) const {
4167 MVT VT = Op.getSimpleValueType();
4168 MVT EltVT = VT.getVectorElementType();
4169 unsigned NumElts = VT.getVectorNumElements();
4170 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
4171 SDLoc DL(Op);
4172 SDValue Op0 = Op.getOperand(0);
4173 SDValue Op1 = Op.getOperand(1);
4174 SDValue Op2 = Op.getOperand(2);
4175
4176 // Lower inserting a loaded integer into lane 0 of an undefined vector as a
4177 // vector load that writes the whole register: FLD.{S/D} for 32/64-bit
4178 // elements and [X]VLDREPL.{B/H} for 8/16-bit ones. Unlike a scalar load +
4179 // [X]VINSGR2VR, it has no false dependency on the previous value of the
4180 // destination and doesn't need to move the value from a GPR.
4181 // For example:
4182 // %a = load i64, ptr %ptr
4183 // %b = insert_vector_elt undef, %a, 0
4184 // is lowered to:
4185 // (FLD_D $a0, 0)
4186 if (Op0.isUndef() && isNullConstant(Op2) && EltVT.isInteger() &&
4187 Op1.getOpcode() == ISD::LOAD && Op1.hasOneUse()) {
4188 auto *LN = cast<LoadSDNode>(Op1);
4189 auto ExtType = LN->getExtensionType();
4190 if (LN->isSimple() &&
4191 (ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
4192 LN->getMemoryVT().getSizeInBits() == EltSizeInBits) {
4193 // Indexed loads and stores are not supported on LoongArch.
4194 assert(LN->isUnindexed() && "Unexpected indexed load.");
4195 SDValue Res;
4196 if (EltSizeInBits >= 32) {
4197 MVT FltVT = MVT::getFloatingPointVT(EltSizeInBits);
4198 // Don't reuse the memory operand, its range metadata (if any) only
4199 // applies to integer loads.
4200 SDValue Ld = DAG.getLoad(
4201 FltVT, DL, LN->getChain(), LN->getBasePtr(), LN->getPointerInfo(),
4202 LN->getAlign(), LN->getMemOperand()->getFlags(), LN->getAAInfo());
4203 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL,
4204 MVT::getVectorVT(FltVT, NumElts), Ld);
4205 Res = DAG.getBitcast(VT, Res);
4206 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), Ld.getValue(1));
4207 } else {
4208 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
4209 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
4210 Res = DAG.getMemIntrinsicNode(LoongArchISD::VLDREPL, DL, Tys, Ops,
4211 LN->getMemoryVT(), LN->getMemOperand());
4212 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), Res.getValue(1));
4213 }
4214 return Res;
4215 }
4216 }
4217
4218 if (isa<ConstantSDNode>(Op2))
4219 return Op;
4220
4221 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4222 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4223
4224 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4225 return SDValue();
4226
4227 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4228 SmallVector<SDValue, 32> RawIndices;
4229 SDValue SplatIdx;
4230 SDValue Indices;
4231
4232 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4233 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4234 for (unsigned i = 0; i < NumElts; ++i) {
4235 RawIndices.push_back(Op2);
4236 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4237 }
4238 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4239 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4240
4241 RawIndices.clear();
4242 for (unsigned i = 0; i < NumElts; ++i) {
4243 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4244 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4245 }
4246 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4247 Indices = DAG.getBitcast(IdxVTy, Indices);
4248 } else {
4249 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4250
4251 for (unsigned i = 0; i < NumElts; ++i)
4252 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4253 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4254 }
4255
4256 // insert vec, elt, idx
4257 // =>
4258 // select (splatidx == {0,1,2...}) ? splatelt : vec
4259 SDValue SelectCC =
4260 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4261 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4262}
4263
4264SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4265 SelectionDAG &DAG) const {
4266 SDLoc DL(Op);
4267 SyncScope::ID FenceSSID =
4268 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4269
4270 // singlethread fences only synchronize with signal handlers on the same
4271 // thread and thus only need to preserve instruction order, not actually
4272 // enforce memory ordering.
4273 if (FenceSSID == SyncScope::SingleThread)
4274 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4275 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4276
4277 return Op;
4278}
4279
4281 MVT GRLenVT, SDValue RMValue) {
4282 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4283 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4284 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4285 //
4286 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4287 // Since the transformation is self-inverse, it applies in both directions:
4288 // LLVM RM <-> LoongArch FCSR RM
4289 //
4290 // Transformation: RM ^ (~(RM >> 1) & 1)
4291 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4292 DAG.getConstant(1, DL, GRLenVT));
4293
4294 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4295 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4296 DAG.getConstant(1, DL, GRLenVT)),
4297 DAG.getConstant(1, DL, GRLenVT));
4298
4299 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4300}
4301
4302SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4303 SelectionDAG &DAG) const {
4304 MVT GRLenVT = Subtarget.getGRLenVT();
4305 SDLoc DL(Op);
4306 SDValue Chain = Op.getOperand(0);
4307 SDValue RMValue = Op.getOperand(1);
4308
4309 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4310 uint64_t RM = CVal->getZExtValue();
4311 if (RM > 3) {
4313 LLVMContext &C = MF.getFunction().getContext();
4314 C.diagnose(DiagnosticInfoUnsupported(
4315 MF.getFunction(),
4316 "rounding mode is not supported by LoongArch hardware",
4317 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4318 return Chain;
4319 }
4320 }
4321
4322 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4323 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4324
4325 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4326 // into position before writing via WRFCSR.
4327 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4328 DAG.getConstant(8, DL, GRLenVT));
4329
4330 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4331 // unrelated fields in FCSR0.
4332 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4333 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4334 FCSRNo, RMValue, Chain);
4335 return SDValue(RN, 0);
4336}
4337
4338SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4339 SelectionDAG &DAG) const {
4340 MVT GRLenVT = Subtarget.getGRLenVT();
4341 SDLoc DL(Op);
4342 SDValue Chain = Op->getOperand(0);
4343
4344 // FCSR3 is an alias of the RM field.
4345 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4346 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4347 MVT::Other, FCSRNo, Chain);
4348 SDValue RMValue = SDValue(FCSR, 0);
4349 Chain = SDValue(FCSR, 1);
4350
4351 // The RM field in FCSR is at bits [9:8].
4352 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4353 DAG.getConstant(8, DL, GRLenVT));
4354 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4355
4356 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4357 return DAG.getMergeValues({RetVal, Chain}, DL);
4358}
4359
4360SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4361 SelectionDAG &DAG) const {
4362
4363 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4364 DAG.getContext()->emitError(
4365 "On LA64, only 64-bit registers can be written.");
4366 return Op.getOperand(0);
4367 }
4368
4369 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4370 DAG.getContext()->emitError(
4371 "On LA32, only 32-bit registers can be written.");
4372 return Op.getOperand(0);
4373 }
4374
4375 return Op;
4376}
4377
4378SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4379 SelectionDAG &DAG) const {
4380 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4381 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4382 "be a constant integer");
4383 return SDValue();
4384 }
4385
4388 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4389 EVT VT = Op.getValueType();
4390 SDLoc DL(Op);
4391 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4392 unsigned Depth = Op.getConstantOperandVal(0);
4393 int GRLenInBytes = Subtarget.getGRLen() / 8;
4394
4395 while (Depth--) {
4396 int Offset = -(GRLenInBytes * 2);
4397 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4398 DAG.getSignedConstant(Offset, DL, VT));
4399 FrameAddr =
4400 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4401 }
4402 return FrameAddr;
4403}
4404
4405SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4406 SelectionDAG &DAG) const {
4407 // Currently only support lowering return address for current frame.
4408 if (Op.getConstantOperandVal(0) != 0) {
4409 DAG.getContext()->emitError(
4410 "return address can only be determined for the current frame");
4411 return SDValue();
4412 }
4413
4416 MVT GRLenVT = Subtarget.getGRLenVT();
4417
4418 // Return the value of the return address register, marking it an implicit
4419 // live-in.
4420 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4421 getRegClassFor(GRLenVT));
4422 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4423}
4424
4425SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4426 SelectionDAG &DAG) const {
4428 auto Size = Subtarget.getGRLen() / 8;
4429 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4430 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4431}
4432
4433SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4434 SelectionDAG &DAG) const {
4436 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4437
4438 SDLoc DL(Op);
4439 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4441
4442 // vastart just stores the address of the VarArgsFrameIndex slot into the
4443 // memory location argument.
4444 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4445 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4446 MachinePointerInfo(SV));
4447}
4448
4449// Lower an unsigned vXi64 -> vXf32 conversion to the same round-to-odd
4450// sequence that the generic legalizer uses for the scalar case:
4451//
4452// Odd = (x >> 1) | (x & 1)
4453// Doubled = (float)(int64_t)Odd + (float)(int64_t)Odd // exact, no rounding
4454// Signed = (float)(int64_t)x // valid for x < 2^63
4455// Result = x < 0 ? Doubled : Signed
4456//
4457// The generic half-word expansion is not usable here: it converts the high and
4458// low 32-bit halves separately and adds them, rounding three times, which is
4459// not enough to emulate the single rounding required by uitofp.
4460SDValue LoongArchTargetLowering::lowerUINT_TO_FPToF32(SDValue Op,
4461 SelectionDAG &DAG) const {
4462 SDLoc DL(Op);
4463 SDValue Src = Op.getOperand(0);
4464 EVT SrcVT = Src.getValueType();
4465 EVT DstVT = Op.getValueType();
4466
4467 SDValue Shift = DAG.getShiftAmountConstant(1, SrcVT, DL);
4468 SDValue Half = DAG.getNode(ISD::SRL, DL, SrcVT, Src, Shift);
4469 SDValue Sticky =
4470 DAG.getNode(ISD::AND, DL, SrcVT, Src, DAG.getConstant(1, DL, SrcVT));
4471 SDValue Odd = DAG.getNode(ISD::OR, DL, SrcVT, Half, Sticky);
4472
4473 // Doubling a value with at most 24 significant bits is exact.
4474 SDValue RoundToOdd = DAG.getNode(ISD::SINT_TO_FP, DL, DstVT, Odd);
4475 SDValue Doubled = DAG.getNode(ISD::FADD, DL, DstVT, RoundToOdd, RoundToOdd);
4476
4477 // Values below 2^63 convert directly; above that the signed conversion is
4478 // negative, so the round-to-odd path is used instead.
4479 SDValue Signed = DAG.getNode(ISD::SINT_TO_FP, DL, DstVT, Src);
4480
4481 // The signed conversion is negative exactly when the source did not fit, so
4482 // its sign bit is the mask: broadcasting it with an arithmetic shift avoids
4483 // a comparison followed by a truncate of the 64-bit result to the width of
4484 // the result vector.
4485 EVT MaskVT = DstVT.changeVectorElementTypeToInteger();
4486 SDValue Mask =
4487 DAG.getNode(ISD::SRA, DL, MaskVT, DAG.getBitcast(MaskVT, Signed),
4488 DAG.getShiftAmountConstant(31, MaskVT, DL));
4489 return DAG.getSelect(DL, DstVT, Mask, Doubled, Signed);
4490}
4491
4492SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4493 SelectionDAG &DAG) const {
4494 SDLoc DL(Op);
4495 SDValue Op0 = Op.getOperand(0);
4496 EVT VT = Op.getValueType();
4497 EVT Op0VT = Op0.getValueType();
4498
4499 if (VT.isVector()) {
4500 if (VT.getScalarSizeInBits() == Op0VT.getScalarSizeInBits())
4501 return Op;
4502
4503 // There is no unsigned 64-bit to 32-bit conversion instruction, so
4504 // synthesize one with a single rounding. A value known to be
4505 // non-negative converts exactly as signed, and that form is native.
4506 if (Subtarget.hasExtLASX() && Op0VT.getScalarType() == MVT::i64 &&
4507 VT.getScalarType() == MVT::f32) {
4508 if (DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg())
4509 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4510 return lowerUINT_TO_FPToF32(Op, DAG);
4511 }
4512
4513 return SDValue();
4514 }
4515
4516 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4519 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4520
4521 // We can't do uint64 -> double -> float because of double-rounding issue.
4522 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4523 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4524 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4525 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4526 DAG.getIntPtrConstant(0, DL));
4527 return Conv;
4528 }
4529
4530 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4531 return SDValue();
4532
4533 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4534 !Subtarget.hasBasicD() && "unexpected target features");
4535
4536 if (Op0->getOpcode() == ISD::AND) {
4537 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4538 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4539 return Op;
4540 }
4541
4542 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4543 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4544 Op0.getConstantOperandVal(2) == UINT64_C(0))
4545 return Op;
4546
4547 if (Op0.getOpcode() == ISD::AssertZext &&
4548 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4549 return Op;
4550
4551 EVT OpVT = Op0.getValueType();
4552 EVT RetVT = Op.getValueType();
4553 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4554 MakeLibCallOptions CallOptions;
4555 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4556 SDValue Chain = SDValue();
4558 std::tie(Result, Chain) =
4559 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4560 return Result;
4561}
4562
4563SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4564 SelectionDAG &DAG) const {
4565 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4566 !Subtarget.hasBasicD() && "unexpected target features");
4567
4568 SDLoc DL(Op);
4569 SDValue Op0 = Op.getOperand(0);
4570
4571 if ((Op0.getOpcode() == ISD::AssertSext ||
4573 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4574 return Op;
4575
4576 EVT OpVT = Op0.getValueType();
4577 EVT RetVT = Op.getValueType();
4578 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4579 MakeLibCallOptions CallOptions;
4580 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4581 SDValue Chain = SDValue();
4583 std::tie(Result, Chain) =
4584 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4585 return Result;
4586}
4587
4588SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4589 SelectionDAG &DAG) const {
4590
4591 SDLoc DL(Op);
4592 EVT VT = Op.getValueType();
4593 SDValue Op0 = Op.getOperand(0);
4594 EVT Op0VT = Op0.getValueType();
4595
4596 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4597 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4598 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4599 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4600 }
4601 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4602 SDValue Lo, Hi;
4603 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4604 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4605 }
4606 return Op;
4607}
4608
4609SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4610 SelectionDAG &DAG) const {
4611
4612 SDLoc DL(Op);
4613 SDValue Op0 = Op.getOperand(0);
4614
4615 if (Op0.getValueType() == MVT::f16)
4616 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4617
4618 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4619 !Subtarget.hasBasicD()) {
4620 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4621 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4622 }
4623
4624 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4625 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4626 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4627}
4628
4629// [X]VFTINTRZ and FTINTRZ saturate out-of-range values and convert NaN to 0,
4630// which is exactly the semantics of FP_TO_SINT_SAT with a native saturation
4631// width.
4632SDValue LoongArchTargetLowering::lowerFP_TO_SINT_SAT(SDValue Op,
4633 SelectionDAG &DAG) const {
4634 SDLoc DL(Op);
4635 SDValue Src = Op.getOperand(0);
4636 EVT VT = Op.getValueType();
4637 EVT SrcVT = Src.getValueType();
4638 unsigned SatWidth = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
4639
4640 // Vectors are selected by patterns.
4641 if (VT.isVector()) {
4642 if (SatWidth == VT.getScalarSizeInBits() &&
4643 SatWidth == SrcVT.getScalarSizeInBits())
4644 return Op;
4645 return SDValue();
4646 }
4647
4648 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4649 return SDValue();
4650
4651 if (SatWidth == 32) {
4652 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Src);
4653 if (Subtarget.is64Bit())
4654 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, VT, Ftint);
4655 return DAG.getBitcast(VT, Ftint);
4656 }
4657
4658 if (SatWidth == 64 && Subtarget.is64Bit() && Subtarget.hasBasicD()) {
4659 SDValue Ftint = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f64, Src);
4660 return DAG.getBitcast(VT, Ftint);
4661 }
4662
4663 return SDValue();
4664}
4665
4666SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4667 SelectionDAG &DAG) const {
4668 if (!Subtarget.hasExtLSX())
4669 return SDValue();
4670
4671 SDLoc DL(Op);
4672 SDValue Src = Op.getOperand(0);
4673 EVT VT = Op.getValueType();
4674 EVT SrcVT = Src.getValueType();
4675
4676 if (VT != MVT::i64)
4677 return SDValue();
4678
4679 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4680 return SDValue();
4681
4682 if (SrcVT == MVT::f32)
4683 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4684 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4685 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4686 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4687 DAG.getIntPtrConstant(0, DL));
4688}
4689
4691 SelectionDAG &DAG, unsigned Flags) {
4692 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4693}
4694
4696 SelectionDAG &DAG, unsigned Flags) {
4697 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4698 Flags);
4699}
4700
4702 SelectionDAG &DAG, unsigned Flags) {
4703 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4704 N->getOffset(), Flags);
4705}
4706
4708 SelectionDAG &DAG, unsigned Flags) {
4709 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4710}
4711
4712template <class NodeTy>
4713SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4715 bool IsLocal) const {
4716 SDLoc DL(N);
4717 EVT Ty = getPointerTy(DAG.getDataLayout());
4718 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4719 SDValue Load;
4720
4721 switch (M) {
4722 default:
4723 report_fatal_error("Unsupported code model");
4724
4725 case CodeModel::Large: {
4726 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4727
4728 // This is not actually used, but is necessary for successfully matching
4729 // the PseudoLA_*_LARGE nodes.
4730 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4731 if (IsLocal) {
4732 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4733 // eventually becomes the desired 5-insn code sequence.
4734 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4735 Tmp, Addr),
4736 0);
4737 } else {
4738 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4739 // eventually becomes the desired 5-insn code sequence.
4740 Load = SDValue(
4741 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4742 0);
4743 }
4744 break;
4745 }
4746
4747 case CodeModel::Small:
4748 case CodeModel::Medium:
4749 if (IsLocal) {
4750 // This generates the pattern (PseudoLA_PCREL sym), which
4751 //
4752 // for la32r expands to:
4753 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4754 //
4755 // for la32s and la64 expands to:
4756 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4757 Load = SDValue(
4758 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4759 } else {
4760 // This generates the pattern (PseudoLA_GOT sym), which
4761 //
4762 // for la32r expands to:
4763 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4764 //
4765 // for la32s and la64 expands to:
4766 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4767 Load =
4768 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4769 }
4770 }
4771
4772 if (!IsLocal) {
4773 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4775 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4779 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4780 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4781 }
4782
4783 return Load;
4784}
4785
4786SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4787 SelectionDAG &DAG) const {
4788 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4789 DAG.getTarget().getCodeModel());
4790}
4791
4792SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4793 SelectionDAG &DAG) const {
4794 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4795 DAG.getTarget().getCodeModel());
4796}
4797
4798SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4799 SelectionDAG &DAG) const {
4800 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4801 DAG.getTarget().getCodeModel());
4802}
4803
4804SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4805 SelectionDAG &DAG) const {
4806 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4807 assert(N->getOffset() == 0 && "unexpected offset in global node");
4808 auto CM = DAG.getTarget().getCodeModel();
4809 const GlobalValue *GV = N->getGlobal();
4810
4811 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4812 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4813 CM = *GCM;
4814 }
4815
4816 return getAddr(N, DAG, CM, GV->isDSOLocal());
4817}
4818
4819SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4820 SelectionDAG &DAG,
4821 unsigned Opc, bool UseGOT,
4822 bool Large) const {
4823 SDLoc DL(N);
4824 EVT Ty = getPointerTy(DAG.getDataLayout());
4825 MVT GRLenVT = Subtarget.getGRLenVT();
4826
4827 // This is not actually used, but is necessary for successfully matching the
4828 // PseudoLA_*_LARGE nodes.
4829 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4830 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4831
4832 // Only IE needs an extra argument for large code model.
4833 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4834 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4835 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4836
4837 // If it is LE for normal/medium code model, the add tp operation will occur
4838 // during the pseudo-instruction expansion.
4839 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4840 return Offset;
4841
4842 if (UseGOT) {
4843 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4845 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4849 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4850 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4851 }
4852
4853 // Add the thread pointer.
4854 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4855 DAG.getRegister(LoongArch::R2, GRLenVT));
4856}
4857
4858SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4859 SelectionDAG &DAG,
4860 unsigned Opc,
4861 bool Large) const {
4862 SDLoc DL(N);
4863 EVT Ty = getPointerTy(DAG.getDataLayout());
4864 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4865
4866 // This is not actually used, but is necessary for successfully matching the
4867 // PseudoLA_*_LARGE nodes.
4868 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4869
4870 // Use a PC-relative addressing mode to access the dynamic GOT address.
4871 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4872 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4873 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4874
4875 // Prepare argument list to generate call.
4877 Args.emplace_back(Load, CallTy);
4878
4879 // Setup call to __tls_get_addr.
4880 TargetLowering::CallLoweringInfo CLI(DAG);
4881 CLI.setDebugLoc(DL)
4882 .setChain(DAG.getEntryNode())
4883 .setLibCallee(CallingConv::C, CallTy,
4884 DAG.getExternalSymbol("__tls_get_addr", Ty),
4885 std::move(Args));
4886
4887 return LowerCallTo(CLI).first;
4888}
4889
4890SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4891 SelectionDAG &DAG, unsigned Opc,
4892 bool Large) const {
4893 SDLoc DL(N);
4894 EVT Ty = getPointerTy(DAG.getDataLayout());
4895 const GlobalValue *GV = N->getGlobal();
4896
4897 // This is not actually used, but is necessary for successfully matching the
4898 // PseudoLA_*_LARGE nodes.
4899 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4900
4901 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4902 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4903 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4904 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4905 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4906}
4907
4908SDValue
4909LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4910 SelectionDAG &DAG) const {
4913 report_fatal_error("In GHC calling convention TLS is not supported");
4914
4915 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4916 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4917
4918 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4919 assert(N->getOffset() == 0 && "unexpected offset in global node");
4920
4921 if (DAG.getTarget().useEmulatedTLS())
4922 reportFatalUsageError("the emulated TLS is prohibited");
4923
4924 bool IsDesc = DAG.getTarget().useTLSDESC();
4925
4926 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4928 // In this model, application code calls the dynamic linker function
4929 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4930 // runtime.
4931 if (!IsDesc)
4932 return getDynamicTLSAddr(N, DAG,
4933 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4934 : LoongArch::PseudoLA_TLS_GD,
4935 Large);
4936 break;
4938 // Same as GeneralDynamic, except for assembly modifiers and relocation
4939 // records.
4940 if (!IsDesc)
4941 return getDynamicTLSAddr(N, DAG,
4942 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4943 : LoongArch::PseudoLA_TLS_LD,
4944 Large);
4945 break;
4947 // This model uses the GOT to resolve TLS offsets.
4948 return getStaticTLSAddr(N, DAG,
4949 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4950 : LoongArch::PseudoLA_TLS_IE,
4951 /*UseGOT=*/true, Large);
4953 // This model is used when static linking as the TLS offsets are resolved
4954 // during program linking.
4955 //
4956 // This node doesn't need an extra argument for the large code model.
4957 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4958 /*UseGOT=*/false, Large);
4959 }
4960
4961 return getTLSDescAddr(N, DAG,
4962 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4963 : LoongArch::PseudoLA_TLS_DESC,
4964 Large);
4965}
4966
4967template <unsigned N>
4969 SelectionDAG &DAG, bool IsSigned = false) {
4970 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4971 // Check the ImmArg.
4972 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4973 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4974 DAG.getContext()->emitError(Op->getOperationName(0) +
4975 ": argument out of range.");
4976 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4977 }
4978 return SDValue();
4979}
4980
4981SDValue
4982LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4983 SelectionDAG &DAG) const {
4984 switch (Op.getConstantOperandVal(0)) {
4985 default:
4986 return SDValue(); // Don't custom lower most intrinsics.
4987 case Intrinsic::thread_pointer: {
4988 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4989 return DAG.getRegister(LoongArch::R2, PtrVT);
4990 }
4991 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4992 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4993 case Intrinsic::loongarch_lsx_vreplvei_d:
4994 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4995 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4996 case Intrinsic::loongarch_lsx_vreplvei_w:
4997 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4998 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4999 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
5000 case Intrinsic::loongarch_lasx_xvpickve_d:
5001 case Intrinsic::loongarch_lasx_xvpickve_d_f:
5002 return checkIntrinsicImmArg<2>(Op, 2, DAG);
5003 case Intrinsic::loongarch_lasx_xvinsve0_d:
5004 return checkIntrinsicImmArg<2>(Op, 3, DAG);
5005 case Intrinsic::loongarch_lsx_vsat_b:
5006 case Intrinsic::loongarch_lsx_vsat_bu:
5007 case Intrinsic::loongarch_lsx_vrotri_b:
5008 case Intrinsic::loongarch_lsx_vsllwil_h_b:
5009 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
5010 case Intrinsic::loongarch_lsx_vsrlri_b:
5011 case Intrinsic::loongarch_lsx_vsrari_b:
5012 case Intrinsic::loongarch_lsx_vreplvei_h:
5013 case Intrinsic::loongarch_lasx_xvsat_b:
5014 case Intrinsic::loongarch_lasx_xvsat_bu:
5015 case Intrinsic::loongarch_lasx_xvrotri_b:
5016 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
5017 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
5018 case Intrinsic::loongarch_lasx_xvsrlri_b:
5019 case Intrinsic::loongarch_lasx_xvsrari_b:
5020 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
5021 case Intrinsic::loongarch_lasx_xvpickve_w:
5022 case Intrinsic::loongarch_lasx_xvpickve_w_f:
5023 return checkIntrinsicImmArg<3>(Op, 2, DAG);
5024 case Intrinsic::loongarch_lasx_xvinsve0_w:
5025 return checkIntrinsicImmArg<3>(Op, 3, DAG);
5026 case Intrinsic::loongarch_lsx_vsat_h:
5027 case Intrinsic::loongarch_lsx_vsat_hu:
5028 case Intrinsic::loongarch_lsx_vrotri_h:
5029 case Intrinsic::loongarch_lsx_vsllwil_w_h:
5030 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
5031 case Intrinsic::loongarch_lsx_vsrlri_h:
5032 case Intrinsic::loongarch_lsx_vsrari_h:
5033 case Intrinsic::loongarch_lsx_vreplvei_b:
5034 case Intrinsic::loongarch_lasx_xvsat_h:
5035 case Intrinsic::loongarch_lasx_xvsat_hu:
5036 case Intrinsic::loongarch_lasx_xvrotri_h:
5037 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
5038 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
5039 case Intrinsic::loongarch_lasx_xvsrlri_h:
5040 case Intrinsic::loongarch_lasx_xvsrari_h:
5041 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
5042 return checkIntrinsicImmArg<4>(Op, 2, DAG);
5043 case Intrinsic::loongarch_lsx_vsrlni_b_h:
5044 case Intrinsic::loongarch_lsx_vsrani_b_h:
5045 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
5046 case Intrinsic::loongarch_lsx_vsrarni_b_h:
5047 case Intrinsic::loongarch_lsx_vssrlni_b_h:
5048 case Intrinsic::loongarch_lsx_vssrani_b_h:
5049 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
5050 case Intrinsic::loongarch_lsx_vssrani_bu_h:
5051 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
5052 case Intrinsic::loongarch_lsx_vssrarni_b_h:
5053 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
5054 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
5055 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
5056 case Intrinsic::loongarch_lasx_xvsrani_b_h:
5057 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
5058 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
5059 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
5060 case Intrinsic::loongarch_lasx_xvssrani_b_h:
5061 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
5062 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
5063 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
5064 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
5065 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
5066 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
5067 return checkIntrinsicImmArg<4>(Op, 3, DAG);
5068 case Intrinsic::loongarch_lsx_vsat_w:
5069 case Intrinsic::loongarch_lsx_vsat_wu:
5070 case Intrinsic::loongarch_lsx_vrotri_w:
5071 case Intrinsic::loongarch_lsx_vsllwil_d_w:
5072 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
5073 case Intrinsic::loongarch_lsx_vsrlri_w:
5074 case Intrinsic::loongarch_lsx_vsrari_w:
5075 case Intrinsic::loongarch_lsx_vslei_bu:
5076 case Intrinsic::loongarch_lsx_vslei_hu:
5077 case Intrinsic::loongarch_lsx_vslei_wu:
5078 case Intrinsic::loongarch_lsx_vslei_du:
5079 case Intrinsic::loongarch_lsx_vslti_bu:
5080 case Intrinsic::loongarch_lsx_vslti_hu:
5081 case Intrinsic::loongarch_lsx_vslti_wu:
5082 case Intrinsic::loongarch_lsx_vslti_du:
5083 case Intrinsic::loongarch_lsx_vbsll_v:
5084 case Intrinsic::loongarch_lsx_vbsrl_v:
5085 case Intrinsic::loongarch_lasx_xvsat_w:
5086 case Intrinsic::loongarch_lasx_xvsat_wu:
5087 case Intrinsic::loongarch_lasx_xvrotri_w:
5088 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
5089 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
5090 case Intrinsic::loongarch_lasx_xvsrlri_w:
5091 case Intrinsic::loongarch_lasx_xvsrari_w:
5092 case Intrinsic::loongarch_lasx_xvslei_bu:
5093 case Intrinsic::loongarch_lasx_xvslei_hu:
5094 case Intrinsic::loongarch_lasx_xvslei_wu:
5095 case Intrinsic::loongarch_lasx_xvslei_du:
5096 case Intrinsic::loongarch_lasx_xvslti_bu:
5097 case Intrinsic::loongarch_lasx_xvslti_hu:
5098 case Intrinsic::loongarch_lasx_xvslti_wu:
5099 case Intrinsic::loongarch_lasx_xvslti_du:
5100 case Intrinsic::loongarch_lasx_xvbsll_v:
5101 case Intrinsic::loongarch_lasx_xvbsrl_v:
5102 return checkIntrinsicImmArg<5>(Op, 2, DAG);
5103 case Intrinsic::loongarch_lsx_vseqi_b:
5104 case Intrinsic::loongarch_lsx_vseqi_h:
5105 case Intrinsic::loongarch_lsx_vseqi_w:
5106 case Intrinsic::loongarch_lsx_vseqi_d:
5107 case Intrinsic::loongarch_lsx_vslei_b:
5108 case Intrinsic::loongarch_lsx_vslei_h:
5109 case Intrinsic::loongarch_lsx_vslei_w:
5110 case Intrinsic::loongarch_lsx_vslei_d:
5111 case Intrinsic::loongarch_lsx_vslti_b:
5112 case Intrinsic::loongarch_lsx_vslti_h:
5113 case Intrinsic::loongarch_lsx_vslti_w:
5114 case Intrinsic::loongarch_lsx_vslti_d:
5115 case Intrinsic::loongarch_lasx_xvseqi_b:
5116 case Intrinsic::loongarch_lasx_xvseqi_h:
5117 case Intrinsic::loongarch_lasx_xvseqi_w:
5118 case Intrinsic::loongarch_lasx_xvseqi_d:
5119 case Intrinsic::loongarch_lasx_xvslei_b:
5120 case Intrinsic::loongarch_lasx_xvslei_h:
5121 case Intrinsic::loongarch_lasx_xvslei_w:
5122 case Intrinsic::loongarch_lasx_xvslei_d:
5123 case Intrinsic::loongarch_lasx_xvslti_b:
5124 case Intrinsic::loongarch_lasx_xvslti_h:
5125 case Intrinsic::loongarch_lasx_xvslti_w:
5126 case Intrinsic::loongarch_lasx_xvslti_d:
5127 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
5128 case Intrinsic::loongarch_lsx_vsrlni_h_w:
5129 case Intrinsic::loongarch_lsx_vsrani_h_w:
5130 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
5131 case Intrinsic::loongarch_lsx_vsrarni_h_w:
5132 case Intrinsic::loongarch_lsx_vssrlni_h_w:
5133 case Intrinsic::loongarch_lsx_vssrani_h_w:
5134 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
5135 case Intrinsic::loongarch_lsx_vssrani_hu_w:
5136 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
5137 case Intrinsic::loongarch_lsx_vssrarni_h_w:
5138 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
5139 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
5140 case Intrinsic::loongarch_lsx_vfrstpi_b:
5141 case Intrinsic::loongarch_lsx_vfrstpi_h:
5142 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
5143 case Intrinsic::loongarch_lasx_xvsrani_h_w:
5144 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
5145 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
5146 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
5147 case Intrinsic::loongarch_lasx_xvssrani_h_w:
5148 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
5149 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
5150 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
5151 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
5152 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
5153 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
5154 case Intrinsic::loongarch_lasx_xvfrstpi_b:
5155 case Intrinsic::loongarch_lasx_xvfrstpi_h:
5156 return checkIntrinsicImmArg<5>(Op, 3, DAG);
5157 case Intrinsic::loongarch_lsx_vsat_d:
5158 case Intrinsic::loongarch_lsx_vsat_du:
5159 case Intrinsic::loongarch_lsx_vrotri_d:
5160 case Intrinsic::loongarch_lsx_vsrlri_d:
5161 case Intrinsic::loongarch_lsx_vsrari_d:
5162 case Intrinsic::loongarch_lasx_xvsat_d:
5163 case Intrinsic::loongarch_lasx_xvsat_du:
5164 case Intrinsic::loongarch_lasx_xvrotri_d:
5165 case Intrinsic::loongarch_lasx_xvsrlri_d:
5166 case Intrinsic::loongarch_lasx_xvsrari_d:
5167 return checkIntrinsicImmArg<6>(Op, 2, DAG);
5168 case Intrinsic::loongarch_lsx_vsrlni_w_d:
5169 case Intrinsic::loongarch_lsx_vsrani_w_d:
5170 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
5171 case Intrinsic::loongarch_lsx_vsrarni_w_d:
5172 case Intrinsic::loongarch_lsx_vssrlni_w_d:
5173 case Intrinsic::loongarch_lsx_vssrani_w_d:
5174 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
5175 case Intrinsic::loongarch_lsx_vssrani_wu_d:
5176 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
5177 case Intrinsic::loongarch_lsx_vssrarni_w_d:
5178 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
5179 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
5180 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
5181 case Intrinsic::loongarch_lasx_xvsrani_w_d:
5182 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
5183 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
5184 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
5185 case Intrinsic::loongarch_lasx_xvssrani_w_d:
5186 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
5187 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
5188 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
5189 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
5190 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
5191 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
5192 return checkIntrinsicImmArg<6>(Op, 3, DAG);
5193 case Intrinsic::loongarch_lsx_vsrlni_d_q:
5194 case Intrinsic::loongarch_lsx_vsrani_d_q:
5195 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
5196 case Intrinsic::loongarch_lsx_vsrarni_d_q:
5197 case Intrinsic::loongarch_lsx_vssrlni_d_q:
5198 case Intrinsic::loongarch_lsx_vssrani_d_q:
5199 case Intrinsic::loongarch_lsx_vssrlni_du_q:
5200 case Intrinsic::loongarch_lsx_vssrani_du_q:
5201 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
5202 case Intrinsic::loongarch_lsx_vssrarni_d_q:
5203 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
5204 case Intrinsic::loongarch_lsx_vssrarni_du_q:
5205 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
5206 case Intrinsic::loongarch_lasx_xvsrani_d_q:
5207 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
5208 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
5209 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
5210 case Intrinsic::loongarch_lasx_xvssrani_d_q:
5211 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
5212 case Intrinsic::loongarch_lasx_xvssrani_du_q:
5213 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
5214 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
5215 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
5216 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
5217 return checkIntrinsicImmArg<7>(Op, 3, DAG);
5218 case Intrinsic::loongarch_lsx_vnori_b:
5219 case Intrinsic::loongarch_lsx_vshuf4i_b:
5220 case Intrinsic::loongarch_lsx_vshuf4i_h:
5221 case Intrinsic::loongarch_lsx_vshuf4i_w:
5222 case Intrinsic::loongarch_lasx_xvnori_b:
5223 case Intrinsic::loongarch_lasx_xvshuf4i_b:
5224 case Intrinsic::loongarch_lasx_xvshuf4i_h:
5225 case Intrinsic::loongarch_lasx_xvshuf4i_w:
5226 case Intrinsic::loongarch_lasx_xvpermi_d:
5227 return checkIntrinsicImmArg<8>(Op, 2, DAG);
5228 case Intrinsic::loongarch_lsx_vshuf4i_d:
5229 case Intrinsic::loongarch_lsx_vpermi_w:
5230 case Intrinsic::loongarch_lsx_vbitseli_b:
5231 case Intrinsic::loongarch_lsx_vextrins_b:
5232 case Intrinsic::loongarch_lsx_vextrins_h:
5233 case Intrinsic::loongarch_lsx_vextrins_w:
5234 case Intrinsic::loongarch_lsx_vextrins_d:
5235 case Intrinsic::loongarch_lasx_xvshuf4i_d:
5236 case Intrinsic::loongarch_lasx_xvpermi_w:
5237 case Intrinsic::loongarch_lasx_xvpermi_q:
5238 case Intrinsic::loongarch_lasx_xvbitseli_b:
5239 case Intrinsic::loongarch_lasx_xvextrins_b:
5240 case Intrinsic::loongarch_lasx_xvextrins_h:
5241 case Intrinsic::loongarch_lasx_xvextrins_w:
5242 case Intrinsic::loongarch_lasx_xvextrins_d:
5243 return checkIntrinsicImmArg<8>(Op, 3, DAG);
5244 case Intrinsic::loongarch_lsx_vrepli_b:
5245 case Intrinsic::loongarch_lsx_vrepli_h:
5246 case Intrinsic::loongarch_lsx_vrepli_w:
5247 case Intrinsic::loongarch_lsx_vrepli_d:
5248 case Intrinsic::loongarch_lasx_xvrepli_b:
5249 case Intrinsic::loongarch_lasx_xvrepli_h:
5250 case Intrinsic::loongarch_lasx_xvrepli_w:
5251 case Intrinsic::loongarch_lasx_xvrepli_d:
5252 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
5253 case Intrinsic::loongarch_lsx_vldi:
5254 case Intrinsic::loongarch_lasx_xvldi:
5255 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
5256 }
5257}
5258
5259// Helper function that emits error message for intrinsics with chain and return
5260// merge values of a UNDEF and the chain.
5262 StringRef ErrorMsg,
5263 SelectionDAG &DAG) {
5264 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5265 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
5266 SDLoc(Op));
5267}
5268
5269SDValue
5270LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
5271 SelectionDAG &DAG) const {
5272 SDLoc DL(Op);
5273 MVT GRLenVT = Subtarget.getGRLenVT();
5274 EVT VT = Op.getValueType();
5275 SDValue Chain = Op.getOperand(0);
5276 const StringRef ErrorMsgOOR = "argument out of range";
5277 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5278 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5279
5280 switch (Op.getConstantOperandVal(1)) {
5281 default:
5282 return Op;
5283 case Intrinsic::loongarch_crc_w_b_w:
5284 case Intrinsic::loongarch_crc_w_h_w:
5285 case Intrinsic::loongarch_crc_w_w_w:
5286 case Intrinsic::loongarch_crc_w_d_w:
5287 case Intrinsic::loongarch_crcc_w_b_w:
5288 case Intrinsic::loongarch_crcc_w_h_w:
5289 case Intrinsic::loongarch_crcc_w_w_w:
5290 case Intrinsic::loongarch_crcc_w_d_w:
5291 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
5292 case Intrinsic::loongarch_csrrd_w:
5293 case Intrinsic::loongarch_csrrd_d: {
5294 unsigned Imm = Op.getConstantOperandVal(2);
5295 return !isUInt<14>(Imm)
5296 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5297 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5298 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5299 }
5300 case Intrinsic::loongarch_csrwr_w:
5301 case Intrinsic::loongarch_csrwr_d: {
5302 unsigned Imm = Op.getConstantOperandVal(3);
5303 return !isUInt<14>(Imm)
5304 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5305 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5306 {Chain, Op.getOperand(2),
5307 DAG.getConstant(Imm, DL, GRLenVT)});
5308 }
5309 case Intrinsic::loongarch_csrxchg_w:
5310 case Intrinsic::loongarch_csrxchg_d: {
5311 unsigned Imm = Op.getConstantOperandVal(4);
5312 return !isUInt<14>(Imm)
5313 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5314 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5315 {Chain, Op.getOperand(2), Op.getOperand(3),
5316 DAG.getConstant(Imm, DL, GRLenVT)});
5317 }
5318 case Intrinsic::loongarch_iocsrrd_d: {
5319 return DAG.getNode(
5320 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5321 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5322 }
5323#define IOCSRRD_CASE(NAME, NODE) \
5324 case Intrinsic::loongarch_##NAME: { \
5325 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5326 {Chain, Op.getOperand(2)}); \
5327 }
5328 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5329 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5330 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5331#undef IOCSRRD_CASE
5332 case Intrinsic::loongarch_cpucfg: {
5333 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5334 {Chain, Op.getOperand(2)});
5335 }
5336 case Intrinsic::loongarch_lddir_d: {
5337 unsigned Imm = Op.getConstantOperandVal(3);
5338 return !isUInt<8>(Imm)
5339 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5340 : Op;
5341 }
5342 case Intrinsic::loongarch_movfcsr2gr: {
5343 if (!Subtarget.hasBasicF())
5344 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5345 unsigned Imm = Op.getConstantOperandVal(2);
5346 return !isUInt<2>(Imm)
5347 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5348 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5349 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5350 }
5351 case Intrinsic::loongarch_lsx_vld:
5352 case Intrinsic::loongarch_lsx_vldrepl_b:
5353 case Intrinsic::loongarch_lasx_xvld:
5354 case Intrinsic::loongarch_lasx_xvldrepl_b:
5355 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5356 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5357 : SDValue();
5358 case Intrinsic::loongarch_lsx_vldrepl_h:
5359 case Intrinsic::loongarch_lasx_xvldrepl_h:
5360 return !isShiftedInt<11, 1>(
5361 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5363 Op, "argument out of range or not a multiple of 2", DAG)
5364 : SDValue();
5365 case Intrinsic::loongarch_lsx_vldrepl_w:
5366 case Intrinsic::loongarch_lasx_xvldrepl_w:
5367 return !isShiftedInt<10, 2>(
5368 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5370 Op, "argument out of range or not a multiple of 4", DAG)
5371 : SDValue();
5372 case Intrinsic::loongarch_lsx_vldrepl_d:
5373 case Intrinsic::loongarch_lasx_xvldrepl_d:
5374 return !isShiftedInt<9, 3>(
5375 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5377 Op, "argument out of range or not a multiple of 8", DAG)
5378 : SDValue();
5379 }
5380}
5381
5382// Helper function that emits error message for intrinsics with void return
5383// value and return the chain.
5385 SelectionDAG &DAG) {
5386
5387 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5388 return Op.getOperand(0);
5389}
5390
5391SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5392 SelectionDAG &DAG) const {
5393 SDLoc DL(Op);
5394 MVT GRLenVT = Subtarget.getGRLenVT();
5395 SDValue Chain = Op.getOperand(0);
5396 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5397 SDValue Op2 = Op.getOperand(2);
5398 const StringRef ErrorMsgOOR = "argument out of range";
5399 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5400 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5401 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5402
5403 switch (IntrinsicEnum) {
5404 default:
5405 // TODO: Add more Intrinsics.
5406 return SDValue();
5407 case Intrinsic::loongarch_cacop_d:
5408 case Intrinsic::loongarch_cacop_w: {
5409 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5410 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5411 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5412 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5413 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5414 unsigned Imm1 = Op2->getAsZExtVal();
5415 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5416 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5417 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5418 return Op;
5419 }
5420 case Intrinsic::loongarch_dbar: {
5421 unsigned Imm = Op2->getAsZExtVal();
5422 return !isUInt<15>(Imm)
5423 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5424 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5425 DAG.getConstant(Imm, DL, GRLenVT));
5426 }
5427 case Intrinsic::loongarch_ibar: {
5428 unsigned Imm = Op2->getAsZExtVal();
5429 return !isUInt<15>(Imm)
5430 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5431 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5432 DAG.getConstant(Imm, DL, GRLenVT));
5433 }
5434 case Intrinsic::loongarch_break: {
5435 unsigned Imm = Op2->getAsZExtVal();
5436 return !isUInt<15>(Imm)
5437 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5438 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5439 DAG.getConstant(Imm, DL, GRLenVT));
5440 }
5441 case Intrinsic::loongarch_movgr2fcsr: {
5442 if (!Subtarget.hasBasicF())
5443 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5444 unsigned Imm = Op2->getAsZExtVal();
5445 return !isUInt<2>(Imm)
5446 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5447 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5448 DAG.getConstant(Imm, DL, GRLenVT),
5449 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5450 Op.getOperand(3)));
5451 }
5452 case Intrinsic::loongarch_syscall: {
5453 unsigned Imm = Op2->getAsZExtVal();
5454 return !isUInt<15>(Imm)
5455 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5456 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5457 DAG.getConstant(Imm, DL, GRLenVT));
5458 }
5459#define IOCSRWR_CASE(NAME, NODE) \
5460 case Intrinsic::loongarch_##NAME: { \
5461 SDValue Op3 = Op.getOperand(3); \
5462 return Subtarget.is64Bit() \
5463 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5464 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5465 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5466 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5467 Op3); \
5468 }
5469 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5470 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5471 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5472#undef IOCSRWR_CASE
5473 case Intrinsic::loongarch_iocsrwr_d: {
5474 return !Subtarget.is64Bit()
5475 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5476 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5477 Op2,
5478 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5479 Op.getOperand(3)));
5480 }
5481#define ASRT_LE_GT_CASE(NAME) \
5482 case Intrinsic::loongarch_##NAME: { \
5483 return !Subtarget.is64Bit() \
5484 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5485 : Op; \
5486 }
5487 ASRT_LE_GT_CASE(asrtle_d)
5488 ASRT_LE_GT_CASE(asrtgt_d)
5489#undef ASRT_LE_GT_CASE
5490 case Intrinsic::loongarch_ldpte_d: {
5491 unsigned Imm = Op.getConstantOperandVal(3);
5492 return !Subtarget.is64Bit()
5493 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5494 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5495 : Op;
5496 }
5497 case Intrinsic::loongarch_lsx_vst:
5498 case Intrinsic::loongarch_lasx_xvst:
5499 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5500 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5501 : SDValue();
5502 case Intrinsic::loongarch_lasx_xvstelm_b:
5503 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5504 !isUInt<5>(Op.getConstantOperandVal(5)))
5505 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5506 : SDValue();
5507 case Intrinsic::loongarch_lsx_vstelm_b:
5508 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5509 !isUInt<4>(Op.getConstantOperandVal(5)))
5510 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5511 : SDValue();
5512 case Intrinsic::loongarch_lasx_xvstelm_h:
5513 return (!isShiftedInt<8, 1>(
5514 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5515 !isUInt<4>(Op.getConstantOperandVal(5)))
5517 Op, "argument out of range or not a multiple of 2", DAG)
5518 : SDValue();
5519 case Intrinsic::loongarch_lsx_vstelm_h:
5520 return (!isShiftedInt<8, 1>(
5521 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5522 !isUInt<3>(Op.getConstantOperandVal(5)))
5524 Op, "argument out of range or not a multiple of 2", DAG)
5525 : SDValue();
5526 case Intrinsic::loongarch_lasx_xvstelm_w:
5527 return (!isShiftedInt<8, 2>(
5528 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5529 !isUInt<3>(Op.getConstantOperandVal(5)))
5531 Op, "argument out of range or not a multiple of 4", DAG)
5532 : SDValue();
5533 case Intrinsic::loongarch_lsx_vstelm_w:
5534 return (!isShiftedInt<8, 2>(
5535 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5536 !isUInt<2>(Op.getConstantOperandVal(5)))
5538 Op, "argument out of range or not a multiple of 4", DAG)
5539 : SDValue();
5540 case Intrinsic::loongarch_lasx_xvstelm_d:
5541 return (!isShiftedInt<8, 3>(
5542 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5543 !isUInt<2>(Op.getConstantOperandVal(5)))
5545 Op, "argument out of range or not a multiple of 8", DAG)
5546 : SDValue();
5547 case Intrinsic::loongarch_lsx_vstelm_d:
5548 return (!isShiftedInt<8, 3>(
5549 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5550 !isUInt<1>(Op.getConstantOperandVal(5)))
5552 Op, "argument out of range or not a multiple of 8", DAG)
5553 : SDValue();
5554 }
5555}
5556
5557SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5558 SelectionDAG &DAG) const {
5559 SDLoc DL(Op);
5560 SDValue Lo = Op.getOperand(0);
5561 SDValue Hi = Op.getOperand(1);
5562 SDValue Shamt = Op.getOperand(2);
5563 EVT VT = Lo.getValueType();
5564
5565 // if Shamt-GRLen < 0: // Shamt < GRLen
5566 // Lo = Lo << Shamt
5567 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5568 // else:
5569 // Lo = 0
5570 // Hi = Lo << (Shamt-GRLen)
5571
5572 SDValue Zero = DAG.getConstant(0, DL, VT);
5573 SDValue One = DAG.getConstant(1, DL, VT);
5574 SDValue MinusGRLen =
5575 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5576 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5577 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5578 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5579
5580 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5581 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5582 SDValue ShiftRightLo =
5583 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5584 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5585 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5586 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5587
5588 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5589
5590 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5591 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5592
5593 SDValue Parts[2] = {Lo, Hi};
5594 return DAG.getMergeValues(Parts, DL);
5595}
5596
5597SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5598 SelectionDAG &DAG,
5599 bool IsSRA) const {
5600 SDLoc DL(Op);
5601 SDValue Lo = Op.getOperand(0);
5602 SDValue Hi = Op.getOperand(1);
5603 SDValue Shamt = Op.getOperand(2);
5604 EVT VT = Lo.getValueType();
5605
5606 // SRA expansion:
5607 // if Shamt-GRLen < 0: // Shamt < GRLen
5608 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5609 // Hi = Hi >>s Shamt
5610 // else:
5611 // Lo = Hi >>s (Shamt-GRLen);
5612 // Hi = Hi >>s (GRLen-1)
5613 //
5614 // SRL expansion:
5615 // if Shamt-GRLen < 0: // Shamt < GRLen
5616 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5617 // Hi = Hi >>u Shamt
5618 // else:
5619 // Lo = Hi >>u (Shamt-GRLen);
5620 // Hi = 0;
5621
5622 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5623
5624 SDValue Zero = DAG.getConstant(0, DL, VT);
5625 SDValue One = DAG.getConstant(1, DL, VT);
5626 SDValue MinusGRLen =
5627 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5628 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5629 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5630 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5631
5632 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5633 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5634 SDValue ShiftLeftHi =
5635 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5636 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5637 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5638 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5639 SDValue HiFalse =
5640 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5641
5642 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5643
5644 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5645 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5646
5647 SDValue Parts[2] = {Lo, Hi};
5648 return DAG.getMergeValues(Parts, DL);
5649}
5650
5651// Returns the opcode of the target-specific SDNode that implements the 32-bit
5652// form of the given Opcode.
5653static unsigned getLoongArchWOpcode(unsigned Opcode) {
5654 switch (Opcode) {
5655 default:
5656 llvm_unreachable("Unexpected opcode");
5657 case ISD::SDIV:
5658 return LoongArchISD::DIV_W;
5659 case ISD::UDIV:
5660 return LoongArchISD::DIV_WU;
5661 case ISD::SREM:
5662 return LoongArchISD::MOD_W;
5663 case ISD::UREM:
5664 return LoongArchISD::MOD_WU;
5665 case ISD::SHL:
5666 return LoongArchISD::SLL_W;
5667 case ISD::SRA:
5668 return LoongArchISD::SRA_W;
5669 case ISD::SRL:
5670 return LoongArchISD::SRL_W;
5671 case ISD::ROTL:
5672 case ISD::ROTR:
5673 return LoongArchISD::ROTR_W;
5674 case ISD::CTTZ:
5675 return LoongArchISD::CTZ_W;
5676 case ISD::CTLZ:
5677 return LoongArchISD::CLZ_W;
5678 }
5679}
5680
5681// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5682// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5683// otherwise be promoted to i64, making it difficult to select the
5684// SLL_W/.../*W later one because the fact the operation was originally of
5685// type i8/i16/i32 is lost.
5687 unsigned ExtOpc = ISD::ANY_EXTEND) {
5688 SDLoc DL(N);
5689 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5690 SDValue NewOp0, NewRes;
5691
5692 switch (NumOp) {
5693 default:
5694 llvm_unreachable("Unexpected NumOp");
5695 case 1: {
5696 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5697 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5698 break;
5699 }
5700 case 2: {
5701 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5702 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5703 if (N->getOpcode() == ISD::ROTL) {
5704 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5705 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5706 }
5707 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5708 break;
5709 }
5710 // TODO:Handle more NumOp.
5711 }
5712
5713 // ReplaceNodeResults requires we maintain the same type for the return
5714 // value.
5715 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5716}
5717
5718// Converts the given 32-bit operation to a i64 operation with signed extension
5719// semantic to reduce the signed extension instructions.
5721 SDLoc DL(N);
5722 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5723 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5724 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5725 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5726 DAG.getValueType(MVT::i32));
5727 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5728}
5729
5730// Helper function that emits error message for intrinsics with/without chain
5731// and return a UNDEF or and the chain as the results.
5734 StringRef ErrorMsg, bool WithChain = true) {
5735 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5736 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5737 if (!WithChain)
5738 return;
5739 Results.push_back(N->getOperand(0));
5740}
5741
5742template <unsigned N>
5743static void
5746 unsigned ResOp) {
5747 const StringRef ErrorMsgOOR = "argument out of range";
5748 unsigned Imm = Node->getConstantOperandVal(2);
5749 if (!isUInt<N>(Imm)) {
5751 /*WithChain=*/false);
5752 return;
5753 }
5754 SDLoc DL(Node);
5755 SDValue Vec = Node->getOperand(1);
5756
5757 SDValue PickElt =
5758 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5759 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5761 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5762 PickElt.getValue(0)));
5763}
5764
5767 SelectionDAG &DAG,
5769 unsigned ResOp) {
5770 SDLoc DL(N);
5771 SDValue Vec = N->getOperand(1);
5772
5773 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5774 Results.push_back(
5775 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5776}
5777
5778static void
5780 SelectionDAG &DAG,
5782 switch (N->getConstantOperandVal(0)) {
5783 default:
5784 llvm_unreachable("Unexpected Intrinsic.");
5785 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5787 LoongArchISD::VPICK_SEXT_ELT);
5788 break;
5789 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5790 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5792 LoongArchISD::VPICK_SEXT_ELT);
5793 break;
5794 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5796 LoongArchISD::VPICK_SEXT_ELT);
5797 break;
5798 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5800 LoongArchISD::VPICK_ZEXT_ELT);
5801 break;
5802 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5803 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5805 LoongArchISD::VPICK_ZEXT_ELT);
5806 break;
5807 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5809 LoongArchISD::VPICK_ZEXT_ELT);
5810 break;
5811 case Intrinsic::loongarch_lsx_bz_b:
5812 case Intrinsic::loongarch_lsx_bz_h:
5813 case Intrinsic::loongarch_lsx_bz_w:
5814 case Intrinsic::loongarch_lsx_bz_d:
5815 case Intrinsic::loongarch_lasx_xbz_b:
5816 case Intrinsic::loongarch_lasx_xbz_h:
5817 case Intrinsic::loongarch_lasx_xbz_w:
5818 case Intrinsic::loongarch_lasx_xbz_d:
5820 LoongArchISD::VALL_ZERO);
5821 break;
5822 case Intrinsic::loongarch_lsx_bz_v:
5823 case Intrinsic::loongarch_lasx_xbz_v:
5825 LoongArchISD::VANY_ZERO);
5826 break;
5827 case Intrinsic::loongarch_lsx_bnz_b:
5828 case Intrinsic::loongarch_lsx_bnz_h:
5829 case Intrinsic::loongarch_lsx_bnz_w:
5830 case Intrinsic::loongarch_lsx_bnz_d:
5831 case Intrinsic::loongarch_lasx_xbnz_b:
5832 case Intrinsic::loongarch_lasx_xbnz_h:
5833 case Intrinsic::loongarch_lasx_xbnz_w:
5834 case Intrinsic::loongarch_lasx_xbnz_d:
5836 LoongArchISD::VALL_NONZERO);
5837 break;
5838 case Intrinsic::loongarch_lsx_bnz_v:
5839 case Intrinsic::loongarch_lasx_xbnz_v:
5841 LoongArchISD::VANY_NONZERO);
5842 break;
5843 }
5844}
5845
5848 SelectionDAG &DAG) {
5849 assert(N->getValueType(0) == MVT::i128 &&
5850 "AtomicCmpSwap on types less than 128 should be legal");
5851 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5852
5853 unsigned Opcode;
5854 switch (MemOp->getMergedOrdering()) {
5858 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5859 break;
5862 Opcode = LoongArch::PseudoCmpXchg128;
5863 break;
5864 default:
5865 llvm_unreachable("Unexpected ordering!");
5866 }
5867
5868 SDLoc DL(N);
5869 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5870 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5871 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5872 NewVal.first, NewVal.second, N->getOperand(0)};
5873
5874 SDNode *CmpSwap = DAG.getMachineNode(
5875 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5876 Ops);
5877 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5878 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5879 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5880 Results.push_back(SDValue(CmpSwap, 3));
5881}
5882
5885 SDLoc DL(N);
5886 EVT VT = N->getValueType(0);
5887 switch (N->getOpcode()) {
5888 default:
5889 llvm_unreachable("Don't know how to legalize this operation");
5890 case ISD::ADD:
5891 case ISD::SUB:
5892 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5893 "Unexpected custom legalisation");
5894 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5895 break;
5896 case ISD::SDIV:
5897 case ISD::UDIV:
5898 case ISD::SREM:
5899 case ISD::UREM:
5900 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5901 "Unexpected custom legalisation");
5902 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5903 Subtarget.hasDiv32() && VT == MVT::i32
5905 : ISD::SIGN_EXTEND));
5906 break;
5907 case ISD::SHL:
5908 case ISD::SRA:
5909 case ISD::SRL:
5910 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5911 "Unexpected custom legalisation");
5912 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5913 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5914 break;
5915 }
5916 break;
5917 case ISD::ROTL:
5918 case ISD::ROTR:
5919 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5920 "Unexpected custom legalisation");
5921 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5922 break;
5923 case ISD::LOAD: {
5924 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5925 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5926 // cast since type legalization will try to use an i64 load.
5927 MVT VT = N->getSimpleValueType(0);
5928 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5929 "Unexpected custom legalisation");
5931 "Unexpected type action!");
5932 if (!ISD::isNON_EXTLoad(N))
5933 return;
5934 auto *Ld = cast<LoadSDNode>(N);
5935 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5936 Ld->getPointerInfo(), Ld->getBaseAlign(),
5937 Ld->getMemOperand()->getFlags());
5938 SDValue Chain = Res.getValue(1);
5939 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5940 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5941 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5942 Res = DAG.getBitcast(WideVT, Res);
5943 Results.push_back(Res);
5944 Results.push_back(Chain);
5945 break;
5946 }
5947 case ISD::FP_TO_SINT: {
5948 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5949 "Unexpected custom legalisation");
5950 SDValue Src = N->getOperand(0);
5951 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5952 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5954 if (!isTypeLegal(Src.getValueType()))
5955 return;
5956 if (Src.getValueType() == MVT::f16)
5957 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5958 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5959 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5960 return;
5961 }
5962 // If the FP type needs to be softened, emit a library call using the 'si'
5963 // version. If we left it to default legalization we'd end up with 'di'.
5964 RTLIB::Libcall LC;
5965 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5966 MakeLibCallOptions CallOptions;
5967 EVT OpVT = Src.getValueType();
5968 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5969 SDValue Chain = SDValue();
5970 SDValue Result;
5971 std::tie(Result, Chain) =
5972 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5973 Results.push_back(Result);
5974 break;
5975 }
5976 case ISD::BITCAST: {
5977 SDValue Src = N->getOperand(0);
5978 EVT SrcVT = Src.getValueType();
5979 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5980 Subtarget.hasBasicF()) {
5981 SDValue Dst =
5982 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5983 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5984 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5985 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5986 DAG.getVTList(MVT::i32, MVT::i32), Src);
5987 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5988 NewReg.getValue(0), NewReg.getValue(1));
5989 Results.push_back(RetReg);
5990 }
5991 break;
5992 }
5993 case ISD::FP_TO_UINT: {
5994 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5995 "Unexpected custom legalisation");
5996 auto &TLI = DAG.getTargetLoweringInfo();
5997 SDValue Tmp1, Tmp2;
5998 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5999 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
6000 break;
6001 }
6002 case ISD::FP_ROUND: {
6003 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
6004 "Unexpected custom legalisation");
6005 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
6006 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
6007 // a target-specific LoongArchISD::VFCVT to optimize it.
6008 SDValue Op0 = N->getOperand(0);
6009 EVT OpVT = Op0.getValueType();
6010 if (OpVT == MVT::v2f64) {
6011 SDValue Undef = DAG.getUNDEF(OpVT);
6012 SDValue Dst =
6013 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
6014 Results.push_back(Dst);
6015 }
6016 break;
6017 }
6018 case ISD::BSWAP: {
6019 SDValue Src = N->getOperand(0);
6020 assert((VT == MVT::i16 || VT == MVT::i32) &&
6021 "Unexpected custom legalization");
6022 MVT GRLenVT = Subtarget.getGRLenVT();
6023 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
6024 SDValue Tmp;
6025 switch (VT.getSizeInBits()) {
6026 default:
6027 llvm_unreachable("Unexpected operand width");
6028 case 16:
6029 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
6030 break;
6031 case 32:
6032 // Only LA64 will get to here due to the size mismatch between VT and
6033 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
6034 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
6035 break;
6036 }
6037 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
6038 break;
6039 }
6040 case ISD::BITREVERSE: {
6041 SDValue Src = N->getOperand(0);
6042 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
6043 "Unexpected custom legalization");
6044 MVT GRLenVT = Subtarget.getGRLenVT();
6045 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
6046 SDValue Tmp;
6047 switch (VT.getSizeInBits()) {
6048 default:
6049 llvm_unreachable("Unexpected operand width");
6050 case 8:
6051 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
6052 break;
6053 case 32:
6054 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
6055 break;
6056 }
6057 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
6058 break;
6059 }
6060 case ISD::CTLZ:
6061 case ISD::CTTZ: {
6062 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
6063 "Unexpected custom legalisation");
6064 Results.push_back(customLegalizeToWOp(N, DAG, 1));
6065 break;
6066 }
6068 SDValue Chain = N->getOperand(0);
6069 SDValue Op2 = N->getOperand(2);
6070 MVT GRLenVT = Subtarget.getGRLenVT();
6071 const StringRef ErrorMsgOOR = "argument out of range";
6072 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
6073 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
6074
6075 switch (N->getConstantOperandVal(1)) {
6076 default:
6077 llvm_unreachable("Unexpected Intrinsic.");
6078 case Intrinsic::loongarch_movfcsr2gr: {
6079 if (!Subtarget.hasBasicF()) {
6080 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
6081 return;
6082 }
6083 unsigned Imm = Op2->getAsZExtVal();
6084 if (!isUInt<2>(Imm)) {
6085 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6086 return;
6087 }
6088 SDValue MOVFCSR2GRResults = DAG.getNode(
6089 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
6090 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
6091 Results.push_back(
6092 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
6093 Results.push_back(MOVFCSR2GRResults.getValue(1));
6094 break;
6095 }
6096#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
6097 case Intrinsic::loongarch_##NAME: { \
6098 SDValue NODE = DAG.getNode( \
6099 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6100 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
6101 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
6102 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
6103 Results.push_back(NODE.getValue(1)); \
6104 break; \
6105 }
6106 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
6107 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
6108 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
6109 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
6110 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
6111 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
6112#undef CRC_CASE_EXT_BINARYOP
6113
6114#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
6115 case Intrinsic::loongarch_##NAME: { \
6116 SDValue NODE = DAG.getNode( \
6117 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6118 {Chain, Op2, \
6119 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
6120 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
6121 Results.push_back(NODE.getValue(1)); \
6122 break; \
6123 }
6124 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
6125 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
6126#undef CRC_CASE_EXT_UNARYOP
6127#define CSR_CASE(ID) \
6128 case Intrinsic::loongarch_##ID: { \
6129 if (!Subtarget.is64Bit()) \
6130 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
6131 break; \
6132 }
6133 CSR_CASE(csrrd_d);
6134 CSR_CASE(csrwr_d);
6135 CSR_CASE(csrxchg_d);
6136 CSR_CASE(iocsrrd_d);
6137#undef CSR_CASE
6138 case Intrinsic::loongarch_csrrd_w: {
6139 unsigned Imm = Op2->getAsZExtVal();
6140 if (!isUInt<14>(Imm)) {
6141 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6142 return;
6143 }
6144 SDValue CSRRDResults =
6145 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
6146 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
6147 Results.push_back(
6148 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
6149 Results.push_back(CSRRDResults.getValue(1));
6150 break;
6151 }
6152 case Intrinsic::loongarch_csrwr_w: {
6153 unsigned Imm = N->getConstantOperandVal(3);
6154 if (!isUInt<14>(Imm)) {
6155 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6156 return;
6157 }
6158 SDValue CSRWRResults =
6159 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
6160 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
6161 DAG.getConstant(Imm, DL, GRLenVT)});
6162 Results.push_back(
6163 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
6164 Results.push_back(CSRWRResults.getValue(1));
6165 break;
6166 }
6167 case Intrinsic::loongarch_csrxchg_w: {
6168 unsigned Imm = N->getConstantOperandVal(4);
6169 if (!isUInt<14>(Imm)) {
6170 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
6171 return;
6172 }
6173 SDValue CSRXCHGResults = DAG.getNode(
6174 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
6175 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
6176 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
6177 DAG.getConstant(Imm, DL, GRLenVT)});
6178 Results.push_back(
6179 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
6180 Results.push_back(CSRXCHGResults.getValue(1));
6181 break;
6182 }
6183#define IOCSRRD_CASE(NAME, NODE) \
6184 case Intrinsic::loongarch_##NAME: { \
6185 SDValue IOCSRRDResults = \
6186 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
6187 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
6188 Results.push_back( \
6189 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
6190 Results.push_back(IOCSRRDResults.getValue(1)); \
6191 break; \
6192 }
6193 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
6194 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
6195 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
6196#undef IOCSRRD_CASE
6197 case Intrinsic::loongarch_cpucfg: {
6198 SDValue CPUCFGResults =
6199 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
6200 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
6201 Results.push_back(
6202 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
6203 Results.push_back(CPUCFGResults.getValue(1));
6204 break;
6205 }
6206 case Intrinsic::loongarch_lddir_d: {
6207 if (!Subtarget.is64Bit()) {
6208 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
6209 return;
6210 }
6211 break;
6212 }
6213 }
6214 break;
6215 }
6216 case ISD::READ_REGISTER: {
6217 if (Subtarget.is64Bit())
6218 DAG.getContext()->emitError(
6219 "On LA64, only 64-bit registers can be read.");
6220 else
6221 DAG.getContext()->emitError(
6222 "On LA32, only 32-bit registers can be read.");
6223 Results.push_back(DAG.getUNDEF(VT));
6224 Results.push_back(N->getOperand(0));
6225 break;
6226 }
6228 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
6229 break;
6230 }
6231 case ISD::LROUND: {
6232 SDValue Op0 = N->getOperand(0);
6233 EVT OpVT = Op0.getValueType();
6234 RTLIB::Libcall LC =
6235 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
6236 MakeLibCallOptions CallOptions;
6237 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
6238 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
6239 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
6240 Results.push_back(Result);
6241 break;
6242 }
6243 case ISD::ATOMIC_CMP_SWAP: {
6245 break;
6246 }
6247 case ISD::TRUNCATE: {
6248 MVT VT = N->getSimpleValueType(0);
6249 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
6250 return;
6251
6252 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
6253 SDValue In = N->getOperand(0);
6254 EVT InVT = In.getValueType();
6255 EVT InEltVT = InVT.getVectorElementType();
6256 EVT EltVT = VT.getVectorElementType();
6257 unsigned MinElts = VT.getVectorNumElements();
6258 unsigned WidenNumElts = WidenVT.getVectorNumElements();
6259 unsigned InBits = InVT.getSizeInBits();
6260
6261 // v8i64 -> (v8i32) -> v8i8
6262 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
6263 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
6264 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6265 InBits = 256;
6266 }
6267
6268 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
6269 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
6270 WidenVT.is128BitVector()) {
6271 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
6272 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
6273 InBits = 128;
6274 InEltVT = InVT.getVectorElementType();
6275 }
6276
6277 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
6278 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
6279 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
6280 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
6281 for (unsigned I = 0; I < MinElts; ++I)
6282 TruncMask[I] = Scale * I;
6283
6284 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
6285 MVT SVT = In.getSimpleValueType().getScalarType();
6286 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
6287 SDValue WidenIn =
6288 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
6289 DAG.getVectorIdxConstant(0, DL));
6290 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
6291 "Illegal vector type in truncation");
6292 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
6293 Results.push_back(
6294 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
6295 return;
6296 }
6297 }
6298
6299 break;
6300 }
6301 case ISD::SIGN_EXTEND: {
6302 // LASX has native VEXT2XV_* for sign extension.
6303 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
6304 return;
6305
6306 EVT DstVT = N->getValueType(0);
6307 SDValue Src = N->getOperand(0);
6308 MVT SrcVT = Src.getSimpleValueType();
6309
6310 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
6311 unsigned DstEltBits = DstVT.getScalarSizeInBits();
6312 unsigned NumElts = DstVT.getVectorNumElements();
6313
6314 if (SrcVT.getSizeInBits() > 128)
6315 return;
6316
6317 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6318 return;
6319
6320 // If every source element is all-ones or all-zeros, so is every extended
6321 // element, and interleaving a block with itself extends its low half.
6322 bool IsSignSplat = DAG.ComputeNumSignBits(Src) == SrcEltBits;
6323
6324 // Legalize and extend the src to 128-bit first.
6325 if (SrcVT.getSizeInBits() < 128) {
6326 unsigned WidenSrcElts = 128 / SrcEltBits;
6327 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6328 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6329 DAG.getUNDEF(WidenSrcVT), Src,
6330 DAG.getVectorIdxConstant(0, DL));
6331 SrcVT = WidenSrcVT;
6332
6333 unsigned FirstStageEltBits = 128 / NumElts;
6334 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6335 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6336 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6337 SrcVT = FirstStageVT;
6338 SrcEltBits = FirstStageEltBits;
6339 }
6340
6342 Blocks.push_back(Src);
6343
6344 // Sign-extend the src by using VSLLWIL (or VILVL for a sign splat) + VEXTH
6345 // recursively.
6346 while (SrcEltBits < DstEltBits) {
6347 unsigned NextEltBits = SrcEltBits * 2;
6348 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6349 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6350 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6351 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6352
6353 SmallVector<SDValue, 8> NextBlocks;
6354 NextBlocks.reserve(Blocks.size() * 2);
6355 for (SDValue Block : Blocks) {
6356 SDValue Lo;
6357 if (IsSignSplat) {
6358 Lo = DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Block, Block);
6359 Lo = DAG.getBitcast(NextBlockVT, Lo);
6360 } else {
6361 Lo = DAG.getNode(LoongArchISD::VSLLWIL, DL, NextBlockVT, Block,
6362 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
6363 }
6364 NextBlocks.push_back(Lo);
6365 NextBlocks.push_back(
6366 DAG.getNode(LoongArchISD::VEXTH, DL, NextBlockVT, Block));
6367 }
6368
6369 Blocks = std::move(NextBlocks);
6370 SrcVT = NextBlockVT;
6371 SrcEltBits = NextEltBits;
6372 }
6373
6374 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6375 break;
6376 }
6377 case ISD::FP_EXTEND:
6378 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6379 // no target-specific lowering is required. Leave it unchanged and rely on
6380 // the default type legalization.
6381 break;
6382 }
6383}
6384
6385/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6387 SelectionDAG &DAG) {
6388 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6389
6390 MVT VT = N->getSimpleValueType(0);
6391 if (!VT.is128BitVector() && !VT.is256BitVector())
6392 return SDValue();
6393
6394 SDValue X, Y;
6395 SDValue N0 = N->getOperand(0);
6396 SDValue N1 = N->getOperand(1);
6397
6398 if (SDValue Not = isNOT(N0, DAG)) {
6399 X = Not;
6400 Y = N1;
6401 } else if (SDValue Not = isNOT(N1, DAG)) {
6402 X = Not;
6403 Y = N0;
6404 } else
6405 return SDValue();
6406
6407 X = DAG.getBitcast(VT, X);
6408 Y = DAG.getBitcast(VT, Y);
6409 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6410}
6411
6412static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6413 unsigned MinSizeInBits) {
6416
6417 if (!Node)
6418 return false;
6419
6420 APInt SplatUndef;
6421 unsigned SplatBitSize;
6422 bool HasAnyUndefs;
6423
6424 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6425 HasAnyUndefs, MinSizeInBits,
6426 /*IsBigEndian=*/false);
6427}
6428
6429static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6430 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6431 if (!BV)
6432 return SDValue();
6433
6434 SDValue Src;
6435 int Start = -1;
6436
6437 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6438 SDValue Op = BV->getOperand(i);
6439 if (Op.isUndef())
6440 continue;
6441 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6442 return SDValue();
6443
6444 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6445 if (!IdxC)
6446 return SDValue();
6447
6448 unsigned EltIdx = IdxC->getZExtValue();
6449 if (Start < 0)
6450 Start = (int)EltIdx - (int)(i * 2);
6451 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6452 return SDValue();
6453
6454 SDValue CurSrc = Op.getOperand(0);
6455 if (!Src)
6456 Src = CurSrc;
6457 else if (Src != CurSrc)
6458 return SDValue();
6459 }
6460
6461 if (!Src || Start < 0)
6462 return SDValue();
6463
6464 StartIndex = (unsigned)Start;
6465 return Src;
6466}
6467
6468static SDValue
6471 if (!Subtarget.hasExtLSX())
6472 return SDValue();
6473
6474 unsigned Opc = N->getOpcode();
6475 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6476
6477 EVT VT = N->getValueType(0);
6478 SDLoc DL(N);
6479
6480 SDValue LHS = N->getOperand(0);
6481 SDValue RHS = N->getOperand(1);
6482
6483 bool isSigned;
6484 unsigned ExtOpc = LHS.getOpcode();
6485 if (ExtOpc == ISD::SIGN_EXTEND)
6486 isSigned = true;
6487 else if (ExtOpc == ISD::ZERO_EXTEND)
6488 isSigned = false;
6489 else
6490 return SDValue();
6491
6492 if (ExtOpc != RHS.getOpcode())
6493 return SDValue();
6494
6495 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6496 return SDValue();
6497
6498 unsigned OddIdx, EvenIdx;
6499 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6500 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6501
6502 if (!LHSVec || !RHSVec)
6503 return SDValue();
6504 if (OddIdx != 1 || EvenIdx != 0)
6505 return SDValue();
6506 if (LHSVec.getValueType() != RHSVec.getValueType())
6507 return SDValue();
6508
6509 EVT SrcVT = LHSVec.getValueType();
6510 EVT SrcEltVT = SrcVT.getVectorElementType();
6511 EVT DstEltVT = VT.getVectorElementType();
6512 auto &TLI = DAG.getTargetLoweringInfo();
6513
6514 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6515 return SDValue();
6516 if (!SrcVT.isVector() || !VT.isVector())
6517 return SDValue();
6518 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6519 return SDValue();
6520 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6521 return SDValue();
6522 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6523 return SDValue();
6524
6525 unsigned TargetOpc;
6526 if (Opc == ISD::ADD)
6527 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6528 else
6529 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6530
6531 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6532}
6533
6538 return V;
6539
6540 if (DCI.isBeforeLegalizeOps())
6541 return SDValue();
6542
6543 EVT VT = N->getValueType(0);
6544 if (!VT.isVector())
6545 return SDValue();
6546
6547 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6548 return SDValue();
6549
6550 EVT EltVT = VT.getVectorElementType();
6551 if (!EltVT.isInteger())
6552 return SDValue();
6553
6554 // match:
6555 //
6556 // add
6557 // (and
6558 // (srl X, shift-1) / X
6559 // 1)
6560 // (srl/sra X, shift)
6561
6562 SDValue Add0 = N->getOperand(0);
6563 SDValue Add1 = N->getOperand(1);
6564 SDValue And;
6565 SDValue Shr;
6566
6567 if (Add0.getOpcode() == ISD::AND) {
6568 And = Add0;
6569 Shr = Add1;
6570 } else if (Add1.getOpcode() == ISD::AND) {
6571 And = Add1;
6572 Shr = Add0;
6573 } else {
6574 return SDValue();
6575 }
6576
6577 // match:
6578 //
6579 // srl/sra X, shift
6580
6581 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6582 return SDValue();
6583
6584 SDValue X = Shr.getOperand(0);
6585 SDValue Shift = Shr.getOperand(1);
6586 APInt ShiftVal;
6587
6588 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6589 return SDValue();
6590
6591 if (ShiftVal == 0)
6592 return SDValue();
6593
6594 // match:
6595 //
6596 // and
6597 // (srl X, shift-1) / X
6598 // 1
6599
6600 SDValue One = And.getOperand(1);
6601 APInt SplatVal;
6602
6603 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6604 return SDValue();
6605
6606 if (SplatVal != 1)
6607 return SDValue();
6608
6609 if (And.getOperand(0) == X) {
6610 // match:
6611 //
6612 // shift == 1
6613
6614 if (ShiftVal != 1)
6615 return SDValue();
6616 } else {
6617 // match:
6618 //
6619 // srl X, shift-1
6620
6621 SDValue Srl = And.getOperand(0);
6622
6623 if (Srl.getOpcode() != ISD::SRL)
6624 return SDValue();
6625
6626 if (Srl.getOperand(0) != X)
6627 return SDValue();
6628
6629 // match:
6630 //
6631 // shift-1
6632
6633 SDValue ShiftMinus1 = Srl.getOperand(1);
6634
6635 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6636 return SDValue();
6637
6638 if (ShiftVal != (SplatVal + 1))
6639 return SDValue();
6640 }
6641
6642 // We matched a rounded right shift pattern and can lower it
6643 // to a single vector rounded shift instruction.
6644
6645 SDLoc DL(N);
6646 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6647 : LoongArchISD::VSRAR,
6648 DL, VT, X, Shift);
6649}
6650
6654 if (DCI.isBeforeLegalizeOps())
6655 return SDValue();
6656
6657 SDValue FirstOperand = N->getOperand(0);
6658 SDValue SecondOperand = N->getOperand(1);
6659 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6660 EVT ValTy = N->getValueType(0);
6661 SDLoc DL(N);
6662 uint64_t lsb, msb;
6663 unsigned SMIdx, SMLen;
6664 ConstantSDNode *CN;
6665 SDValue NewOperand;
6666 MVT GRLenVT = Subtarget.getGRLenVT();
6667
6668 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6669 return R;
6670
6671 // BSTRPICK requires the 32S feature.
6672 if (!Subtarget.has32S())
6673 return SDValue();
6674
6675 // Op's second operand must be a shifted mask.
6676 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6677 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6678 return SDValue();
6679
6680 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6681 // Pattern match BSTRPICK.
6682 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6683 // => BSTRPICK $dst, $src, msb, lsb
6684 // where msb = lsb + len - 1
6685
6686 // The second operand of the shift must be an immediate.
6687 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6688 return SDValue();
6689
6690 lsb = CN->getZExtValue();
6691
6692 // Return if the shifted mask does not start at bit 0 or the sum of its
6693 // length and lsb exceeds the word's size.
6694 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6695 return SDValue();
6696
6697 NewOperand = FirstOperand.getOperand(0);
6698 } else {
6699 // Pattern match BSTRPICK.
6700 // $dst = and $src, (2**len- 1) , if len > 12
6701 // => BSTRPICK $dst, $src, msb, lsb
6702 // where lsb = 0 and msb = len - 1
6703
6704 // If the mask is <= 0xfff, andi can be used instead.
6705 if (CN->getZExtValue() <= 0xfff)
6706 return SDValue();
6707
6708 // Return if the MSB exceeds.
6709 if (SMIdx + SMLen > ValTy.getSizeInBits())
6710 return SDValue();
6711
6712 if (SMIdx > 0) {
6713 // Omit if the constant has more than 2 uses. This a conservative
6714 // decision. Whether it is a win depends on the HW microarchitecture.
6715 // However it should always be better for 1 and 2 uses.
6716 if (CN->use_size() > 2)
6717 return SDValue();
6718 // Return if the constant can be composed by a single LU12I.W.
6719 if ((CN->getZExtValue() & 0xfff) == 0)
6720 return SDValue();
6721 // Return if the constand can be composed by a single ADDI with
6722 // the zero register.
6723 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6724 return SDValue();
6725 }
6726
6727 lsb = SMIdx;
6728 NewOperand = FirstOperand;
6729 }
6730
6731 msb = lsb + SMLen - 1;
6732 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6733 DAG.getConstant(msb, DL, GRLenVT),
6734 DAG.getConstant(lsb, DL, GRLenVT));
6735 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6736 return NR0;
6737 // Try to optimize to
6738 // bstrpick $Rd, $Rs, msb, lsb
6739 // slli $Rd, $Rd, lsb
6740 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6741 DAG.getConstant(lsb, DL, GRLenVT));
6742}
6743
6744// Return the original source vector if N consists of the half
6745// of each 128-bit lane.
6748
6749 EVT DstVT = N.getValueType();
6750 if (!DstVT.isVector())
6751 return SDValue();
6752
6753 unsigned NumElts = DstVT.getVectorNumElements();
6754
6755 // LSX canonical form:
6756 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6757 SDValue Src = N.getOperand(0);
6758 EVT SrcVT = Src.getValueType();
6759
6760 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6761 return SDValue();
6762 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6763 return SDValue();
6764 if (SrcVT.getVectorNumElements() != NumElts * 2)
6765 return SDValue();
6766 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6767 return SDValue();
6768
6769 return Src;
6770 }
6771
6772 // LASX canonical form:
6773 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6774 if (!BV)
6775 return SDValue();
6776
6777 if (NumElts % 2 != 0)
6778 return SDValue();
6779
6780 SDValue Src;
6781 EVT SrcVT;
6782
6783 for (unsigned I = 0; I != NumElts; ++I) {
6784 SDValue Elt = BV->getOperand(I);
6785 if (Elt.isUndef())
6786 continue;
6788 return SDValue();
6789
6790 SDValue ThisSrc = Elt.getOperand(0);
6791 SDValue Idx = Elt.getOperand(1);
6792 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6793 if (!CI)
6794 return SDValue();
6795
6796 if (!Src) {
6797 Src = ThisSrc;
6798 SrcVT = Src.getValueType();
6799 if (!SrcVT.isVector())
6800 return SDValue();
6801
6802 if (!SrcVT.is256BitVector())
6803 return SDValue();
6804 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6805 return SDValue();
6806 if (SrcVT.getVectorNumElements() != NumElts * 2)
6807 return SDValue();
6808 } else if (ThisSrc != Src) {
6809 return SDValue();
6810 }
6811
6812 unsigned Half = NumElts / 2;
6813 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6814 ExpectedIdx += isLow ? 0 : Half;
6815
6816 if (CI->getZExtValue() != ExpectedIdx)
6817 return SDValue();
6818 }
6819
6820 return Src;
6821}
6822
6826 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6827
6828 EVT VT = N->getValueType(0);
6829 SDLoc DL(N);
6830
6831 SDValue LHS = N->getOperand(0);
6832 SDValue RHS = N->getOperand(1);
6833
6834 bool isSigned;
6835 unsigned ExtOpc = LHS.getOpcode();
6836 if (ExtOpc == ISD::SIGN_EXTEND)
6837 isSigned = true;
6838 else if (ExtOpc == ISD::ZERO_EXTEND)
6839 isSigned = false;
6840 else
6841 return SDValue();
6842
6843 if (!LHS.hasOneUse())
6844 return SDValue();
6845
6846 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
6847 N->getValueSizeInBits(0) != LHS->getOperand(0).getValueSizeInBits() * 2)
6848 return SDValue();
6849
6850 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6851 if (!Vec)
6852 return SDValue();
6853
6854 EVT SrcVT = Vec.getValueType();
6855 EVT SrcEltVT = SrcVT.getVectorElementType();
6856 EVT DstEltVT = VT.getVectorElementType();
6857 APInt Imm;
6858 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6859 return SDValue();
6860 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6861 return SDValue();
6862
6863 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6864 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6865 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6866}
6867
6871 // BSTRPICK requires the 32S feature.
6872 if (!Subtarget.has32S())
6873 return SDValue();
6874
6875 if (DCI.isBeforeLegalizeOps())
6876 return SDValue();
6877
6878 // $dst = srl (and $src, Mask), Shamt
6879 // =>
6880 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6881 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6882 //
6883
6884 SDValue FirstOperand = N->getOperand(0);
6885 ConstantSDNode *CN;
6886 EVT ValTy = N->getValueType(0);
6887 SDLoc DL(N);
6888 MVT GRLenVT = Subtarget.getGRLenVT();
6889 unsigned MaskIdx, MaskLen;
6890 uint64_t Shamt;
6891
6892 // The first operand must be an AND and the second operand of the AND must be
6893 // a shifted mask.
6894 if (FirstOperand.getOpcode() != ISD::AND ||
6895 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6896 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6897 return SDValue();
6898
6899 // The second operand (shift amount) must be an immediate.
6900 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6901 return SDValue();
6902
6903 Shamt = CN->getZExtValue();
6904 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6905 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6906 FirstOperand->getOperand(0),
6907 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6908 DAG.getConstant(Shamt, DL, GRLenVT));
6909
6910 return SDValue();
6911}
6912
6913// Try to turn a sub boolean RHS and constant LHS into an addi. LoongArch's
6914// SUB has no immediate form, so (sub C, X) normally requires either
6915// materializing C or using sub with R0 plus an addi; rewriting it as
6916// (add X', C - 1) lets the immediate fold into a single ADDI.
6918 SDValue N0 = N->getOperand(0);
6919 SDValue N1 = N->getOperand(1);
6920 EVT VT = N->getValueType(0);
6921 SDLoc DL(N);
6922
6923 // Require a constant LHS.
6924 auto *N0C = dyn_cast<ConstantSDNode>(N0);
6925 if (!N0C)
6926 return SDValue();
6927
6928 // (sub 0, X) is a negation, not a constant materialization; rewriting it
6929 // as (add (setcc inv), -1) changes the condition code and can duplicate a
6930 // compare, without saving any instruction.
6931 if (N0C->isZero() && !N->hasOneUse())
6932 return SDValue();
6933
6934 // The result of this fold is only folded into an ADDI when it is used
6935 // directly. When it feeds an extend, the original (sub C, X) form usually
6936 // combines better with the surrounding zext/negate/xor.
6937 if (N->hasOneUse()) {
6938 unsigned UserOpc = N->use_begin()->getUser()->getOpcode();
6939 if (UserOpc == ISD::ZERO_EXTEND || UserOpc == ISD::SIGN_EXTEND ||
6940 UserOpc == ISD::ANY_EXTEND || UserOpc == ISD::SUB)
6941 return SDValue();
6942 }
6943
6944 // All our optimizations involve subtracting 1 from the immediate and
6945 // forming an ADDI. Make sure the new immediate is valid for an ADDI.
6946 APInt ImmValMinus1 = N0C->getAPIntValue() - 1;
6947 if (!ImmValMinus1.isSignedIntN(12))
6948 return SDValue();
6949
6950 SDValue NewLHS;
6951 if (N1.getOpcode() == ISD::SETCC && N1.hasOneUse()) {
6952 // (sub constant, (setcc x, y, eq/neq)) ->
6953 // (add (setcc x, y, neq/eq), constant - 1)
6954 ISD::CondCode CCVal = cast<CondCodeSDNode>(N1.getOperand(2))->get();
6955 EVT SetCCOpVT = N1.getOperand(0).getValueType();
6956 if (!ISD::isIntEqualitySetCC(CCVal) || !SetCCOpVT.isInteger())
6957 return SDValue();
6958 CCVal = ISD::getSetCCInverse(CCVal, SetCCOpVT);
6959 NewLHS =
6960 DAG.getSetCC(SDLoc(N1), VT, N1.getOperand(0), N1.getOperand(1), CCVal);
6961 } else if (N1.getOpcode() == ISD::XOR && isOneConstant(N1.getOperand(1)) &&
6962 N1.getOperand(0).getOpcode() == ISD::SETCC) {
6963 // (sub C, (xor (setcc), 1)) -> (add (setcc), C-1).
6964 // Since setcc returns a bool the xor is equivalent to 1-setcc.
6965 NewLHS = N1.getOperand(0);
6966 } else
6967 return SDValue();
6968
6969 SDValue NewRHS = DAG.getConstant(ImmValMinus1, DL, VT);
6970 return DAG.getNode(ISD::ADD, DL, VT, NewLHS, NewRHS);
6971}
6972
6977 return V;
6978
6979 if (N->getValueType(0) != Subtarget.getGRLenVT())
6980 return SDValue();
6981
6982 SDValue N0 = N->getOperand(0);
6983 SDValue N1 = N->getOperand(1);
6984 EVT VT = N->getValueType(0);
6985
6986 if (SDValue V = combineSubOfBoolean(N, DAG))
6987 return V;
6988
6989 // fold (sub 0, (setcc x, 0, setlt)) -> (sra x, xlen - 1)
6990 if (isNullConstant(N0) && N1.getOpcode() == ISD::SETCC && N1.hasOneUse() &&
6991 isNullConstant(N1.getOperand(1)) &&
6992 N1.getValueType() == N1.getOperand(0).getValueType()) {
6993 ISD::CondCode CCVal = cast<CondCodeSDNode>(N1.getOperand(2))->get();
6994 if (CCVal == ISD::SETLT) {
6995 SDLoc DL(N);
6996 unsigned ShAmt = N0.getValueSizeInBits() - 1;
6997 return DAG.getNode(ISD::SRA, DL, VT, N1.getOperand(0),
6998 DAG.getConstant(ShAmt, DL, VT));
6999 }
7000 }
7001
7002 return SDValue();
7003}
7004
7005// Helper to peek through bitops/trunc/setcc to determine size of source vector.
7006// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
7007static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
7008 unsigned Depth) {
7009 // Limit recursion.
7011 return false;
7012 switch (Src.getOpcode()) {
7013 case ISD::SETCC:
7014 case ISD::TRUNCATE:
7015 return Src.getOperand(0).getValueSizeInBits() == Size;
7016 case ISD::FREEZE:
7017 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
7018 case ISD::AND:
7019 case ISD::XOR:
7020 case ISD::OR:
7021 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
7022 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
7023 case ISD::SELECT:
7024 case ISD::VSELECT:
7025 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
7026 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
7027 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
7028 case ISD::BUILD_VECTOR:
7029 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
7030 ISD::isBuildVectorAllOnes(Src.getNode());
7031 }
7032 return false;
7033}
7034
7035// Helper to push sign extension of vXi1 SETCC result through bitops.
7037 SDValue Src, const SDLoc &DL) {
7038 switch (Src.getOpcode()) {
7039 case ISD::SETCC:
7040 case ISD::FREEZE:
7041 case ISD::TRUNCATE:
7042 case ISD::BUILD_VECTOR:
7043 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
7044 case ISD::AND:
7045 case ISD::XOR:
7046 case ISD::OR:
7047 return DAG.getNode(
7048 Src.getOpcode(), DL, SExtVT,
7049 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
7050 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
7051 case ISD::SELECT:
7052 case ISD::VSELECT:
7053 return DAG.getSelect(
7054 DL, SExtVT, Src.getOperand(0),
7055 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
7056 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
7057 }
7058 llvm_unreachable("Unexpected node type for vXi1 sign extension");
7059}
7060
7061static SDValue
7065 SDLoc DL(N);
7066 EVT VT = N->getValueType(0);
7067 SDValue Src = N->getOperand(0);
7068 EVT SrcVT = Src.getValueType();
7069
7070 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
7071 return SDValue();
7072
7073 bool UseLASX;
7074 unsigned Opc = ISD::DELETED_NODE;
7075 EVT CmpVT = Src.getOperand(0).getValueType();
7076 EVT EltVT = CmpVT.getVectorElementType();
7077
7078 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
7079 UseLASX = false;
7080 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
7081 CmpVT.getSizeInBits() == 256)
7082 UseLASX = true;
7083 else
7084 return SDValue();
7085
7086 SDValue SrcN1 = Src.getOperand(1);
7087 switch (Src.getOperandCondCode(2)) {
7088 default:
7089 break;
7090 case ISD::SETEQ:
7091 // x == 0 => not (vmsknez.b x)
7092 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
7093 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
7094 break;
7095 case ISD::SETGT:
7096 // x > -1 => vmskgez.b x
7097 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
7098 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
7099 break;
7100 case ISD::SETGE:
7101 // x >= 0 => vmskgez.b x
7102 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
7103 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
7104 break;
7105 case ISD::SETLT:
7106 // x < 0 => vmskltz.{b,h,w,d} x
7107 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
7108 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
7109 EltVT == MVT::i64))
7110 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
7111 break;
7112 case ISD::SETLE:
7113 // x <= -1 => vmskltz.{b,h,w,d} x
7114 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
7115 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
7116 EltVT == MVT::i64))
7117 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
7118 break;
7119 case ISD::SETNE:
7120 // x != 0 => vmsknez.b x
7121 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
7122 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
7123 break;
7124 }
7125
7126 if (Opc == ISD::DELETED_NODE)
7127 return SDValue();
7128
7129 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
7131 V = DAG.getZExtOrTrunc(V, DL, T);
7132 return DAG.getBitcast(VT, V);
7133}
7134
7138 SDLoc DL(N);
7139 EVT VT = N->getValueType(0);
7140 SDValue Src = N->getOperand(0);
7141 EVT SrcVT = Src.getValueType();
7142 MVT GRLenVT = Subtarget.getGRLenVT();
7143
7144 if (!DCI.isBeforeLegalizeOps())
7145 return SDValue();
7146
7147 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
7148 return SDValue();
7149
7150 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
7152 if (Res)
7153 return Res;
7154
7155 // Generate vXi1 using [X]VMSKLTZ
7156 MVT SExtVT;
7157 unsigned Opc;
7158 bool UseLASX = false;
7159 bool PropagateSExt = false;
7160
7161 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
7162 EVT CmpVT = Src.getOperand(0).getValueType();
7163 if (CmpVT.getSizeInBits() > 256)
7164 return SDValue();
7165 }
7166
7167 switch (SrcVT.getSimpleVT().SimpleTy) {
7168 default:
7169 return SDValue();
7170 case MVT::v2i1:
7171 SExtVT = MVT::v2i64;
7172 break;
7173 case MVT::v4i1:
7174 SExtVT = MVT::v4i32;
7175 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
7176 SExtVT = MVT::v4i64;
7177 UseLASX = true;
7178 PropagateSExt = true;
7179 }
7180 break;
7181 case MVT::v8i1:
7182 SExtVT = MVT::v8i16;
7183 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
7184 SExtVT = MVT::v8i32;
7185 UseLASX = true;
7186 PropagateSExt = true;
7187 }
7188 break;
7189 case MVT::v16i1:
7190 SExtVT = MVT::v16i8;
7191 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
7192 SExtVT = MVT::v16i16;
7193 UseLASX = true;
7194 PropagateSExt = true;
7195 }
7196 break;
7197 case MVT::v32i1:
7198 SExtVT = MVT::v32i8;
7199 UseLASX = true;
7200 break;
7201 };
7202 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
7203 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
7204
7205 SDValue V;
7206 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
7207 if (Src.getSimpleValueType() == MVT::v32i8) {
7208 SDValue Lo, Hi;
7209 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
7210 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
7211 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
7212 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
7213 DAG.getShiftAmountConstant(16, GRLenVT, DL));
7214 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
7215 } else if (UseLASX) {
7216 return SDValue();
7217 }
7218 }
7219
7220 if (!V) {
7221 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
7222 V = DAG.getNode(Opc, DL, GRLenVT, Src);
7223 }
7224
7226 V = DAG.getZExtOrTrunc(V, DL, T);
7227 return DAG.getBitcast(VT, V);
7228}
7229
7233 MVT GRLenVT = Subtarget.getGRLenVT();
7234 EVT ValTy = N->getValueType(0);
7235 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
7236 ConstantSDNode *CN0, *CN1;
7237 SDLoc DL(N);
7238 unsigned ValBits = ValTy.getSizeInBits();
7239 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
7240 unsigned Shamt;
7241 bool SwapAndRetried = false;
7242
7243 // BSTRPICK requires the 32S feature.
7244 if (!Subtarget.has32S())
7245 return SDValue();
7246
7247 if (DCI.isBeforeLegalizeOps())
7248 return SDValue();
7249
7250 if (ValBits != 32 && ValBits != 64)
7251 return SDValue();
7252
7253Retry:
7254 // 1st pattern to match BSTRINS:
7255 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
7256 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
7257 // =>
7258 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
7259 if (N0.getOpcode() == ISD::AND &&
7260 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7261 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7262 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
7263 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7264 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
7265 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
7266 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7267 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
7268 (MaskIdx0 + MaskLen0 <= ValBits)) {
7269 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
7270 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7271 N1.getOperand(0).getOperand(0),
7272 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7273 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7274 }
7275
7276 // 2nd pattern to match BSTRINS:
7277 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
7278 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
7279 // =>
7280 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
7281 if (N0.getOpcode() == ISD::AND &&
7282 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7283 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7284 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7285 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7286 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
7287 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7288 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
7289 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
7290 (MaskIdx0 + MaskLen0 <= ValBits)) {
7291 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
7292 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7293 N1.getOperand(0).getOperand(0),
7294 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
7295 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7296 }
7297
7298 // 3rd pattern to match BSTRINS:
7299 // R = or (and X, mask0), (and Y, mask1)
7300 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
7301 // =>
7302 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
7303 // where msb = lsb + size - 1
7304 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
7305 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7306 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7307 (MaskIdx0 + MaskLen0 <= 64) &&
7308 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
7309 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7310 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
7311 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7312 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
7313 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
7314 DAG.getConstant(ValBits == 32
7315 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7316 : (MaskIdx0 + MaskLen0 - 1),
7317 DL, GRLenVT),
7318 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7319 }
7320
7321 // 4th pattern to match BSTRINS:
7322 // R = or (and X, mask), (shl Y, shamt)
7323 // where mask = (2**shamt - 1)
7324 // =>
7325 // R = BSTRINS X, Y, ValBits - 1, shamt
7326 // where ValBits = 32 or 64
7327 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
7328 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7329 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
7330 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7331 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
7332 (MaskIdx0 + MaskLen0 <= ValBits)) {
7333 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
7334 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7335 N1.getOperand(0),
7336 DAG.getConstant((ValBits - 1), DL, GRLenVT),
7337 DAG.getConstant(Shamt, DL, GRLenVT));
7338 }
7339
7340 // 5th pattern to match BSTRINS:
7341 // R = or (and X, mask), const
7342 // where ~mask = (2**size - 1) << lsb, mask & const = 0
7343 // =>
7344 // R = BSTRINS X, (const >> lsb), msb, lsb
7345 // where msb = lsb + size - 1
7346 if (N0.getOpcode() == ISD::AND &&
7347 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
7348 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
7349 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
7350 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
7351 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
7352 return DAG.getNode(
7353 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
7354 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
7355 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
7356 : (MaskIdx0 + MaskLen0 - 1),
7357 DL, GRLenVT),
7358 DAG.getConstant(MaskIdx0, DL, GRLenVT));
7359 }
7360
7361 // 6th pattern.
7362 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
7363 // by the incoming bits are known to be zero.
7364 // =>
7365 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
7366 //
7367 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
7368 // pattern is more common than the 1st. So we put the 1st before the 6th in
7369 // order to match as many nodes as possible.
7370 ConstantSDNode *CNMask, *CNShamt;
7371 unsigned MaskIdx, MaskLen;
7372 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
7373 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7374 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7375 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7376 CNShamt->getZExtValue() + MaskLen <= ValBits) {
7377 Shamt = CNShamt->getZExtValue();
7378 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
7379 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7380 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
7381 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7382 N1.getOperand(0).getOperand(0),
7383 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
7384 DAG.getConstant(Shamt, DL, GRLenVT));
7385 }
7386 }
7387
7388 // 7th pattern.
7389 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
7390 // overwritten by the incoming bits are known to be zero.
7391 // =>
7392 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7393 //
7394 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7395 // before the 7th in order to match as many nodes as possible.
7396 if (N1.getOpcode() == ISD::AND &&
7397 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7398 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7399 N1.getOperand(0).getOpcode() == ISD::SHL &&
7400 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7401 CNShamt->getZExtValue() == MaskIdx) {
7402 APInt ShMask(ValBits, CNMask->getZExtValue());
7403 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7404 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7405 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7406 N1.getOperand(0).getOperand(0),
7407 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7408 DAG.getConstant(MaskIdx, DL, GRLenVT));
7409 }
7410 }
7411
7412 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7413 if (!SwapAndRetried) {
7414 std::swap(N0, N1);
7415 SwapAndRetried = true;
7416 goto Retry;
7417 }
7418
7419 SwapAndRetried = false;
7420Retry2:
7421 // 8th pattern.
7422 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7423 // the incoming bits are known to be zero.
7424 // =>
7425 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7426 //
7427 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7428 // we put it here in order to match as many nodes as possible or generate less
7429 // instructions.
7430 if (N1.getOpcode() == ISD::AND &&
7431 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7432 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7433 APInt ShMask(ValBits, CNMask->getZExtValue());
7434 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7435 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7436 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7437 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7438 N1->getOperand(0),
7439 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7440 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7441 DAG.getConstant(MaskIdx, DL, GRLenVT));
7442 }
7443 }
7444 // Swap N0/N1 and retry.
7445 if (!SwapAndRetried) {
7446 std::swap(N0, N1);
7447 SwapAndRetried = true;
7448 goto Retry2;
7449 }
7450
7451 return SDValue();
7452}
7453
7456 EVT VT = N->getValueType(0);
7457 // LA64 promotes i32 integer operations to GPR-width operations during
7458 // legalization. Match the idiom before that promotion as well as after
7459 // it, otherwise common unsigned 32-bit bit tests miss this combine.
7460 if (VT != Subtarget.getGRLenVT() && !(Subtarget.is64Bit() && VT == MVT::i32))
7461 return SDValue();
7462
7463 SDValue XorOps[] = {N->getOperand(0), N->getOperand(1)};
7464 for (unsigned AndIdx = 0; AndIdx != 2; ++AndIdx) {
7465 SDValue And = XorOps[AndIdx];
7466 SDValue Mask = XorOps[1 - AndIdx];
7467 if (And.getOpcode() != ISD::AND || !And.hasOneUse())
7468 continue;
7469
7470 for (unsigned MaskIdx = 0; MaskIdx != 2; ++MaskIdx) {
7471 // Match by SDValue identity so that (X & M1) ^ M2 is never folded
7472 // unless M1 and M2 are the same value. Canonicalize before
7473 // instruction selection, where the AND operand may already have been
7474 // selected to a target machine node.
7475 if (And.getOperand(MaskIdx) != Mask)
7476 continue;
7477 SDLoc DL(N);
7478 SDValue X = And.getOperand(1 - MaskIdx);
7479 return DAG.getNode(ISD::AND, DL, VT, Mask, DAG.getNOT(DL, X, VT));
7480 }
7481 }
7482 return SDValue();
7483}
7484
7486 ExtType = ISD::NON_EXTLOAD;
7487
7488 switch (V.getNode()->getOpcode()) {
7489 case ISD::LOAD: {
7490 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7491 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7492 (LoadNode->getMemoryVT() == MVT::i16)) {
7493 ExtType = LoadNode->getExtensionType();
7494 return true;
7495 }
7496 return false;
7497 }
7498 case ISD::AssertSext: {
7499 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7500 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7501 ExtType = ISD::SEXTLOAD;
7502 return true;
7503 }
7504 return false;
7505 }
7506 case ISD::AssertZext: {
7507 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7508 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7509 ExtType = ISD::ZEXTLOAD;
7510 return true;
7511 }
7512 return false;
7513 }
7514 default:
7515 return false;
7516 }
7517
7518 return false;
7519}
7520
7521// Fold a lane-mask extraction that is only compared against zero into one of
7522// all-lane check instructions, which write the results into fcc register, so
7523// BCEQZ could use it directly.
7524//
7525// (VMSKLTZ X) != 0 -> VSETNEZ.V X
7526// (VMSKLTZ X) == 0 -> VSETEQZ.V X
7527//
7528// This is valid when X is the result of a vector compare instruction,
7529// so each lane of X has to be all-ones or all-zeros.
7531 const SDLoc &DL, SelectionDAG &DAG,
7533 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7534 return SDValue();
7535 if (!isNullConstant(RHS))
7536 return SDValue();
7537
7538 unsigned MskOpc = LHS.getOpcode();
7539 if (MskOpc != LoongArchISD::VMSKLTZ && MskOpc != LoongArchISD::XVMSKLTZ)
7540 return SDValue();
7541 // Keeping the mask alive for another user would defeat the purpose.
7542 if (!LHS.hasOneUse())
7543 return SDValue();
7544
7545 SDValue Src = LHS.getOperand(0);
7546 EVT SrcVT = Src.getValueType();
7547 // Make sure every lane is all-ones or all-zeros.
7548 if (!SrcVT.isVector() ||
7549 DAG.ComputeNumSignBits(Src) != SrcVT.getScalarSizeInBits())
7550 return SDValue();
7551
7552 return DAG.getNode(CC == ISD::SETNE ? LoongArchISD::VANYNONZERO
7553 : LoongArchISD::VALLZERO,
7554 DL, Subtarget.getGRLenVT(), Src);
7555}
7556
7557// Eliminate redundant truncation and zero-extension nodes.
7558// * Case 1:
7559// +------------+ +------------+ +------------+
7560// | Input1 | | Input2 | | CC |
7561// +------------+ +------------+ +------------+
7562// | | |
7563// V V +----+
7564// +------------+ +------------+ |
7565// | TRUNCATE | | TRUNCATE | |
7566// +------------+ +------------+ |
7567// | | |
7568// V V |
7569// +------------+ +------------+ |
7570// | ZERO_EXT | | ZERO_EXT | |
7571// +------------+ +------------+ |
7572// | | |
7573// | +-------------+ |
7574// V V | |
7575// +----------------+ | |
7576// | AND | | |
7577// +----------------+ | |
7578// | | |
7579// +---------------+ | |
7580// | | |
7581// V V V
7582// +-------------+
7583// | CMP |
7584// +-------------+
7585// * Case 2:
7586// +------------+ +------------+ +-------------+ +------------+ +------------+
7587// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7588// +------------+ +------------+ +-------------+ +------------+ +------------+
7589// | | | | |
7590// V | | | |
7591// +------------+ | | | |
7592// | XOR |<---------------------+ | |
7593// +------------+ | | |
7594// | | | |
7595// V V +---------------+ |
7596// +------------+ +------------+ | |
7597// | TRUNCATE | | TRUNCATE | | +-------------------------+
7598// +------------+ +------------+ | |
7599// | | | |
7600// V V | |
7601// +------------+ +------------+ | |
7602// | ZERO_EXT | | ZERO_EXT | | |
7603// +------------+ +------------+ | |
7604// | | | |
7605// V V | |
7606// +----------------+ | |
7607// | AND | | |
7608// +----------------+ | |
7609// | | |
7610// +---------------+ | |
7611// | | |
7612// V V V
7613// +-------------+
7614// | CMP |
7615// +-------------+
7619 ISD::CondCode CC = N->getOperandCondCode(2);
7620
7621 if (N->getValueType(0) == Subtarget.getGRLenVT())
7622 if (SDValue V = foldVMskZeroTest(N->getOperand(0), N->getOperand(1), CC,
7623 SDLoc(N), DAG, Subtarget))
7624 return V;
7625
7626 SDNode *AndNode = N->getOperand(0).getNode();
7627 if (AndNode->getOpcode() != ISD::AND)
7628 return SDValue();
7629
7630 SDValue AndInputValue2 = AndNode->getOperand(1);
7631 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7632 return SDValue();
7633
7634 SDValue CmpInputValue = N->getOperand(1);
7635 SDValue AndInputValue1 = AndNode->getOperand(0);
7636 if (AndInputValue1.getOpcode() == ISD::XOR) {
7637 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7638 return SDValue();
7639 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7640 if (!CN || !CN->isAllOnes())
7641 return SDValue();
7642 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7643 if (!CN || !CN->isZero())
7644 return SDValue();
7645 AndInputValue1 = AndInputValue1.getOperand(0);
7646 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7647 return SDValue();
7648 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7649 if (AndInputValue2 != CmpInputValue)
7650 return SDValue();
7651 } else {
7652 return SDValue();
7653 }
7654
7655 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7656 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7657 return SDValue();
7658
7659 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7660 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7661 return SDValue();
7662
7663 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7664 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7665 ISD::LoadExtType ExtType1;
7666 ISD::LoadExtType ExtType2;
7667
7668 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7669 !checkValueWidth(TruncInputValue2, ExtType2))
7670 return SDValue();
7671
7672 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7673 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7674 return SDValue();
7675
7676 if ((ExtType2 != ISD::ZEXTLOAD) &&
7677 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7678 return SDValue();
7679
7680 // These truncation and zero-extension nodes are not necessary, remove them.
7681 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7682 TruncInputValue1, TruncInputValue2);
7683 SDValue NewSetCC =
7684 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7685 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7686 return SDValue(N, 0);
7687}
7688
7689// Strip a single outer ISD::SIGN_EXTEND_INREG from \p V, if present, and
7690// return the inner value together with the narrow VT it was extending
7691// from. If no such node is present, returns \p V unchanged and an invalid
7692// EVT.
7693//
7694// i32 (and other sub-GRLen) arithmetic is legalized to operate on the full
7695// GRLen-width register, with a `sign_extend_inreg` re-normalizing the
7696// result back into the narrow type's range afterwards (see e.g. the
7697// `add i32` -> `add` + `sign_extend_inreg ..., i32` legalization). Any
7698// combine that reassociates such a binop must track and reapply this
7699// extension, otherwise the transformed code can produce a value whose
7700// high bits no longer match the narrow-type semantics.
7701static std::pair<SDValue, EVT> stripSignExtendInReg(SDValue V) {
7702 if (V.getOpcode() == ISD::SIGN_EXTEND_INREG)
7703 return {V.getOperand(0), cast<VTSDNode>(V.getOperand(1))->getVT()};
7704 return {V, EVT()};
7705}
7706
7707// Try to match \p BinV (after optionally stripping an outer
7708// sign_extend_inreg) as a supported binary operation that has \p X as one
7709// of its operands, returning the matched opcode, the other operand (the
7710// "delta"), and the narrow VT of the sign_extend_inreg that was stripped
7711// (invalid EVT if none was present).
7712//
7713// For commutative ops (add/or/xor), \p X may be either operand, since
7714// `binop(X, Y) == binop(Y, X)` and the identity element (0) works on
7715// either side.
7716//
7717// For `sub`, the operation is NOT commutative: `sub(X, Y) != sub(Y, X)`.
7718// Only `sub(X, Y)` (i.e. \p X is the *minuend*, the first operand) can be
7719// rewritten using the identity `X - 0 == X`. If \p X were the *subtrahend*
7720// (second operand, i.e. the pattern is actually `sub(Y, X)`), there is no
7721// way to express `cond ? (Y - X) : X` (or the symmetric case) as
7722// `X op (select ...)` without introducing an extra negation, so that case
7723// must be rejected instead of "optimized" into worse code.
7724static std::tuple<unsigned, SDValue, EVT>
7726 auto [Inner, ExtVT] = stripSignExtendInReg(BinV);
7727
7728 unsigned Opc = Inner.getOpcode();
7729 switch (Opc) {
7730 case ISD::ADD:
7731 case ISD::OR:
7732 case ISD::XOR:
7733 if (Inner.getOperand(0) == X)
7734 return {Opc, Inner.getOperand(1), ExtVT};
7735 if (Inner.getOperand(1) == X)
7736 return {Opc, Inner.getOperand(0), ExtVT};
7737 return {0, SDValue(), EVT()};
7738 case ISD::SUB:
7739 // Only accept X as the minuend (first operand); see comment above.
7740 if (Inner.getOperand(0) == X)
7741 return {Opc, Inner.getOperand(1), ExtVT};
7742 return {0, SDValue(), EVT()};
7743 default:
7744 return {0, SDValue(), EVT()};
7745 }
7746}
7747
7748// Try to combine:
7749// select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
7750// select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
7751// for binop in {add, or, xor, sub}, where 0 is the identity element of the
7752// respective operation, additionally handling the common legalized form
7753// where the binop result is wrapped in a `sign_extend_inreg` (as happens
7754// for sub-GRLen types such as i32 on a 64-bit GRLen target). See
7755// matchBinOpWithSharedOperand() for the restrictions applied to
7756// non-commutative operations (currently only `sub`).
7760 if (DCI.isBeforeLegalizeOps())
7761 return SDValue();
7762
7763 EVT VT = N->getValueType(0);
7764 // Restrict to the scalar GRLen integer type that maskeqz/masknez operate
7765 // on; this also naturally excludes float and vector selects.
7766 if (VT != Subtarget.getGRLenVT())
7767 return SDValue();
7768
7769 SDValue Cond = N->getOperand(0);
7770 SDValue TrueV = N->getOperand(1);
7771 SDValue FalseV = N->getOperand(2);
7772 SDLoc DL(N);
7773
7774 auto TryFold = [&](SDValue BinV, SDValue SharedV,
7775 bool BinIsTrueArm) -> SDValue {
7776 auto [Opc, Delta, ExtVT] = matchBinOpWithSharedOperand(BinV, SharedV);
7777 if (!Opc)
7778 return SDValue();
7779
7780 // Avoid infinite combine loops: bail out if Delta is trivially the
7781 // same node we would otherwise be selecting on (shouldn't normally
7782 // happen, but guards against degenerate/self-referential IR).
7783 if (Delta.getNode() == N)
7784 return SDValue();
7785
7786 SDValue Zero = DAG.getConstant(0, DL, VT);
7787 SDValue NewSel = BinIsTrueArm ? DAG.getSelect(DL, VT, Cond, Delta, Zero)
7788 : DAG.getSelect(DL, VT, Cond, Zero, Delta);
7789 SDValue NewBin = DAG.getNode(Opc, DL, VT, SharedV, NewSel);
7790
7791 // If the original binop result was normalized back into a narrower
7792 // type via sign_extend_inreg (e.g. i32 arithmetic on a 64-bit GRLen
7793 // target), the new binop must be re-normalized the same way: SharedV
7794 // is already known-sign-extended for that narrow type, but NewSel
7795 // (Delta or 0, selected) combined with SharedV via Opc can still
7796 // produce a 64-bit result whose high bits don't match the narrow
7797 // type's sign-extended representation.
7798 if (ExtVT != EVT())
7799 NewBin = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, NewBin,
7800 DAG.getValueType(ExtVT));
7801
7802 return NewBin;
7803 };
7804
7805 if (SDValue R = TryFold(TrueV, FalseV, /*BinIsTrueArm=*/true))
7806 return R;
7807 if (SDValue R = TryFold(FalseV, TrueV, /*BinIsTrueArm=*/false))
7808 return R;
7809
7810 return SDValue();
7811}
7812
7813// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7817 if (DCI.isBeforeLegalizeOps())
7818 return SDValue();
7819
7820 SDValue Src = N->getOperand(0);
7821 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7822 return SDValue();
7823
7824 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7825 Src.getOperand(0));
7826}
7827
7828// Perform common combines for BR_CC and SELECT_CC conditions.
7829static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7831 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7832
7833 // As far as arithmetic right shift always saves the sign,
7834 // shift can be omitted.
7835 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7836 // setge (sra X, N), 0 -> setge X, 0
7837 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7838 LHS.getOpcode() == ISD::SRA) {
7839 LHS = LHS.getOperand(0);
7840 return true;
7841 }
7842
7843 if (!ISD::isIntEqualitySetCC(CCVal))
7844 return false;
7845
7846 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7847 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7848 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7849 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7850 // If we're looking for eq 0 instead of ne 0, we need to invert the
7851 // condition.
7852 bool Invert = CCVal == ISD::SETEQ;
7853 CCVal = LHS.getOperandCondCode(2);
7854 if (Invert)
7855 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7856
7857 RHS = LHS.getOperand(1);
7858 LHS = LHS.getOperand(0);
7859 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7860
7861 CC = DAG.getCondCode(CCVal);
7862 return true;
7863 }
7864
7865 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7866 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7867 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7868 SDValue LHS0 = LHS.getOperand(0);
7869 if (LHS0.getOpcode() == ISD::AND &&
7870 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7871 uint64_t Mask = LHS0.getConstantOperandVal(1);
7872 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7873 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7874 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7875 CC = DAG.getCondCode(CCVal);
7876
7877 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7878 LHS = LHS0.getOperand(0);
7879 if (ShAmt != 0)
7880 LHS =
7881 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7882 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7883 return true;
7884 }
7885 }
7886 }
7887
7888 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7889 // This can occur when legalizing some floating point comparisons.
7890 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7891 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7892 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7893 CC = DAG.getCondCode(CCVal);
7894 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7895 return true;
7896 }
7897
7898 // Fold ((shl (extract_vector_elt X, I), GRLen - EleBits)), 0, eq/ne) ->
7899 // ((extract_vector_elt X, I), 0, eq/ne)
7900 if (isNullConstant(RHS) && (CCVal == ISD::SETEQ || CCVal == ISD::SETNE) &&
7901 LHS.getOpcode() == ISD::SHL && LHS.hasOneUse() &&
7902 isa<ConstantSDNode>(LHS.getOperand(1))) {
7903 SDValue Ext = LHS.getOperand(0);
7904 unsigned Sht = LHS.getConstantOperandVal(1);
7905 if (Ext.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
7906 SDValue Vec = Ext.getOperand(0);
7907 unsigned EleBits = Vec.getScalarValueSizeInBits();
7908 if ((EleBits + Sht) == Subtarget.getGRLen()) {
7909 LHS = Ext;
7910 return true;
7911 }
7912 }
7913 }
7914
7915 // Fold (C1, C2, cond) -> (0, 0, seteq/setne)
7917 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
7918 EVT VT = LHS.getValueType();
7919 EVT SetCCResVT =
7920 TLI->getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
7921 if (SDValue Folded = DAG.FoldSetCC(SetCCResVT, LHS, RHS, CCVal, DL)) {
7922 LHS = DAG.getConstant(0, DL, VT);
7923 RHS = DAG.getConstant(0, DL, VT);
7925 return true;
7926 }
7927 }
7928
7929 return false;
7930}
7931
7935 SDValue LHS = N->getOperand(1);
7936 SDValue RHS = N->getOperand(2);
7937 SDValue CC = N->getOperand(3);
7938 SDLoc DL(N);
7939
7940 // CC was folded into V, so always return ISD::SETNE is fine.
7942 DL, DAG, Subtarget))
7943 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7944 N->getOperand(0), V,
7945 DAG.getConstant(0, DL, Subtarget.getGRLenVT()),
7946 DAG.getCondCode(ISD::SETNE), N->getOperand(4));
7947
7948 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7949 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7950 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7951
7952 return SDValue();
7953}
7954
7958 // Transform
7959 SDValue LHS = N->getOperand(0);
7960 SDValue RHS = N->getOperand(1);
7961 SDValue CC = N->getOperand(2);
7962 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7963 SDValue TrueV = N->getOperand(3);
7964 SDValue FalseV = N->getOperand(4);
7965 SDLoc DL(N);
7966 EVT VT = N->getValueType(0);
7967
7968 // If the True and False values are the same, we don't need a select_cc.
7969 if (TrueV == FalseV)
7970 return TrueV;
7971
7972 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7973 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7974 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7976 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7977 if (CCVal == ISD::CondCode::SETGE)
7978 std::swap(TrueV, FalseV);
7979
7980 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7981 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7982 // Only handle simm12, if it is not in this range, it can be considered as
7983 // register.
7984 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7985 isInt<12>(TrueSImm - FalseSImm)) {
7986 SDValue SRA =
7987 DAG.getNode(ISD::SRA, DL, VT, LHS,
7988 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7989 SDValue AND =
7990 DAG.getNode(ISD::AND, DL, VT, SRA,
7991 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7992 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7993 }
7994
7995 if (CCVal == ISD::CondCode::SETGE)
7996 std::swap(TrueV, FalseV);
7997 }
7998
7999 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
8000 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
8001 {LHS, RHS, CC, TrueV, FalseV});
8002
8003 return SDValue();
8004}
8005
8006template <unsigned N>
8008 SelectionDAG &DAG,
8010 bool IsSigned = false) {
8011 SDLoc DL(Node);
8012 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
8013 // Check the ImmArg.
8014 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
8015 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
8016 DAG.getContext()->emitError(Node->getOperationName(0) +
8017 ": argument out of range.");
8018 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
8019 }
8020 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
8021}
8022
8023template <unsigned N>
8024static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
8025 SelectionDAG &DAG, bool IsSigned = false) {
8026 SDLoc DL(Node);
8027 EVT ResTy = Node->getValueType(0);
8028 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
8029
8030 // Check the ImmArg.
8031 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
8032 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
8033 DAG.getContext()->emitError(Node->getOperationName(0) +
8034 ": argument out of range.");
8035 return DAG.getNode(ISD::UNDEF, DL, ResTy);
8036 }
8037 return DAG.getConstant(
8039 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
8040 DL, ResTy);
8041}
8042
8044 SDLoc DL(Node);
8045 EVT ResTy = Node->getValueType(0);
8046 SDValue Vec = Node->getOperand(2);
8047 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
8048 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
8049}
8050
8052 SDLoc DL(Node);
8053 EVT ResTy = Node->getValueType(0);
8054 SDValue One = DAG.getConstant(1, DL, ResTy);
8055 SDValue Bit =
8056 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
8057
8058 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
8059 DAG.getNOT(DL, Bit, ResTy));
8060}
8061
8062template <unsigned N>
8064 SDLoc DL(Node);
8065 EVT ResTy = Node->getValueType(0);
8066 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
8067 // Check the unsigned ImmArg.
8068 if (!isUInt<N>(CImm->getZExtValue())) {
8069 DAG.getContext()->emitError(Node->getOperationName(0) +
8070 ": argument out of range.");
8071 return DAG.getNode(ISD::UNDEF, DL, ResTy);
8072 }
8073
8074 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
8075 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
8076
8077 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
8078}
8079
8080template <unsigned N>
8082 SDLoc DL(Node);
8083 EVT ResTy = Node->getValueType(0);
8084 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
8085 // Check the unsigned ImmArg.
8086 if (!isUInt<N>(CImm->getZExtValue())) {
8087 DAG.getContext()->emitError(Node->getOperationName(0) +
8088 ": argument out of range.");
8089 return DAG.getNode(ISD::UNDEF, DL, ResTy);
8090 }
8091
8092 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
8093 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
8094 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
8095}
8096
8097template <unsigned N>
8099 SDLoc DL(Node);
8100 EVT ResTy = Node->getValueType(0);
8101 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
8102 // Check the unsigned ImmArg.
8103 if (!isUInt<N>(CImm->getZExtValue())) {
8104 DAG.getContext()->emitError(Node->getOperationName(0) +
8105 ": argument out of range.");
8106 return DAG.getNode(ISD::UNDEF, DL, ResTy);
8107 }
8108
8109 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
8110 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
8111 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
8112}
8113
8114template <unsigned W>
8116 unsigned ResOp) {
8117 unsigned Imm = N->getConstantOperandVal(2);
8118 if (!isUInt<W>(Imm)) {
8119 const StringRef ErrorMsg = "argument out of range";
8120 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
8121 return DAG.getUNDEF(N->getValueType(0));
8122 }
8123 SDLoc DL(N);
8124 SDValue Vec = N->getOperand(1);
8125 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
8127 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
8128}
8129
8130static SDValue
8134 SDLoc DL(N);
8135 switch (N->getConstantOperandVal(0)) {
8136 default:
8137 break;
8138 case Intrinsic::loongarch_lsx_vadd_b:
8139 case Intrinsic::loongarch_lsx_vadd_h:
8140 case Intrinsic::loongarch_lsx_vadd_w:
8141 case Intrinsic::loongarch_lsx_vadd_d:
8142 case Intrinsic::loongarch_lasx_xvadd_b:
8143 case Intrinsic::loongarch_lasx_xvadd_h:
8144 case Intrinsic::loongarch_lasx_xvadd_w:
8145 case Intrinsic::loongarch_lasx_xvadd_d:
8146 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
8147 N->getOperand(2));
8148 case Intrinsic::loongarch_lsx_vaddi_bu:
8149 case Intrinsic::loongarch_lsx_vaddi_hu:
8150 case Intrinsic::loongarch_lsx_vaddi_wu:
8151 case Intrinsic::loongarch_lsx_vaddi_du:
8152 case Intrinsic::loongarch_lasx_xvaddi_bu:
8153 case Intrinsic::loongarch_lasx_xvaddi_hu:
8154 case Intrinsic::loongarch_lasx_xvaddi_wu:
8155 case Intrinsic::loongarch_lasx_xvaddi_du:
8156 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
8157 lowerVectorSplatImm<5>(N, 2, DAG));
8158 case Intrinsic::loongarch_lsx_vsub_b:
8159 case Intrinsic::loongarch_lsx_vsub_h:
8160 case Intrinsic::loongarch_lsx_vsub_w:
8161 case Intrinsic::loongarch_lsx_vsub_d:
8162 case Intrinsic::loongarch_lasx_xvsub_b:
8163 case Intrinsic::loongarch_lasx_xvsub_h:
8164 case Intrinsic::loongarch_lasx_xvsub_w:
8165 case Intrinsic::loongarch_lasx_xvsub_d:
8166 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
8167 N->getOperand(2));
8168 case Intrinsic::loongarch_lsx_vsubi_bu:
8169 case Intrinsic::loongarch_lsx_vsubi_hu:
8170 case Intrinsic::loongarch_lsx_vsubi_wu:
8171 case Intrinsic::loongarch_lsx_vsubi_du:
8172 case Intrinsic::loongarch_lasx_xvsubi_bu:
8173 case Intrinsic::loongarch_lasx_xvsubi_hu:
8174 case Intrinsic::loongarch_lasx_xvsubi_wu:
8175 case Intrinsic::loongarch_lasx_xvsubi_du:
8176 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
8177 lowerVectorSplatImm<5>(N, 2, DAG));
8178 case Intrinsic::loongarch_lsx_vneg_b:
8179 case Intrinsic::loongarch_lsx_vneg_h:
8180 case Intrinsic::loongarch_lsx_vneg_w:
8181 case Intrinsic::loongarch_lsx_vneg_d:
8182 case Intrinsic::loongarch_lasx_xvneg_b:
8183 case Intrinsic::loongarch_lasx_xvneg_h:
8184 case Intrinsic::loongarch_lasx_xvneg_w:
8185 case Intrinsic::loongarch_lasx_xvneg_d:
8186 return DAG.getNode(
8187 ISD::SUB, DL, N->getValueType(0),
8188 DAG.getConstant(
8189 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
8190 /*isSigned=*/true),
8191 SDLoc(N), N->getValueType(0)),
8192 N->getOperand(1));
8193 case Intrinsic::loongarch_lsx_vmax_b:
8194 case Intrinsic::loongarch_lsx_vmax_h:
8195 case Intrinsic::loongarch_lsx_vmax_w:
8196 case Intrinsic::loongarch_lsx_vmax_d:
8197 case Intrinsic::loongarch_lasx_xvmax_b:
8198 case Intrinsic::loongarch_lasx_xvmax_h:
8199 case Intrinsic::loongarch_lasx_xvmax_w:
8200 case Intrinsic::loongarch_lasx_xvmax_d:
8201 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
8202 N->getOperand(2));
8203 case Intrinsic::loongarch_lsx_vmax_bu:
8204 case Intrinsic::loongarch_lsx_vmax_hu:
8205 case Intrinsic::loongarch_lsx_vmax_wu:
8206 case Intrinsic::loongarch_lsx_vmax_du:
8207 case Intrinsic::loongarch_lasx_xvmax_bu:
8208 case Intrinsic::loongarch_lasx_xvmax_hu:
8209 case Intrinsic::loongarch_lasx_xvmax_wu:
8210 case Intrinsic::loongarch_lasx_xvmax_du:
8211 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
8212 N->getOperand(2));
8213 case Intrinsic::loongarch_lsx_vmaxi_b:
8214 case Intrinsic::loongarch_lsx_vmaxi_h:
8215 case Intrinsic::loongarch_lsx_vmaxi_w:
8216 case Intrinsic::loongarch_lsx_vmaxi_d:
8217 case Intrinsic::loongarch_lasx_xvmaxi_b:
8218 case Intrinsic::loongarch_lasx_xvmaxi_h:
8219 case Intrinsic::loongarch_lasx_xvmaxi_w:
8220 case Intrinsic::loongarch_lasx_xvmaxi_d:
8221 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
8222 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
8223 case Intrinsic::loongarch_lsx_vmaxi_bu:
8224 case Intrinsic::loongarch_lsx_vmaxi_hu:
8225 case Intrinsic::loongarch_lsx_vmaxi_wu:
8226 case Intrinsic::loongarch_lsx_vmaxi_du:
8227 case Intrinsic::loongarch_lasx_xvmaxi_bu:
8228 case Intrinsic::loongarch_lasx_xvmaxi_hu:
8229 case Intrinsic::loongarch_lasx_xvmaxi_wu:
8230 case Intrinsic::loongarch_lasx_xvmaxi_du:
8231 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
8232 lowerVectorSplatImm<5>(N, 2, DAG));
8233 case Intrinsic::loongarch_lsx_vmin_b:
8234 case Intrinsic::loongarch_lsx_vmin_h:
8235 case Intrinsic::loongarch_lsx_vmin_w:
8236 case Intrinsic::loongarch_lsx_vmin_d:
8237 case Intrinsic::loongarch_lasx_xvmin_b:
8238 case Intrinsic::loongarch_lasx_xvmin_h:
8239 case Intrinsic::loongarch_lasx_xvmin_w:
8240 case Intrinsic::loongarch_lasx_xvmin_d:
8241 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
8242 N->getOperand(2));
8243 case Intrinsic::loongarch_lsx_vmin_bu:
8244 case Intrinsic::loongarch_lsx_vmin_hu:
8245 case Intrinsic::loongarch_lsx_vmin_wu:
8246 case Intrinsic::loongarch_lsx_vmin_du:
8247 case Intrinsic::loongarch_lasx_xvmin_bu:
8248 case Intrinsic::loongarch_lasx_xvmin_hu:
8249 case Intrinsic::loongarch_lasx_xvmin_wu:
8250 case Intrinsic::loongarch_lasx_xvmin_du:
8251 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
8252 N->getOperand(2));
8253 case Intrinsic::loongarch_lsx_vmini_b:
8254 case Intrinsic::loongarch_lsx_vmini_h:
8255 case Intrinsic::loongarch_lsx_vmini_w:
8256 case Intrinsic::loongarch_lsx_vmini_d:
8257 case Intrinsic::loongarch_lasx_xvmini_b:
8258 case Intrinsic::loongarch_lasx_xvmini_h:
8259 case Intrinsic::loongarch_lasx_xvmini_w:
8260 case Intrinsic::loongarch_lasx_xvmini_d:
8261 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
8262 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
8263 case Intrinsic::loongarch_lsx_vmini_bu:
8264 case Intrinsic::loongarch_lsx_vmini_hu:
8265 case Intrinsic::loongarch_lsx_vmini_wu:
8266 case Intrinsic::loongarch_lsx_vmini_du:
8267 case Intrinsic::loongarch_lasx_xvmini_bu:
8268 case Intrinsic::loongarch_lasx_xvmini_hu:
8269 case Intrinsic::loongarch_lasx_xvmini_wu:
8270 case Intrinsic::loongarch_lasx_xvmini_du:
8271 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
8272 lowerVectorSplatImm<5>(N, 2, DAG));
8273 case Intrinsic::loongarch_lsx_vmul_b:
8274 case Intrinsic::loongarch_lsx_vmul_h:
8275 case Intrinsic::loongarch_lsx_vmul_w:
8276 case Intrinsic::loongarch_lsx_vmul_d:
8277 case Intrinsic::loongarch_lasx_xvmul_b:
8278 case Intrinsic::loongarch_lasx_xvmul_h:
8279 case Intrinsic::loongarch_lasx_xvmul_w:
8280 case Intrinsic::loongarch_lasx_xvmul_d:
8281 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
8282 N->getOperand(2));
8283 case Intrinsic::loongarch_lsx_vmadd_b:
8284 case Intrinsic::loongarch_lsx_vmadd_h:
8285 case Intrinsic::loongarch_lsx_vmadd_w:
8286 case Intrinsic::loongarch_lsx_vmadd_d:
8287 case Intrinsic::loongarch_lasx_xvmadd_b:
8288 case Intrinsic::loongarch_lasx_xvmadd_h:
8289 case Intrinsic::loongarch_lasx_xvmadd_w:
8290 case Intrinsic::loongarch_lasx_xvmadd_d: {
8291 EVT ResTy = N->getValueType(0);
8292 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
8293 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
8294 N->getOperand(3)));
8295 }
8296 case Intrinsic::loongarch_lsx_vmsub_b:
8297 case Intrinsic::loongarch_lsx_vmsub_h:
8298 case Intrinsic::loongarch_lsx_vmsub_w:
8299 case Intrinsic::loongarch_lsx_vmsub_d:
8300 case Intrinsic::loongarch_lasx_xvmsub_b:
8301 case Intrinsic::loongarch_lasx_xvmsub_h:
8302 case Intrinsic::loongarch_lasx_xvmsub_w:
8303 case Intrinsic::loongarch_lasx_xvmsub_d: {
8304 EVT ResTy = N->getValueType(0);
8305 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
8306 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
8307 N->getOperand(3)));
8308 }
8309 case Intrinsic::loongarch_lsx_vdiv_b:
8310 case Intrinsic::loongarch_lsx_vdiv_h:
8311 case Intrinsic::loongarch_lsx_vdiv_w:
8312 case Intrinsic::loongarch_lsx_vdiv_d:
8313 case Intrinsic::loongarch_lasx_xvdiv_b:
8314 case Intrinsic::loongarch_lasx_xvdiv_h:
8315 case Intrinsic::loongarch_lasx_xvdiv_w:
8316 case Intrinsic::loongarch_lasx_xvdiv_d:
8317 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
8318 N->getOperand(2));
8319 case Intrinsic::loongarch_lsx_vdiv_bu:
8320 case Intrinsic::loongarch_lsx_vdiv_hu:
8321 case Intrinsic::loongarch_lsx_vdiv_wu:
8322 case Intrinsic::loongarch_lsx_vdiv_du:
8323 case Intrinsic::loongarch_lasx_xvdiv_bu:
8324 case Intrinsic::loongarch_lasx_xvdiv_hu:
8325 case Intrinsic::loongarch_lasx_xvdiv_wu:
8326 case Intrinsic::loongarch_lasx_xvdiv_du:
8327 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
8328 N->getOperand(2));
8329 case Intrinsic::loongarch_lsx_vmod_b:
8330 case Intrinsic::loongarch_lsx_vmod_h:
8331 case Intrinsic::loongarch_lsx_vmod_w:
8332 case Intrinsic::loongarch_lsx_vmod_d:
8333 case Intrinsic::loongarch_lasx_xvmod_b:
8334 case Intrinsic::loongarch_lasx_xvmod_h:
8335 case Intrinsic::loongarch_lasx_xvmod_w:
8336 case Intrinsic::loongarch_lasx_xvmod_d:
8337 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
8338 N->getOperand(2));
8339 case Intrinsic::loongarch_lsx_vmod_bu:
8340 case Intrinsic::loongarch_lsx_vmod_hu:
8341 case Intrinsic::loongarch_lsx_vmod_wu:
8342 case Intrinsic::loongarch_lsx_vmod_du:
8343 case Intrinsic::loongarch_lasx_xvmod_bu:
8344 case Intrinsic::loongarch_lasx_xvmod_hu:
8345 case Intrinsic::loongarch_lasx_xvmod_wu:
8346 case Intrinsic::loongarch_lasx_xvmod_du:
8347 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
8348 N->getOperand(2));
8349 case Intrinsic::loongarch_lsx_vand_v:
8350 case Intrinsic::loongarch_lasx_xvand_v:
8351 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8352 N->getOperand(2));
8353 case Intrinsic::loongarch_lsx_vor_v:
8354 case Intrinsic::loongarch_lasx_xvor_v:
8355 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8356 N->getOperand(2));
8357 case Intrinsic::loongarch_lsx_vxor_v:
8358 case Intrinsic::loongarch_lasx_xvxor_v:
8359 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8360 N->getOperand(2));
8361 case Intrinsic::loongarch_lsx_vnor_v:
8362 case Intrinsic::loongarch_lasx_xvnor_v: {
8363 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8364 N->getOperand(2));
8365 return DAG.getNOT(DL, Res, Res->getValueType(0));
8366 }
8367 case Intrinsic::loongarch_lsx_vandi_b:
8368 case Intrinsic::loongarch_lasx_xvandi_b:
8369 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
8370 lowerVectorSplatImm<8>(N, 2, DAG));
8371 case Intrinsic::loongarch_lsx_vori_b:
8372 case Intrinsic::loongarch_lasx_xvori_b:
8373 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
8374 lowerVectorSplatImm<8>(N, 2, DAG));
8375 case Intrinsic::loongarch_lsx_vxori_b:
8376 case Intrinsic::loongarch_lasx_xvxori_b:
8377 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
8378 lowerVectorSplatImm<8>(N, 2, DAG));
8379 case Intrinsic::loongarch_lsx_vsll_b:
8380 case Intrinsic::loongarch_lsx_vsll_h:
8381 case Intrinsic::loongarch_lsx_vsll_w:
8382 case Intrinsic::loongarch_lsx_vsll_d:
8383 case Intrinsic::loongarch_lasx_xvsll_b:
8384 case Intrinsic::loongarch_lasx_xvsll_h:
8385 case Intrinsic::loongarch_lasx_xvsll_w:
8386 case Intrinsic::loongarch_lasx_xvsll_d:
8387 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8388 truncateVecElts(N, DAG));
8389 case Intrinsic::loongarch_lsx_vslli_b:
8390 case Intrinsic::loongarch_lasx_xvslli_b:
8391 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8392 lowerVectorSplatImm<3>(N, 2, DAG));
8393 case Intrinsic::loongarch_lsx_vslli_h:
8394 case Intrinsic::loongarch_lasx_xvslli_h:
8395 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8396 lowerVectorSplatImm<4>(N, 2, DAG));
8397 case Intrinsic::loongarch_lsx_vslli_w:
8398 case Intrinsic::loongarch_lasx_xvslli_w:
8399 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8400 lowerVectorSplatImm<5>(N, 2, DAG));
8401 case Intrinsic::loongarch_lsx_vslli_d:
8402 case Intrinsic::loongarch_lasx_xvslli_d:
8403 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
8404 lowerVectorSplatImm<6>(N, 2, DAG));
8405 case Intrinsic::loongarch_lsx_vsrl_b:
8406 case Intrinsic::loongarch_lsx_vsrl_h:
8407 case Intrinsic::loongarch_lsx_vsrl_w:
8408 case Intrinsic::loongarch_lsx_vsrl_d:
8409 case Intrinsic::loongarch_lasx_xvsrl_b:
8410 case Intrinsic::loongarch_lasx_xvsrl_h:
8411 case Intrinsic::loongarch_lasx_xvsrl_w:
8412 case Intrinsic::loongarch_lasx_xvsrl_d:
8413 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8414 truncateVecElts(N, DAG));
8415 case Intrinsic::loongarch_lsx_vsrli_b:
8416 case Intrinsic::loongarch_lasx_xvsrli_b:
8417 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8418 lowerVectorSplatImm<3>(N, 2, DAG));
8419 case Intrinsic::loongarch_lsx_vsrli_h:
8420 case Intrinsic::loongarch_lasx_xvsrli_h:
8421 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8422 lowerVectorSplatImm<4>(N, 2, DAG));
8423 case Intrinsic::loongarch_lsx_vsrli_w:
8424 case Intrinsic::loongarch_lasx_xvsrli_w:
8425 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8426 lowerVectorSplatImm<5>(N, 2, DAG));
8427 case Intrinsic::loongarch_lsx_vsrli_d:
8428 case Intrinsic::loongarch_lasx_xvsrli_d:
8429 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8430 lowerVectorSplatImm<6>(N, 2, DAG));
8431 case Intrinsic::loongarch_lsx_vsra_b:
8432 case Intrinsic::loongarch_lsx_vsra_h:
8433 case Intrinsic::loongarch_lsx_vsra_w:
8434 case Intrinsic::loongarch_lsx_vsra_d:
8435 case Intrinsic::loongarch_lasx_xvsra_b:
8436 case Intrinsic::loongarch_lasx_xvsra_h:
8437 case Intrinsic::loongarch_lasx_xvsra_w:
8438 case Intrinsic::loongarch_lasx_xvsra_d:
8439 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8440 truncateVecElts(N, DAG));
8441 case Intrinsic::loongarch_lsx_vsrai_b:
8442 case Intrinsic::loongarch_lasx_xvsrai_b:
8443 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8444 lowerVectorSplatImm<3>(N, 2, DAG));
8445 case Intrinsic::loongarch_lsx_vsrai_h:
8446 case Intrinsic::loongarch_lasx_xvsrai_h:
8447 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8448 lowerVectorSplatImm<4>(N, 2, DAG));
8449 case Intrinsic::loongarch_lsx_vsrai_w:
8450 case Intrinsic::loongarch_lasx_xvsrai_w:
8451 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8452 lowerVectorSplatImm<5>(N, 2, DAG));
8453 case Intrinsic::loongarch_lsx_vsrai_d:
8454 case Intrinsic::loongarch_lasx_xvsrai_d:
8455 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8456 lowerVectorSplatImm<6>(N, 2, DAG));
8457 case Intrinsic::loongarch_lsx_vclz_b:
8458 case Intrinsic::loongarch_lsx_vclz_h:
8459 case Intrinsic::loongarch_lsx_vclz_w:
8460 case Intrinsic::loongarch_lsx_vclz_d:
8461 case Intrinsic::loongarch_lasx_xvclz_b:
8462 case Intrinsic::loongarch_lasx_xvclz_h:
8463 case Intrinsic::loongarch_lasx_xvclz_w:
8464 case Intrinsic::loongarch_lasx_xvclz_d:
8465 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
8466 case Intrinsic::loongarch_lsx_vpcnt_b:
8467 case Intrinsic::loongarch_lsx_vpcnt_h:
8468 case Intrinsic::loongarch_lsx_vpcnt_w:
8469 case Intrinsic::loongarch_lsx_vpcnt_d:
8470 case Intrinsic::loongarch_lasx_xvpcnt_b:
8471 case Intrinsic::loongarch_lasx_xvpcnt_h:
8472 case Intrinsic::loongarch_lasx_xvpcnt_w:
8473 case Intrinsic::loongarch_lasx_xvpcnt_d:
8474 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
8475 case Intrinsic::loongarch_lsx_vbitclr_b:
8476 case Intrinsic::loongarch_lsx_vbitclr_h:
8477 case Intrinsic::loongarch_lsx_vbitclr_w:
8478 case Intrinsic::loongarch_lsx_vbitclr_d:
8479 case Intrinsic::loongarch_lasx_xvbitclr_b:
8480 case Intrinsic::loongarch_lasx_xvbitclr_h:
8481 case Intrinsic::loongarch_lasx_xvbitclr_w:
8482 case Intrinsic::loongarch_lasx_xvbitclr_d:
8483 return lowerVectorBitClear(N, DAG);
8484 case Intrinsic::loongarch_lsx_vbitclri_b:
8485 case Intrinsic::loongarch_lasx_xvbitclri_b:
8486 return lowerVectorBitClearImm<3>(N, DAG);
8487 case Intrinsic::loongarch_lsx_vbitclri_h:
8488 case Intrinsic::loongarch_lasx_xvbitclri_h:
8489 return lowerVectorBitClearImm<4>(N, DAG);
8490 case Intrinsic::loongarch_lsx_vbitclri_w:
8491 case Intrinsic::loongarch_lasx_xvbitclri_w:
8492 return lowerVectorBitClearImm<5>(N, DAG);
8493 case Intrinsic::loongarch_lsx_vbitclri_d:
8494 case Intrinsic::loongarch_lasx_xvbitclri_d:
8495 return lowerVectorBitClearImm<6>(N, DAG);
8496 case Intrinsic::loongarch_lsx_vbitset_b:
8497 case Intrinsic::loongarch_lsx_vbitset_h:
8498 case Intrinsic::loongarch_lsx_vbitset_w:
8499 case Intrinsic::loongarch_lsx_vbitset_d:
8500 case Intrinsic::loongarch_lasx_xvbitset_b:
8501 case Intrinsic::loongarch_lasx_xvbitset_h:
8502 case Intrinsic::loongarch_lasx_xvbitset_w:
8503 case Intrinsic::loongarch_lasx_xvbitset_d: {
8504 EVT VecTy = N->getValueType(0);
8505 SDValue One = DAG.getConstant(1, DL, VecTy);
8506 return DAG.getNode(
8507 ISD::OR, DL, VecTy, N->getOperand(1),
8508 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8509 }
8510 case Intrinsic::loongarch_lsx_vbitseti_b:
8511 case Intrinsic::loongarch_lasx_xvbitseti_b:
8512 return lowerVectorBitSetImm<3>(N, DAG);
8513 case Intrinsic::loongarch_lsx_vbitseti_h:
8514 case Intrinsic::loongarch_lasx_xvbitseti_h:
8515 return lowerVectorBitSetImm<4>(N, DAG);
8516 case Intrinsic::loongarch_lsx_vbitseti_w:
8517 case Intrinsic::loongarch_lasx_xvbitseti_w:
8518 return lowerVectorBitSetImm<5>(N, DAG);
8519 case Intrinsic::loongarch_lsx_vbitseti_d:
8520 case Intrinsic::loongarch_lasx_xvbitseti_d:
8521 return lowerVectorBitSetImm<6>(N, DAG);
8522 case Intrinsic::loongarch_lsx_vbitrev_b:
8523 case Intrinsic::loongarch_lsx_vbitrev_h:
8524 case Intrinsic::loongarch_lsx_vbitrev_w:
8525 case Intrinsic::loongarch_lsx_vbitrev_d:
8526 case Intrinsic::loongarch_lasx_xvbitrev_b:
8527 case Intrinsic::loongarch_lasx_xvbitrev_h:
8528 case Intrinsic::loongarch_lasx_xvbitrev_w:
8529 case Intrinsic::loongarch_lasx_xvbitrev_d: {
8530 EVT VecTy = N->getValueType(0);
8531 SDValue One = DAG.getConstant(1, DL, VecTy);
8532 return DAG.getNode(
8533 ISD::XOR, DL, VecTy, N->getOperand(1),
8534 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8535 }
8536 case Intrinsic::loongarch_lsx_vbitrevi_b:
8537 case Intrinsic::loongarch_lasx_xvbitrevi_b:
8538 return lowerVectorBitRevImm<3>(N, DAG);
8539 case Intrinsic::loongarch_lsx_vbitrevi_h:
8540 case Intrinsic::loongarch_lasx_xvbitrevi_h:
8541 return lowerVectorBitRevImm<4>(N, DAG);
8542 case Intrinsic::loongarch_lsx_vbitrevi_w:
8543 case Intrinsic::loongarch_lasx_xvbitrevi_w:
8544 return lowerVectorBitRevImm<5>(N, DAG);
8545 case Intrinsic::loongarch_lsx_vbitrevi_d:
8546 case Intrinsic::loongarch_lasx_xvbitrevi_d:
8547 return lowerVectorBitRevImm<6>(N, DAG);
8548 case Intrinsic::loongarch_lsx_vfadd_s:
8549 case Intrinsic::loongarch_lsx_vfadd_d:
8550 case Intrinsic::loongarch_lasx_xvfadd_s:
8551 case Intrinsic::loongarch_lasx_xvfadd_d:
8552 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
8553 N->getOperand(2));
8554 case Intrinsic::loongarch_lsx_vfsub_s:
8555 case Intrinsic::loongarch_lsx_vfsub_d:
8556 case Intrinsic::loongarch_lasx_xvfsub_s:
8557 case Intrinsic::loongarch_lasx_xvfsub_d:
8558 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
8559 N->getOperand(2));
8560 case Intrinsic::loongarch_lsx_vfmul_s:
8561 case Intrinsic::loongarch_lsx_vfmul_d:
8562 case Intrinsic::loongarch_lasx_xvfmul_s:
8563 case Intrinsic::loongarch_lasx_xvfmul_d:
8564 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
8565 N->getOperand(2));
8566 case Intrinsic::loongarch_lsx_vfdiv_s:
8567 case Intrinsic::loongarch_lsx_vfdiv_d:
8568 case Intrinsic::loongarch_lasx_xvfdiv_s:
8569 case Intrinsic::loongarch_lasx_xvfdiv_d:
8570 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
8571 N->getOperand(2));
8572 case Intrinsic::loongarch_lsx_vfmadd_s:
8573 case Intrinsic::loongarch_lsx_vfmadd_d:
8574 case Intrinsic::loongarch_lasx_xvfmadd_s:
8575 case Intrinsic::loongarch_lasx_xvfmadd_d:
8576 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
8577 N->getOperand(2), N->getOperand(3));
8578 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
8579 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8580 N->getOperand(1), N->getOperand(2),
8582 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
8583 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
8584 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8585 N->getOperand(1), N->getOperand(2),
8587 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
8588 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
8589 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8590 N->getOperand(1), N->getOperand(2),
8592 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
8593 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8594 N->getOperand(1), N->getOperand(2),
8596 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
8597 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
8598 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
8599 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
8600 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
8601 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
8602 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
8603 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
8604 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
8605 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8606 N->getOperand(1)));
8607 case Intrinsic::loongarch_lsx_vreplve_b:
8608 case Intrinsic::loongarch_lsx_vreplve_h:
8609 case Intrinsic::loongarch_lsx_vreplve_w:
8610 case Intrinsic::loongarch_lsx_vreplve_d:
8611 case Intrinsic::loongarch_lasx_xvreplve_b:
8612 case Intrinsic::loongarch_lasx_xvreplve_h:
8613 case Intrinsic::loongarch_lasx_xvreplve_w:
8614 case Intrinsic::loongarch_lasx_xvreplve_d:
8615 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
8616 N->getOperand(1),
8617 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8618 N->getOperand(2)));
8619 case Intrinsic::loongarch_lsx_vpickve2gr_b:
8620 if (!Subtarget.is64Bit())
8621 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8622 break;
8623 case Intrinsic::loongarch_lsx_vpickve2gr_h:
8624 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
8625 if (!Subtarget.is64Bit())
8626 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8627 break;
8628 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8629 if (!Subtarget.is64Bit())
8630 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8631 break;
8632 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8633 if (!Subtarget.is64Bit())
8634 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8635 break;
8636 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8637 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8638 if (!Subtarget.is64Bit())
8639 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8640 break;
8641 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8642 if (!Subtarget.is64Bit())
8643 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8644 break;
8645 case Intrinsic::loongarch_lsx_bz_b:
8646 case Intrinsic::loongarch_lsx_bz_h:
8647 case Intrinsic::loongarch_lsx_bz_w:
8648 case Intrinsic::loongarch_lsx_bz_d:
8649 case Intrinsic::loongarch_lasx_xbz_b:
8650 case Intrinsic::loongarch_lasx_xbz_h:
8651 case Intrinsic::loongarch_lasx_xbz_w:
8652 case Intrinsic::loongarch_lasx_xbz_d:
8653 if (!Subtarget.is64Bit())
8654 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8655 N->getOperand(1));
8656 break;
8657 case Intrinsic::loongarch_lsx_bz_v:
8658 case Intrinsic::loongarch_lasx_xbz_v:
8659 if (!Subtarget.is64Bit())
8660 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8661 N->getOperand(1));
8662 break;
8663 case Intrinsic::loongarch_lsx_bnz_b:
8664 case Intrinsic::loongarch_lsx_bnz_h:
8665 case Intrinsic::loongarch_lsx_bnz_w:
8666 case Intrinsic::loongarch_lsx_bnz_d:
8667 case Intrinsic::loongarch_lasx_xbnz_b:
8668 case Intrinsic::loongarch_lasx_xbnz_h:
8669 case Intrinsic::loongarch_lasx_xbnz_w:
8670 case Intrinsic::loongarch_lasx_xbnz_d:
8671 if (!Subtarget.is64Bit())
8672 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8673 N->getOperand(1));
8674 break;
8675 case Intrinsic::loongarch_lsx_bnz_v:
8676 case Intrinsic::loongarch_lasx_xbnz_v:
8677 if (!Subtarget.is64Bit())
8678 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8679 N->getOperand(1));
8680 break;
8681 case Intrinsic::loongarch_lasx_concat_128_s:
8682 case Intrinsic::loongarch_lasx_concat_128_d:
8683 case Intrinsic::loongarch_lasx_concat_128:
8684 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8685 N->getOperand(1), N->getOperand(2));
8686 }
8687 return SDValue();
8688}
8689
8693 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8694 // conversion is unnecessary and can be replaced with the
8695 // MOVFR2GR_S_LA64 operand.
8696 SDValue Op0 = N->getOperand(0);
8697 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8698 return Op0.getOperand(0);
8699 return SDValue();
8700}
8701
8705 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8706 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8707 // operand.
8708 SDValue Op0 = N->getOperand(0);
8709 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8710 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8711 "Unexpected value type!");
8712 return Op0.getOperand(0);
8713 }
8714 return SDValue();
8715}
8716
8717static SDValue
8720 MVT VT = N->getSimpleValueType(0);
8721 unsigned NumBits = VT.getScalarSizeInBits();
8722
8723 // Simplify the inputs.
8725 APInt DemandedMask(APInt::getAllOnes(NumBits));
8726 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8727 return SDValue(N, 0);
8728
8729 return SDValue();
8730}
8731
8732static SDValue
8736 SDValue Op0 = N->getOperand(0);
8737 SDLoc DL(N);
8738
8739 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8740 // redundant. Instead, use BuildPairF64's operands directly.
8741 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8742 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8743
8744 if (Op0->isUndef()) {
8745 SDValue Lo = DAG.getUNDEF(MVT::i32);
8746 SDValue Hi = DAG.getUNDEF(MVT::i32);
8747 return DCI.CombineTo(N, Lo, Hi);
8748 }
8749
8750 // It's cheaper to materialise two 32-bit integers than to load a double
8751 // from the constant pool and transfer it to integer registers through the
8752 // stack.
8754 APInt V = C->getValueAPF().bitcastToAPInt();
8755 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8756 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8757 return DCI.CombineTo(N, Lo, Hi);
8758 }
8759
8760 return SDValue();
8761}
8762
8763/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8767 SDValue N0 = N->getOperand(0);
8768 SDValue N1 = N->getOperand(1);
8769 MVT VT = N->getSimpleValueType(0);
8770 SDLoc DL(N);
8771
8772 // VANDN(undef, x) -> 0
8773 // VANDN(x, undef) -> 0
8774 if (N0.isUndef() || N1.isUndef())
8775 return DAG.getConstant(0, DL, VT);
8776
8777 // VANDN(0, x) -> x
8779 return N1;
8780
8781 // VANDN(x, 0) -> 0
8783 return DAG.getConstant(0, DL, VT);
8784
8785 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8787 return DAG.getNOT(DL, N0, VT);
8788
8789 // Turn VANDN back to AND if input is inverted.
8790 if (SDValue Not = isNOT(N0, DAG))
8791 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8792
8793 // VANDN(bitcast(shl(splat(1), y)), x)
8794 // -> bitcast(VANDN(shl(splat(1), y), bitcast(x)))
8795 // Perform the VANDN in the element type of the shift so that it can be
8796 // selected as [x]vbitclr.{b/h/w/d}.
8797 if (N0.getOpcode() == ISD::BITCAST && N0.hasOneUse()) {
8798 SDValue Shl = N0.getOperand(0);
8799 EVT ShlVT = Shl.getValueType();
8800 APInt SplatVal;
8801 if (Shl.getOpcode() == ISD::SHL && ShlVT.isVector() && ShlVT.isInteger() &&
8802 ShlVT != VT && ShlVT.getSizeInBits() == VT.getSizeInBits() &&
8803 DAG.getTargetLoweringInfo().isTypeLegal(ShlVT) &&
8804 ISD::isConstantSplatVector(Shl.getOperand(0).getNode(), SplatVal) &&
8805 SplatVal.isOne()) {
8806 SDValue V = DAG.getNode(LoongArchISD::VANDN, DL, ShlVT, Shl,
8807 DAG.getBitcast(ShlVT, N1));
8808 return DAG.getBitcast(VT, V);
8809 }
8810 }
8811
8812 // Folds for better commutativity:
8813 if (N1->hasOneUse()) {
8814 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8815 if (SDValue Not = isNOT(N1, DAG))
8816 return DAG.getNOT(
8817 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8818
8819 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8820 // -> NOT(OR(x, SplatVector(-Imm))
8821 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8822 // gain benefits.
8823 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8824 N1.getOpcode() == ISD::BUILD_VECTOR) {
8825 if (SDValue SplatValue =
8826 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8827 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8828 return SDValue();
8829
8830 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8831 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8832 SDValue Not =
8833 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8834 return DAG.getNOT(
8835 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8836 VT);
8837 }
8838 }
8839 }
8840 }
8841
8842 return SDValue();
8843}
8844
8845static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8846 SDLoc DL(N);
8847 EVT VT = N->getValueType(0);
8848 SDValue Src = N->getOperand(0);
8849 EVT SrcVT = Src.getValueType();
8850
8851 unsigned DstElts = VT.getVectorNumElements();
8852 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8853 unsigned DstEltBits = VT.getScalarSizeInBits();
8854
8855 if (SrcEltBits >= DstEltBits)
8856 return SDValue();
8857
8858 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8859 EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
8860
8861 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8862 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8863}
8864
8865// Merge two 64 to 32 convert instructions into one,
8866// e.g.
8867// vffint.s.l $vr0, $vr1, $vr2
8868// will convert 4 si64 into 4 float at once.
8869// or
8870// vftintrz.w.d $vr0, $vr1, $vr2
8871// which will convert 4 double into 4 si32 at once.
8872// also deal with their 256-bits LASX version.
8873static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8874 unsigned BlockBits) {
8875 SDLoc DL(N);
8876 MVT DstVT = N->getSimpleValueType(0);
8877 SDValue Src = N->getOperand(0);
8878 MVT SrcVT = Src.getSimpleValueType();
8879 unsigned SrcBits = SrcVT.getSizeInBits();
8880
8882 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8883 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8884 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8885 Src.getOperand(0).getValueType() == BlockVT) {
8886 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8887 Blocks.push_back(Src.getOperand(i));
8888 } else if (SrcBits > BlockBits) {
8889 // Wider than one register: extract each BlockBits-wide sub-vector.
8890 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8891 Blocks.push_back(
8892 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8893 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8894 } else {
8895 BlockBits = SrcBits;
8896 Blocks.push_back(Src);
8897 }
8898
8899 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8900 BlockBits / DstVT.getScalarSizeInBits());
8902 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8903 SDValue Lo = Blocks[i];
8904 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8905 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8906
8907 if (BlockBits == 256) {
8908 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8909 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8910 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8911 Res = DAG.getBitcast(NativeVecVT, Res);
8912 }
8913
8914 Parts.push_back(Res);
8915 }
8916
8917 if (Blocks.size() == 1)
8918 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8919 DAG.getVectorIdxConstant(0, DL));
8920 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8921}
8922
8926 SDLoc DL(N);
8927 EVT VT = N->getValueType(0);
8928 SDValue Src = N->getOperand(0);
8929 EVT SrcVT = Src.getValueType();
8930
8931 if (VT.isVector()) {
8932 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8933 unsigned DstEltBits = VT.getScalarSizeInBits();
8934 unsigned NumElts = VT.getVectorNumElements();
8935 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8936
8937 // Sign-extend src to avoid scalarization.
8938 if (SrcEltBits <= DstEltBits)
8939 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8940
8941 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8942 return SDValue();
8943
8944 if (!SrcVT.isSimple() || !VT.isSimple())
8945 return SDValue();
8946
8947 // [x]vffint.s.l needs LSX and at least one full 128-bit source register.
8948 if (!Subtarget.hasExtLSX() || SrcVT.getSizeInBits() < 128)
8949 return SDValue();
8950
8951 // Combine [x]vffint.s.l for vector si64 to float conversion.
8952 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8953 }
8954
8955 if (VT != MVT::f32 && VT != MVT::f64)
8956 return SDValue();
8957 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8958 return SDValue();
8959 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8960 return SDValue();
8961
8962 // Only optimize when the source and destination types have the same width.
8963 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8964 return SDValue();
8965
8966 // If the result of an integer load is only used by an integer-to-float
8967 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8968 // (movgr2fr) instruction.
8969 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8970 // Do not change the width of a volatile load. This condition check is
8971 // inspired by AArch64.
8972 !cast<LoadSDNode>(Src)->isVolatile()) {
8973 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8974 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8975 LN0->getPointerInfo(), LN0->getAlign(),
8976 LN0->getMemOperand()->getFlags());
8977
8978 // Make sure successors of the original load stay after it by updating them
8979 // to use the new Chain.
8980 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8981 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8982 }
8983
8984 return SDValue();
8985}
8986
8990 SDLoc DL(N);
8991 EVT VT = N->getValueType(0);
8992
8993 // Zero-extend src to avoid scalarization.
8994 if (VT.isVector())
8995 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8996
8997 return SDValue();
8998}
8999
9000// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
9001// For example:
9002// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
9003// Can be combined into:
9004// v4i32 = VFTINTRZ_W_D v2f64. v2f64
9008 if (!Subtarget.hasExtLSX())
9009 return SDValue();
9010
9011 SDLoc DL(N);
9012 EVT DstVT = N->getValueType(0);
9013 SDValue Src = N->getOperand(0);
9014 EVT SrcVT = Src.getValueType();
9015 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
9016
9017 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
9018 return SDValue();
9019
9020 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
9021 unsigned SrcBits = SrcVT.getSizeInBits();
9022 unsigned DstEltBits = DstVT.getScalarSizeInBits();
9023 unsigned NumElts = DstVT.getVectorNumElements();
9024 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
9025
9026 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
9027 return SDValue();
9028
9029 if (SrcBits % BlockBits != 0 && SrcBits != 128)
9030 return SDValue();
9031
9032 if (DstEltBits < 32) {
9033 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
9034 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
9035 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
9036 }
9037
9038 if (SrcEltBits != 64 || DstEltBits != 32)
9039 return SDValue();
9040
9041 if (!IsSigned) {
9042 // LASX already has pattern for double convert to uint32.
9043 if (Subtarget.hasExtLASX())
9044 return SDValue();
9045 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
9046 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
9047 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
9048 }
9049
9050 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
9051}
9052
9053// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
9054// logical operations, like in the example below.
9055// or (and (truncate x, truncate y)),
9056// (xor (truncate z, build_vector (constants)))
9057// Given a target type \p VT, we generate
9058// or (and x, y), (xor z, zext(build_vector (constants)))
9059// given x, y and z are of type \p VT. We can do so, if operands are either
9060// truncates from VT types, the second operand is a vector of constants, can
9061// be recursively promoted or is an existing extension we can extend further.
9063 SelectionDAG &DAG,
9065 unsigned Depth) {
9066 // Limit recursion to avoid excessive compile times.
9068 return SDValue();
9069
9070 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
9071 return SDValue();
9072
9073 SDValue N0 = N.getOperand(0);
9074 SDValue N1 = N.getOperand(1);
9075
9077 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
9078 return SDValue();
9079
9080 if (SDValue NN0 =
9081 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
9082 N0 = NN0;
9083 else {
9084 // The left side has to be a 'trunc'.
9085 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
9086 N0.getOperand(0).getValueType() == VT;
9087 if (LHSTrunc)
9088 N0 = N0.getOperand(0);
9089 else
9090 return SDValue();
9091 }
9092
9093 if (SDValue NN1 =
9094 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
9095 N1 = NN1;
9096 else {
9097 // The right side has to be a 'trunc', a (foldable) constant or an
9098 // existing extension we can extend further.
9099 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
9100 N1.getOperand(0).getValueType() == VT;
9101 if (RHSTrunc)
9102 N1 = N1.getOperand(0);
9103 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
9104 Subtarget.hasExtLASX() && N1.hasOneUse())
9105 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
9106 // On 32-bit platform, i64 is an illegal integer scalar type, and
9107 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
9108 // future.
9109 else if (SDValue Cst =
9111 N1 = Cst;
9112 else
9113 return SDValue();
9114 }
9115
9116 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
9117}
9118
9119// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
9120// is LSX-sized register. In most cases we actually compare or select LASX-sized
9121// registers and mixing the two types creates horrible code. This method
9122// optimizes some of the transition sequences.
9124 SelectionDAG &DAG,
9126 EVT VT = N.getValueType();
9127 assert(VT.isVector() && "Expected vector type");
9128 assert((N.getOpcode() == ISD::ANY_EXTEND ||
9129 N.getOpcode() == ISD::ZERO_EXTEND ||
9130 N.getOpcode() == ISD::SIGN_EXTEND) &&
9131 "Invalid Node");
9132
9133 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
9134 return SDValue();
9135
9136 SDValue Narrow = N.getOperand(0);
9137 EVT NarrowVT = Narrow.getValueType();
9138
9139 // Generate the wide operation.
9140 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
9141 if (!Op)
9142 return SDValue();
9143 switch (N.getOpcode()) {
9144 default:
9145 llvm_unreachable("Unexpected opcode");
9146 case ISD::ANY_EXTEND:
9147 return Op;
9148 case ISD::ZERO_EXTEND:
9149 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
9150 case ISD::SIGN_EXTEND:
9151 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
9152 DAG.getValueType(NarrowVT));
9153 }
9154}
9155
9159 EVT VT = N->getValueType(0);
9160 SDLoc DL(N);
9161
9162 if (VT.isVector()) {
9163 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
9164 return R;
9165
9166 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
9167 N->getValueSizeInBits(0) != N->getOperand(0).getValueSizeInBits() * 2)
9168 return SDValue();
9169
9170 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
9171 if (N->getOpcode() == ISD::SIGN_EXTEND)
9172 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
9173 if (N->getOpcode() == ISD::ZERO_EXTEND)
9174 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
9175 }
9176 }
9177
9178 return SDValue();
9179}
9180
9181static SDValue
9185 SDLoc DL(N);
9186 EVT VT = N->getValueType(0);
9187
9188 if (VT.isVector() && N->getNumOperands() == 2)
9189 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
9190 return R;
9191
9192 return SDValue();
9193}
9194
9198 if (DCI.isBeforeLegalizeOps())
9199 return SDValue();
9200
9201 EVT VT = N->getValueType(0);
9202 if (!VT.isVector())
9203 return SDValue();
9204
9205 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
9206 return SDValue();
9207
9208 EVT EltVT = VT.getVectorElementType();
9209 if (!EltVT.isInteger())
9210 return SDValue();
9211
9212 SDValue Cond = N->getOperand(0);
9213 SDValue TrueVal = N->getOperand(1);
9214 SDValue FalseVal = N->getOperand(2);
9215
9216 // match:
9217 //
9218 // vselect (setcc shift, 0, seteq),
9219 // x,
9220 // rounded_shift
9221
9222 if (Cond.getOpcode() != ISD::SETCC)
9223 return SDValue();
9224
9225 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
9226 return SDValue();
9227
9228 if (Cond.getOperandCondCode(2) != ISD::SETEQ)
9229 return SDValue();
9230
9231 SDValue Shift = Cond.getOperand(0);
9232
9233 // True branch must be original value:
9234 //
9235 // vselect cond, x, ...
9236
9237 SDValue X = TrueVal;
9238
9239 // Now match rounded shift pattern:
9240 //
9241 // add
9242 // (and
9243 // (srl X, shift-1)
9244 // 1)
9245 // (srl/sra X, shift)
9246
9247 if (FalseVal.getOpcode() != ISD::ADD)
9248 return SDValue();
9249
9250 SDValue Add0 = FalseVal.getOperand(0);
9251 SDValue Add1 = FalseVal.getOperand(1);
9252 SDValue And;
9253 SDValue Shr;
9254
9255 if (Add0.getOpcode() == ISD::AND) {
9256 And = Add0;
9257 Shr = Add1;
9258 } else if (Add1.getOpcode() == ISD::AND) {
9259 And = Add1;
9260 Shr = Add0;
9261 } else {
9262 return SDValue();
9263 }
9264
9265 // match:
9266 //
9267 // srl/sra X, shift
9268
9269 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
9270 return SDValue();
9271
9272 if (Shr.getOperand(0) != X)
9273 return SDValue();
9274
9275 if (Shr.getOperand(1) != Shift)
9276 return SDValue();
9277
9278 // match:
9279 //
9280 // and
9281 // (srl X, shift-1)
9282 // 1
9283
9284 SDValue Srl = And.getOperand(0);
9285 SDValue One = And.getOperand(1);
9286 APInt SplatVal;
9287
9288 if (Srl.getOpcode() != ISD::SRL)
9289 return SDValue();
9290
9291 One = peekThroughBitcasts(One);
9292 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
9293 return SDValue();
9294
9295 if (SplatVal != 1)
9296 return SDValue();
9297
9298 if (Srl.getOperand(0) != X)
9299 return SDValue();
9300
9301 // match:
9302 //
9303 // shift-1
9304
9305 SDValue ShiftMinus1 = Srl.getOperand(1);
9306
9307 if (ShiftMinus1.getOpcode() != ISD::ADD)
9308 return SDValue();
9309
9310 if (ShiftMinus1.getOperand(0) != Shift)
9311 return SDValue();
9312
9314 return SDValue();
9315
9316 // We matched a rounded right shift pattern and can lower it
9317 // to a single vector rounded shift instruction.
9318
9319 SDLoc DL(N);
9320 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
9321 : LoongArchISD::VSRAR,
9322 DL, VT, X, Shift);
9323}
9324
9328 if (!DCI.isBeforeLegalize())
9329 return SDValue();
9330
9331 SDLoc DL(N);
9332 EVT ResTy = N->getValueType(0);
9333 SDValue N0 = N->getOperand(0);
9334 SDValue N1 = N->getOperand(1);
9335
9336 bool HasLSXOnly = Subtarget.hasExtLSX() && !Subtarget.hasExtLASX();
9337 if (ResTy != MVT::v8i16 && ResTy != MVT::v4i32 && ResTy != MVT::v2i64 &&
9338 ResTy != MVT::i128 && ResTy != MVT::v16i16 && ResTy != MVT::v8i32 &&
9339 ResTy != MVT::v4i64 && ResTy != MVT::v2i128)
9340 return SDValue();
9341 if (HasLSXOnly && (ResTy.is256BitVector() || ResTy == MVT::v2i128))
9342 return SDValue();
9343
9344 // Combine:
9345 // ti,tii,...,tx = extract_vector_elt t0, {0,2,4,.../1,3,5,...}
9346 // tj,tjj,...,ty = extract_vector_elt t1, {0,2,4,.../1,3,5,...}
9347 // tm = BUILD_VECTOR ti,tii,...,tx (Only when ResTy != MVT::i128)
9348 // tn = BUILD_VECTOR tj,tjj,...,ty (Only when ResTy != MVT::i128)
9349 // ta = {sign/zero}_extend tm
9350 // tb = {sign/zero}_extend tn
9351 // tr = mul ta, tb
9352 // to:
9353 // tr = VMULW{EV/OD}[U/US] t0, t1
9354 auto getExtType = [](unsigned Op0, unsigned Op1) -> int {
9355 if (Op0 == ISD::SIGN_EXTEND && Op1 == ISD::SIGN_EXTEND)
9356 return 0;
9357 if (Op0 == ISD::ZERO_EXTEND && Op1 == ISD::ZERO_EXTEND)
9358 return 1;
9359 if (Op0 == ISD::ZERO_EXTEND && Op1 == ISD::SIGN_EXTEND)
9360 return 2;
9361 if (Op0 == ISD::SIGN_EXTEND && Op1 == ISD::ZERO_EXTEND)
9362 return 3;
9363 return -1;
9364 };
9365
9366 int ExtType = getExtType(N0.getOpcode(), N1.getOpcode());
9367 if (ExtType < 0)
9368 return SDValue();
9369
9370 // Avoid the regressions on LA64 introduced by combining
9371 // i128-type multiplications.
9372 bool IsScalar = (ResTy == MVT::i128);
9373 if (IsScalar && ExtType < 2 && Subtarget.is64Bit())
9374 return SDValue();
9375
9376 SDValue Src0 = N0.getOperand(0);
9377 SDValue Src1 = N1.getOperand(0);
9378 if (IsScalar && (Src0.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
9379 Src1.getOpcode() != ISD::EXTRACT_VECTOR_ELT))
9380 return SDValue();
9381 if (!IsScalar && (Src0.getOpcode() != ISD::BUILD_VECTOR ||
9382 Src1.getOpcode() != ISD::BUILD_VECTOR))
9383 return SDValue();
9384
9385 unsigned ResBits = ResTy.getScalarSizeInBits();
9386 unsigned Src0Bits = Src0.getValueType().getScalarSizeInBits();
9387 unsigned Src1Bits = Src1.getValueType().getScalarSizeInBits();
9388 if (Src0Bits != Src1Bits || ResBits != Src0Bits * 2)
9389 return SDValue();
9390
9391 // Collect all EXTRACT_VECTOR_ELT.
9393 if (IsScalar) {
9394 Elems.emplace_back(Src0, Src1);
9395 } else {
9396 for (unsigned i = 0; i < Src0.getNumOperands(); ++i)
9397 Elems.emplace_back(Src0.getOperand(i), Src1.getOperand(i));
9398 }
9399
9400 unsigned Index;
9401 SDValue OrigN0, OrigN1;
9402 bool First = true;
9403 for (auto &[Op0, Op1] : Elems) {
9404 // Each element must be EXTRACT_VECTOR_ELT.
9405 if (Op0.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
9407 return SDValue();
9408
9409 // Check each EXTRACT_VECTOR_ELT's source vector and index.
9410 if (Op0.getOperand(1) != Op1.getOperand(1))
9411 return SDValue();
9412
9413 auto *IdxC = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
9414 if (!IdxC)
9415 return SDValue();
9416
9417 unsigned CurIdx = IdxC->getZExtValue();
9418 if (First) {
9419 if (CurIdx != 0 && CurIdx != 1)
9420 return SDValue();
9421 OrigN0 = Op0.getOperand(0);
9422 OrigN1 = Op1.getOperand(0);
9423 First = false;
9424 } else {
9425 if (CurIdx != Index + 2 || Op0.getOperand(0) != OrigN0 ||
9426 Op1.getOperand(0) != OrigN1)
9427 return SDValue();
9428 }
9429 Index = CurIdx;
9430 }
9431
9432 if (OrigN0.getValueType() != OrigN1.getValueType())
9433 return SDValue();
9434 if (OrigN0.getValueType().getVectorNumElements() !=
9435 (IsScalar ? 1 : ResTy.getVectorNumElements()) * 2)
9436 return SDValue();
9437
9438 SDValue Result;
9439 EVT OrigTy = OrigN0.getValueType();
9440 bool IsEven = (Index % 2 == 0);
9441
9442 static const unsigned OpcTable[3][2] = {
9443 {LoongArchISD::VMULWOD, LoongArchISD::VMULWEV},
9444 {LoongArchISD::VMULWODU, LoongArchISD::VMULWEVU},
9445 {LoongArchISD::VMULWODUS, LoongArchISD::VMULWEVUS}};
9446
9447 if (ExtType == 3)
9448 Result = DAG.getNode(OpcTable[2][IsEven], DL, OrigTy, OrigN1, OrigN0);
9449 else
9450 Result = DAG.getNode(OpcTable[ExtType][IsEven], DL, OrigTy, OrigN0, OrigN1);
9451
9452 return DAG.getBitcast(ResTy, Result);
9453}
9454
9455static SDValue
9458 SelectionDAG &DAG = DCI.DAG;
9459 SDValue Src = N->getOperand(0);
9460 EVT VT = N->getValueType(0);
9461 EVT SrcVT = cast<VTSDNode>(N->getOperand(1))->getVT();
9462 unsigned Opc = Src.getOpcode();
9463 SDLoc DL(N);
9464
9465 // Leave the sign extension in place when it feeds an xor with another
9466 // sign-extended value; the generic xor-of-sext_inregs combine can then
9467 // fold both extensions into a single one.
9468 if (N->hasOneUse()) {
9469 SDNode *User = N->use_begin()->getUser();
9470 if (User->getOpcode() == ISD::XOR) {
9471 SDValue Other = User->getOperand(0).getNode() == N ? User->getOperand(1)
9472 : User->getOperand(0);
9473 if (Other.getOpcode() == ISD::SIGN_EXTEND_INREG)
9474 return SDValue();
9475 }
9476 }
9477
9478 // Do not hide a sign-extended boolean from a compare against zero: the
9479 // generic combiner folds (setcc (sext_inreg X, i1), 0, setlt) back to X.
9480 for (SDNode *User : N->users()) {
9481 if (User->getOpcode() != ISD::SETCC)
9482 continue;
9483 if ((User->getOperand(0).getNode() == N &&
9485 (User->getOperand(1).getNode() == N &&
9487 return SDValue();
9488 }
9489
9490 // Fold (sext_inreg (shl X, Y), i32) -> (sll.w X, Y) iff Y u< 32.
9491 if (DCI.isAfterLegalizeDAG() && Subtarget.is64Bit() && SrcVT == MVT::i32 &&
9492 VT == MVT::i64 && Opc == ISD::SHL &&
9493 !isa<ConstantSDNode>(Src.getOperand(1)) &&
9494 DAG.computeKnownBits(Src.getOperand(1)).countMaxActiveBits() <= 5) {
9495 return DAG.getNode(LoongArchISD::SLL_W, DL, VT, Src.getOperand(0),
9496 Src.getOperand(1));
9497 }
9498
9499 // The SETCC/XOR folds replace the sign extension itself. When the result
9500 // has several users they do not save an instruction and can duplicate the
9501 // compare; leave it to the generic combiner.
9502 if (!N->hasOneUse())
9503 return SDValue();
9504
9505 // Similarly, a sign-extended boolean that feeds a sign-bit extraction is
9506 // usually part of a compare that the generic combiner can fold away.
9507 for (SDNode *User : N->users()) {
9508 if ((User->getOpcode() == ISD::SRL || User->getOpcode() == ISD::SRA) &&
9510 return SDValue();
9511 }
9512
9513 // Fold (sext_inreg (setcc X, Y, CC), i1) -> (sub 0, (setcc X, Y, CC)) if CC
9514 // can be selected with a single instruction, or
9515 // (add (setcc X, Y, inv(CC)), -1) if the inverted CC is cheaper. LoongArch
9516 // selects setge/setle/setuge/setule as slt + xori, so inverting such an
9517 // integer compare avoids the extra xor. Inverting replaces the original
9518 // setcc, so only do it when it has a single use; otherwise (e.g. an FP
9519 // compare shared with another user) this would introduce a second compare.
9520 if (Opc == ISD::SETCC && SrcVT == MVT::i1) {
9521 ISD::CondCode CC = cast<CondCodeSDNode>(Src.getOperand(2))->get();
9522 if (Src.hasOneUse() && Src.getOperand(0).getValueType().isInteger()) {
9523 switch (CC) {
9524 case ISD::SETGE:
9525 case ISD::SETLE:
9526 case ISD::SETUGE:
9527 case ISD::SETULE:
9528 // (sub 0, X >= Y) == (add (X < Y), -1), etc.
9529 return DAG.getNode(
9530 ISD::ADD, DL, VT,
9531 DAG.getSetCC(
9532 SDLoc(N), Src.getValueType(), Src.getOperand(0),
9533 Src.getOperand(1),
9534 ISD::getSetCCInverse(CC, Src.getOperand(0).getValueType())),
9535 DAG.getAllOnesConstant(DL, VT));
9536 default:
9537 break;
9538 }
9539 }
9540 return DAG.getNegative(Src, DL, VT);
9541 }
9542
9543 // Fold (sext_inreg (xor (setcc), C), i1) -> (add (setcc), -1) where C is
9544 // either 1 or -1. Since setcc only produces 0 or 1, the xor only flips the
9545 // low bit, so the sign extension of that bit is -(1 - setcc) == setcc - 1.
9546 // The setcc may be wrapped in a truncate/any_extend when the boolean is
9547 // extended to VT (e.g. by a zext, which knows the upper bits are zero).
9548 if (Opc == ISD::XOR && SrcVT == MVT::i1 &&
9549 (isOneConstant(Src.getOperand(1)) ||
9550 isAllOnesConstant(Src.getOperand(1)))) {
9551 SDValue XorOp = Src.getOperand(0);
9552 if (XorOp.getOpcode() == ISD::TRUNCATE ||
9553 XorOp.getOpcode() == ISD::ANY_EXTEND)
9554 XorOp = XorOp.getOperand(0);
9555 if (XorOp.getOpcode() != ISD::SETCC)
9556 return SDValue();
9557 // The setcc may still have an i1 result type, in which case rebuild it
9558 // with VT so that both ADD operands have the same type. A setcc produces
9559 // a canonical 0/1 value, so this is exact while the any_extend leaves the
9560 // upper bits undefined.
9562 EVT OpVT = XorOp.getOperand(0).getValueType();
9563
9564 // Inverting an FP compare is free, so this fold does not save anything
9565 // and can duplicate a shared fcmp. Keep the original form.
9566 if (OpVT.isFloatingPoint())
9567 return SDValue();
9568
9569 // Reusing the original compare is only possible when the setcc is
9570 // otherwise dead. Inverting a shared compare duplicates it (e.g. an FP
9571 // compare used by a zext as well).
9572 if (!XorOp.hasOneUse())
9573 return SDValue();
9574
9575 // A constant compare with a greater-than style condition code cannot use
9576 // the slti/sltui immediate patterns; leave it to the generic combiner,
9577 // which canonicalizes it to setlt/setult first.
9578 if (isa<ConstantSDNode>(XorOp.getOperand(1)) && CC != ISD::SETLT &&
9579 CC != ISD::SETULT)
9580 return SDValue();
9581
9582 // The generic (sub X, (0 - Y)) -> (add X, Y) fold is better than
9583 // rewriting the sign-extended boolean here.
9584 if (N->hasOneUse() && N->use_begin()->getUser()->getOpcode() == ISD::SUB)
9585 return SDValue();
9586
9587 // For integer compares, sext(!setcc CC) == -(setcc inv(CC)). Only keep
9588 // CC (as add -1) when CC itself is the single-instruction form; otherwise
9589 // negate the inverted setcc, which also CSEs with an existing one.
9590 if (OpVT.isInteger() && CC != ISD::SETLT && CC != ISD::SETGT &&
9591 CC != ISD::SETULT && CC != ISD::SETUGT)
9592 return DAG.getNegative(DAG.getSetCC(DL, VT, XorOp.getOperand(0),
9593 XorOp.getOperand(1),
9594 ISD::getSetCCInverse(CC, OpVT)),
9595 DL, VT);
9596 if (XorOp.getValueType() != VT)
9597 XorOp =
9598 DAG.getSetCC(DL, VT, XorOp.getOperand(0), XorOp.getOperand(1), CC);
9599 return DAG.getNode(ISD::ADD, DL, VT, XorOp, DAG.getAllOnesConstant(DL, VT));
9600 }
9601
9602 return SDValue();
9603}
9604
9606 DAGCombinerInfo &DCI) const {
9607 SelectionDAG &DAG = DCI.DAG;
9608 switch (N->getOpcode()) {
9609 default:
9610 break;
9611 case ISD::ADD:
9612 return performADDCombine(N, DAG, DCI, Subtarget);
9613 case ISD::AND:
9614 return performANDCombine(N, DAG, DCI, Subtarget);
9615 case ISD::OR:
9616 return performORCombine(N, DAG, DCI, Subtarget);
9617 case ISD::XOR:
9618 return performXORCombine(N, DAG, Subtarget);
9619 case ISD::SETCC:
9620 return performSETCCCombine(N, DAG, DCI, Subtarget);
9621 case ISD::SELECT:
9622 return performSELECTCombine(N, DAG, DCI, Subtarget);
9623 case ISD::SHL:
9624 return performSHLCombine(N, DAG, DCI, Subtarget);
9625 case ISD::SRL:
9626 return performSRLCombine(N, DAG, DCI, Subtarget);
9627 case ISD::SUB:
9628 return performSUBCombine(N, DAG, DCI, Subtarget);
9629 case ISD::BITCAST:
9630 return performBITCASTCombine(N, DAG, DCI, Subtarget);
9631 case ISD::ANY_EXTEND:
9632 case ISD::ZERO_EXTEND:
9633 case ISD::SIGN_EXTEND:
9634 return performEXTENDCombine(N, DAG, DCI, Subtarget);
9636 return performSIGN_EXTEND_INREGCombine(N, DCI, Subtarget);
9637 case ISD::SINT_TO_FP:
9638 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9639 case ISD::UINT_TO_FP:
9640 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
9641 case ISD::FP_TO_SINT:
9642 case ISD::FP_TO_UINT:
9643 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
9644 case LoongArchISD::BITREV_W:
9645 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
9646 case LoongArchISD::BR_CC:
9647 return performBR_CCCombine(N, DAG, DCI, Subtarget);
9648 case LoongArchISD::SELECT_CC:
9649 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
9651 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
9652 case LoongArchISD::MOVGR2FR_W_LA64:
9653 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
9654 case LoongArchISD::MOVFR2GR_S_LA64:
9655 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
9656 case LoongArchISD::CRC_W_B_W:
9657 case LoongArchISD::CRC_W_H_W:
9658 case LoongArchISD::CRCC_W_B_W:
9659 case LoongArchISD::CRCC_W_H_W:
9660 case LoongArchISD::VMSKLTZ:
9661 case LoongArchISD::XVMSKLTZ:
9662 return performDemandedBitsCombine(N, DAG, DCI);
9663 case LoongArchISD::SPLIT_PAIR_F64:
9664 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
9665 case LoongArchISD::VANDN:
9666 return performVANDNCombine(N, DAG, DCI, Subtarget);
9668 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
9669 case ISD::VSELECT:
9670 return performVSELECTCombine(N, DAG, DCI, Subtarget);
9671 case LoongArchISD::VPACKEV:
9672 case LoongArchISD::VPERMI:
9673 if (SDValue Result =
9674 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
9675 return Result;
9676 break;
9677 case ISD::MUL:
9678 return performMULCombine(N, DAG, DCI, Subtarget);
9679 }
9680 return SDValue();
9681}
9682
9685 if (!ZeroDivCheck)
9686 return MBB;
9687
9688 // Build instructions:
9689 // MBB:
9690 // div(or mod) $dst, $dividend, $divisor
9691 // bne $divisor, $zero, SinkMBB
9692 // BreakMBB:
9693 // break 7 // BRK_DIVZERO
9694 // SinkMBB:
9695 // fallthrough
9696 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
9697 MachineFunction::iterator It = ++MBB->getIterator();
9698 MachineFunction *MF = MBB->getParent();
9699 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9700 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
9701 MF->insert(It, BreakMBB);
9702 MF->insert(It, SinkMBB);
9703
9704 // Transfer the remainder of MBB and its successor edges to SinkMBB.
9705 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
9706 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
9707
9708 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
9709 DebugLoc DL = MI.getDebugLoc();
9710 MachineOperand &Divisor = MI.getOperand(2);
9711 Register DivisorReg = Divisor.getReg();
9712
9713 // MBB:
9714 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
9715 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
9716 .addReg(LoongArch::R0)
9717 .addMBB(SinkMBB);
9718 MBB->addSuccessor(BreakMBB);
9719 MBB->addSuccessor(SinkMBB);
9720
9721 // BreakMBB:
9722 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
9723 // definition of BRK_DIVZERO.
9724 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
9725 BreakMBB->addSuccessor(SinkMBB);
9726
9727 // Clear Divisor's kill flag.
9728 Divisor.setIsKill(false);
9729
9730 return SinkMBB;
9731}
9732
9733static MachineBasicBlock *
9736 unsigned InsOp;
9737 unsigned BroadcastOp;
9738 unsigned HalfSize;
9739 switch (MI.getOpcode()) {
9740 default:
9741 llvm_unreachable("Unexpected opcode");
9742 case LoongArch::PseudoXVINSGR2VR_B:
9743 HalfSize = 16;
9744 BroadcastOp = LoongArch::XVREPLGR2VR_B;
9745 InsOp = LoongArch::XVEXTRINS_B;
9746 break;
9747 case LoongArch::PseudoXVINSGR2VR_H:
9748 HalfSize = 8;
9749 BroadcastOp = LoongArch::XVREPLGR2VR_H;
9750 InsOp = LoongArch::XVEXTRINS_H;
9751 break;
9752 }
9753 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9754 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
9755 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
9756 DebugLoc DL = MI.getDebugLoc();
9758 // XDst = vector_insert XSrc, Elt, Idx
9759 Register XDst = MI.getOperand(0).getReg();
9760 Register XSrc = MI.getOperand(1).getReg();
9761 Register Elt = MI.getOperand(2).getReg();
9762 unsigned Idx = MI.getOperand(3).getImm();
9763
9764 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
9765 Idx < HalfSize) {
9766 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
9767 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
9768
9769 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
9770 .addReg(XSrc, {}, LoongArch::sub_128);
9771 BuildMI(*BB, MI, DL,
9772 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
9773 : LoongArch::VINSGR2VR_B),
9774 ScratchSubReg2)
9775 .addReg(ScratchSubReg1)
9776 .addReg(Elt)
9777 .addImm(Idx);
9778
9779 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
9780 .addReg(ScratchSubReg2)
9781 .addImm(LoongArch::sub_128);
9782 } else {
9783 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9784 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9785
9786 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
9787
9788 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
9789 .addReg(ScratchReg1)
9790 .addReg(XSrc)
9791 .addImm(Idx >= HalfSize ? 48 : 18);
9792
9793 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
9794 .addReg(XSrc)
9795 .addReg(ScratchReg2)
9796 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
9797 }
9798
9799 MI.eraseFromParent();
9800 return BB;
9801}
9802
9806 assert(Subtarget.hasExtLSX());
9807 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9808 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9809 DebugLoc DL = MI.getDebugLoc();
9811 Register Dst = MI.getOperand(0).getReg();
9812 Register Src = MI.getOperand(1).getReg();
9813
9814 unsigned BroadcastOp, CTOp, PickOp;
9815 switch (MI.getOpcode()) {
9816 default:
9817 llvm_unreachable("Unexpected opcode");
9818 case LoongArch::PseudoCTPOP_B:
9819 BroadcastOp = LoongArch::VREPLGR2VR_B;
9820 CTOp = LoongArch::VPCNT_B;
9821 PickOp = LoongArch::VPICKVE2GR_B;
9822 break;
9823 case LoongArch::PseudoCTPOP_H:
9824 case LoongArch::PseudoCTPOP_H_LA32:
9825 BroadcastOp = LoongArch::VREPLGR2VR_H;
9826 CTOp = LoongArch::VPCNT_H;
9827 PickOp = LoongArch::VPICKVE2GR_H;
9828 break;
9829 case LoongArch::PseudoCTPOP_W:
9830 case LoongArch::PseudoCTPOP_W_LA32:
9831 BroadcastOp = LoongArch::VREPLGR2VR_W;
9832 CTOp = LoongArch::VPCNT_W;
9833 PickOp = LoongArch::VPICKVE2GR_W;
9834 break;
9835 case LoongArch::PseudoCTPOP_D:
9836 BroadcastOp = LoongArch::VREPLGR2VR_D;
9837 CTOp = LoongArch::VPCNT_D;
9838 PickOp = LoongArch::VPICKVE2GR_D;
9839 break;
9840 }
9841
9842 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9843 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9844 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9845 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9846 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9847
9848 MI.eraseFromParent();
9849 return BB;
9850}
9851
9852static MachineBasicBlock *
9855 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9856 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9857 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9859 Register Dst = MI.getOperand(0).getReg();
9860 Register Src = MI.getOperand(1).getReg();
9861 DebugLoc DL = MI.getDebugLoc();
9862 unsigned EleBits = 8;
9863 unsigned NotOpc = 0;
9864 unsigned MskOpc;
9865
9866 switch (MI.getOpcode()) {
9867 default:
9868 llvm_unreachable("Unexpected opcode");
9869 case LoongArch::PseudoVMSKLTZ_B:
9870 MskOpc = LoongArch::VMSKLTZ_B;
9871 break;
9872 case LoongArch::PseudoVMSKLTZ_H:
9873 MskOpc = LoongArch::VMSKLTZ_H;
9874 EleBits = 16;
9875 break;
9876 case LoongArch::PseudoVMSKLTZ_W:
9877 MskOpc = LoongArch::VMSKLTZ_W;
9878 EleBits = 32;
9879 break;
9880 case LoongArch::PseudoVMSKLTZ_D:
9881 MskOpc = LoongArch::VMSKLTZ_D;
9882 EleBits = 64;
9883 break;
9884 case LoongArch::PseudoVMSKGEZ_B:
9885 MskOpc = LoongArch::VMSKGEZ_B;
9886 break;
9887 case LoongArch::PseudoVMSKEQZ_B:
9888 MskOpc = LoongArch::VMSKNZ_B;
9889 NotOpc = LoongArch::VNOR_V;
9890 break;
9891 case LoongArch::PseudoVMSKNEZ_B:
9892 MskOpc = LoongArch::VMSKNZ_B;
9893 break;
9894 case LoongArch::PseudoXVMSKLTZ_B:
9895 MskOpc = LoongArch::XVMSKLTZ_B;
9896 RC = &LoongArch::LASX256RegClass;
9897 break;
9898 case LoongArch::PseudoXVMSKLTZ_H:
9899 MskOpc = LoongArch::XVMSKLTZ_H;
9900 RC = &LoongArch::LASX256RegClass;
9901 EleBits = 16;
9902 break;
9903 case LoongArch::PseudoXVMSKLTZ_W:
9904 MskOpc = LoongArch::XVMSKLTZ_W;
9905 RC = &LoongArch::LASX256RegClass;
9906 EleBits = 32;
9907 break;
9908 case LoongArch::PseudoXVMSKLTZ_D:
9909 MskOpc = LoongArch::XVMSKLTZ_D;
9910 RC = &LoongArch::LASX256RegClass;
9911 EleBits = 64;
9912 break;
9913 case LoongArch::PseudoXVMSKGEZ_B:
9914 MskOpc = LoongArch::XVMSKGEZ_B;
9915 RC = &LoongArch::LASX256RegClass;
9916 break;
9917 case LoongArch::PseudoXVMSKEQZ_B:
9918 MskOpc = LoongArch::XVMSKNZ_B;
9919 NotOpc = LoongArch::XVNOR_V;
9920 RC = &LoongArch::LASX256RegClass;
9921 break;
9922 case LoongArch::PseudoXVMSKNEZ_B:
9923 MskOpc = LoongArch::XVMSKNZ_B;
9924 RC = &LoongArch::LASX256RegClass;
9925 break;
9926 }
9927
9928 Register Msk = MRI.createVirtualRegister(RC);
9929 if (NotOpc) {
9930 Register Tmp = MRI.createVirtualRegister(RC);
9931 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9932 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk).addReg(Tmp).addReg(Tmp);
9933 } else {
9934 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9935 }
9936
9937 if (TRI->getRegSizeInBits(*RC) > 128) {
9938 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9939 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9940 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9941 .addReg(Msk)
9942 .addImm(0);
9943 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9944 .addReg(Msk)
9945 .addImm(4);
9946 BuildMI(*BB, MI, DL,
9947 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9948 : LoongArch::BSTRINS_W),
9949 Dst)
9950 .addReg(Lo)
9951 .addReg(Hi)
9952 .addImm(256 / EleBits - 1)
9953 .addImm(128 / EleBits);
9954 } else {
9955 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9956 .addReg(Msk)
9957 .addImm(0);
9958 }
9959
9960 MI.eraseFromParent();
9961 return BB;
9962}
9963
9964static MachineBasicBlock *
9967 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9968 "Unexpected instruction");
9969
9970 MachineFunction &MF = *BB->getParent();
9971 DebugLoc DL = MI.getDebugLoc();
9973 Register LoReg = MI.getOperand(0).getReg();
9974 Register HiReg = MI.getOperand(1).getReg();
9975 Register SrcReg = MI.getOperand(2).getReg();
9976
9977 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9978 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9979 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9980 MI.eraseFromParent(); // The pseudo instruction is gone now.
9981 return BB;
9982}
9983
9984static MachineBasicBlock *
9987 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9988 "Unexpected instruction");
9989
9990 MachineFunction &MF = *BB->getParent();
9991 DebugLoc DL = MI.getDebugLoc();
9994 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9995 Register DstReg = MI.getOperand(0).getReg();
9996 Register LoReg = MI.getOperand(1).getReg();
9997 Register HiReg = MI.getOperand(2).getReg();
9998
9999 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
10000 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
10001 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
10002 .addReg(TmpReg)
10003 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
10004 MI.eraseFromParent(); // The pseudo instruction is gone now.
10005 return BB;
10006}
10007
10009 switch (MI.getOpcode()) {
10010 default:
10011 return false;
10012 case LoongArch::Select_GPR_Using_CC_GPR:
10013 return true;
10014 }
10015}
10016
10017static MachineBasicBlock *
10020 // To "insert" Select_* instructions, we actually have to insert the triangle
10021 // control-flow pattern. The incoming instructions know the destination vreg
10022 // to set, the condition code register to branch on, the true/false values to
10023 // select between, and the condcode to use to select the appropriate branch.
10024 //
10025 // We produce the following control flow:
10026 // HeadMBB
10027 // | \
10028 // | IfFalseMBB
10029 // | /
10030 // TailMBB
10031 //
10032 // When we find a sequence of selects we attempt to optimize their emission
10033 // by sharing the control flow. Currently we only handle cases where we have
10034 // multiple selects with the exact same condition (same LHS, RHS and CC).
10035 // The selects may be interleaved with other instructions if the other
10036 // instructions meet some requirements we deem safe:
10037 // - They are not pseudo instructions.
10038 // - They are debug instructions. Otherwise,
10039 // - They do not have side-effects, do not access memory and their inputs do
10040 // not depend on the results of the select pseudo-instructions.
10041 // The TrueV/FalseV operands of the selects cannot depend on the result of
10042 // previous selects in the sequence.
10043 // These conditions could be further relaxed. See the X86 target for a
10044 // related approach and more information.
10045
10046 Register LHS = MI.getOperand(1).getReg();
10047 Register RHS;
10048 if (MI.getOperand(2).isReg())
10049 RHS = MI.getOperand(2).getReg();
10050 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
10051
10052 SmallVector<MachineInstr *, 4> SelectDebugValues;
10053 SmallSet<Register, 4> SelectDests;
10054 SelectDests.insert(MI.getOperand(0).getReg());
10055
10056 MachineInstr *LastSelectPseudo = &MI;
10057 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
10058 SequenceMBBI != E; ++SequenceMBBI) {
10059 if (SequenceMBBI->isDebugInstr())
10060 continue;
10061 if (isSelectPseudo(*SequenceMBBI)) {
10062 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
10063 !SequenceMBBI->getOperand(2).isReg() ||
10064 SequenceMBBI->getOperand(2).getReg() != RHS ||
10065 SequenceMBBI->getOperand(3).getImm() != CC ||
10066 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
10067 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
10068 break;
10069 LastSelectPseudo = &*SequenceMBBI;
10070 SequenceMBBI->collectDebugValues(SelectDebugValues);
10071 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
10072 continue;
10073 }
10074 if (SequenceMBBI->hasUnmodeledSideEffects() ||
10075 SequenceMBBI->mayLoadOrStore() ||
10076 SequenceMBBI->usesCustomInsertionHook())
10077 break;
10078 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
10079 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
10080 }))
10081 break;
10082 }
10083
10084 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
10085 const BasicBlock *LLVM_BB = BB->getBasicBlock();
10086 DebugLoc DL = MI.getDebugLoc();
10088
10089 MachineBasicBlock *HeadMBB = BB;
10090 MachineFunction *F = BB->getParent();
10091 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
10092 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
10093
10094 F->insert(I, IfFalseMBB);
10095 F->insert(I, TailMBB);
10096
10097 // Set the call frame size on entry to the new basic blocks.
10098 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
10099 IfFalseMBB->setCallFrameSize(CallFrameSize);
10100 TailMBB->setCallFrameSize(CallFrameSize);
10101
10102 // Transfer debug instructions associated with the selects to TailMBB.
10103 for (MachineInstr *DebugInstr : SelectDebugValues) {
10104 TailMBB->push_back(DebugInstr->removeFromParent());
10105 }
10106
10107 // Move all instructions after the sequence to TailMBB.
10108 TailMBB->splice(TailMBB->end(), HeadMBB,
10109 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
10110 // Update machine-CFG edges by transferring all successors of the current
10111 // block to the new block which will contain the Phi nodes for the selects.
10112 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
10113 // Set the successors for HeadMBB.
10114 HeadMBB->addSuccessor(IfFalseMBB);
10115 HeadMBB->addSuccessor(TailMBB);
10116
10117 // Insert appropriate branch.
10118 if (MI.getOperand(2).isImm())
10119 BuildMI(HeadMBB, DL, TII.get(CC))
10120 .addReg(LHS)
10121 .addImm(MI.getOperand(2).getImm())
10122 .addMBB(TailMBB);
10123 else
10124 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
10125
10126 // IfFalseMBB just falls through to TailMBB.
10127 IfFalseMBB->addSuccessor(TailMBB);
10128
10129 // Create PHIs for all of the select pseudo-instructions.
10130 auto SelectMBBI = MI.getIterator();
10131 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
10132 auto InsertionPoint = TailMBB->begin();
10133 while (SelectMBBI != SelectEnd) {
10134 auto Next = std::next(SelectMBBI);
10135 if (isSelectPseudo(*SelectMBBI)) {
10136 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
10137 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
10138 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
10139 .addReg(SelectMBBI->getOperand(4).getReg())
10140 .addMBB(HeadMBB)
10141 .addReg(SelectMBBI->getOperand(5).getReg())
10142 .addMBB(IfFalseMBB);
10143 SelectMBBI->eraseFromParent();
10144 }
10145 SelectMBBI = Next;
10146 }
10147
10148 F->getProperties().resetNoPHIs();
10149 return TailMBB;
10150}
10151
10152MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
10153 MachineInstr &MI, MachineBasicBlock *BB) const {
10154 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
10155 DebugLoc DL = MI.getDebugLoc();
10156
10157 switch (MI.getOpcode()) {
10158 default:
10159 llvm_unreachable("Unexpected instr type to insert");
10160 case LoongArch::DIV_W:
10161 case LoongArch::DIV_WU:
10162 case LoongArch::MOD_W:
10163 case LoongArch::MOD_WU:
10164 case LoongArch::DIV_D:
10165 case LoongArch::DIV_DU:
10166 case LoongArch::MOD_D:
10167 case LoongArch::MOD_DU:
10168 return insertDivByZeroTrap(MI, BB);
10169 break;
10170 case LoongArch::WRFCSR: {
10171 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
10172 LoongArch::FCSR0 + MI.getOperand(0).getImm())
10173 .addReg(MI.getOperand(1).getReg());
10174 MI.eraseFromParent();
10175 return BB;
10176 }
10177 case LoongArch::RDFCSR: {
10178 MachineInstr *ReadFCSR =
10179 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
10180 MI.getOperand(0).getReg())
10181 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
10182 ReadFCSR->getOperand(1).setIsUndef();
10183 MI.eraseFromParent();
10184 return BB;
10185 }
10186 case LoongArch::Select_GPR_Using_CC_GPR:
10187 return emitSelectPseudo(MI, BB, Subtarget);
10188 case LoongArch::BuildPairF64Pseudo:
10189 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
10190 case LoongArch::SplitPairF64Pseudo:
10191 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
10192 case LoongArch::PseudoXVINSGR2VR_B:
10193 case LoongArch::PseudoXVINSGR2VR_H:
10194 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
10195 case LoongArch::PseudoCTPOP_B:
10196 case LoongArch::PseudoCTPOP_H:
10197 case LoongArch::PseudoCTPOP_W:
10198 case LoongArch::PseudoCTPOP_D:
10199 case LoongArch::PseudoCTPOP_H_LA32:
10200 case LoongArch::PseudoCTPOP_W_LA32:
10201 return emitPseudoCTPOP(MI, BB, Subtarget);
10202 case LoongArch::PseudoVMSKLTZ_B:
10203 case LoongArch::PseudoVMSKLTZ_H:
10204 case LoongArch::PseudoVMSKLTZ_W:
10205 case LoongArch::PseudoVMSKLTZ_D:
10206 case LoongArch::PseudoVMSKGEZ_B:
10207 case LoongArch::PseudoVMSKEQZ_B:
10208 case LoongArch::PseudoVMSKNEZ_B:
10209 case LoongArch::PseudoXVMSKLTZ_B:
10210 case LoongArch::PseudoXVMSKLTZ_H:
10211 case LoongArch::PseudoXVMSKLTZ_W:
10212 case LoongArch::PseudoXVMSKLTZ_D:
10213 case LoongArch::PseudoXVMSKGEZ_B:
10214 case LoongArch::PseudoXVMSKEQZ_B:
10215 case LoongArch::PseudoXVMSKNEZ_B:
10216 return emitPseudoVMSKCOND(MI, BB, Subtarget);
10217 case TargetOpcode::STATEPOINT:
10218 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
10219 // while bl call instruction (where statepoint will be lowered at the
10220 // end) has implicit def. This def is early-clobber as it will be set at
10221 // the moment of the call and earlier than any use is read.
10222 // Add this implicit dead def here as a workaround.
10223 MI.addOperand(*MI.getMF(),
10225 LoongArch::R1, /*isDef*/ true,
10226 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
10227 /*isUndef*/ false, /*isEarlyClobber*/ true));
10228 if (!Subtarget.is64Bit())
10229 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
10230 return emitPatchPoint(MI, BB);
10231 case LoongArch::PROBED_STACKALLOC_DYN:
10232 return emitDynamicProbedAlloc(MI, BB);
10233 }
10234}
10235
10237 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
10238 unsigned *Fast) const {
10239 if (!Subtarget.hasUAL())
10240 return false;
10241
10242 // TODO: set reasonable speed number.
10243 if (Fast)
10244 *Fast = 1;
10245 return true;
10246}
10247
10248//===----------------------------------------------------------------------===//
10249// Calling Convention Implementation
10250//===----------------------------------------------------------------------===//
10251
10252// Eight general-purpose registers a0-a7 used for passing integer arguments,
10253// with a0-a1 reused to return values. Generally, the GPRs are used to pass
10254// fixed-point arguments, and floating-point arguments when no FPR is available
10255// or with soft float ABI.
10256const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
10257 LoongArch::R7, LoongArch::R8, LoongArch::R9,
10258 LoongArch::R10, LoongArch::R11};
10259
10260// PreserveNone calling convention:
10261// Arguments may be passed in any general-purpose registers except:
10262// - R1 : return address register
10263// - R22 : frame pointer
10264// - R31 : base pointer
10265//
10266// All general-purpose registers are treated as caller-saved,
10267// except R1 (RA) and R22 (FP).
10268//
10269// Non-volatile registers are allocated first so that a function
10270// can call normal functions without having to spill and reload
10271// argument registers.
10273 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
10274 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
10275 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
10276 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
10277 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
10278 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
10279 LoongArch::R20};
10280
10281// Eight floating-point registers fa0-fa7 used for passing floating-point
10282// arguments, and fa0-fa1 are also used to return values.
10283const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
10284 LoongArch::F3, LoongArch::F4, LoongArch::F5,
10285 LoongArch::F6, LoongArch::F7};
10286// FPR32 and FPR64 alias each other.
10288 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
10289 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
10290
10291const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
10292 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
10293 LoongArch::VR6, LoongArch::VR7};
10294
10295const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
10296 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
10297 LoongArch::XR6, LoongArch::XR7};
10298
10300 switch (State.getCallingConv()) {
10302 if (!State.isVarArg())
10303 return State.AllocateReg(PreserveNoneArgGPRs);
10304 [[fallthrough]];
10305 default:
10306 return State.AllocateReg(ArgGPRs);
10307 }
10308}
10309
10310// Pass a 2*GRLen argument that has been split into two GRLen values through
10311// registers or the stack as necessary.
10312static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
10313 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
10314 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
10315 ISD::ArgFlagsTy ArgFlags2) {
10316 unsigned GRLenInBytes = GRLen / 8;
10317 if (Register Reg = allocateArgGPR(State)) {
10318 // At least one half can be passed via register.
10319 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
10320 VA1.getLocVT(), CCValAssign::Full));
10321 } else {
10322 // Both halves must be passed on the stack, with proper alignment.
10323 Align StackAlign =
10324 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
10325 State.addLoc(
10327 State.AllocateStack(GRLenInBytes, StackAlign),
10328 VA1.getLocVT(), CCValAssign::Full));
10329 State.addLoc(CCValAssign::getMem(
10330 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
10331 LocVT2, CCValAssign::Full));
10332 return false;
10333 }
10334 if (Register Reg = allocateArgGPR(State)) {
10335 // The second half can also be passed via register.
10336 State.addLoc(
10337 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
10338 } else {
10339 // The second half is passed via the stack, without additional alignment.
10340 State.addLoc(CCValAssign::getMem(
10341 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
10342 LocVT2, CCValAssign::Full));
10343 }
10344 return false;
10345}
10346
10347// Implements the LoongArch calling convention. Returns true upon failure.
10349 unsigned ValNo, MVT ValVT,
10350 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
10351 CCState &State, bool IsRet, Type *OrigTy) {
10352 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
10353 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
10354 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
10355 MVT LocVT = ValVT;
10356
10357 // Any return value split into more than two values can't be returned
10358 // directly.
10359 if (IsRet && ValNo > 1)
10360 return true;
10361
10362 // If passing a variadic argument, or if no FPR is available.
10363 bool UseGPRForFloat = true;
10364
10365 switch (ABI) {
10366 default:
10367 llvm_unreachable("Unexpected ABI");
10368 break;
10373 UseGPRForFloat = ArgFlags.isVarArg();
10374 break;
10377 break;
10378 }
10379
10380 // If this is a variadic argument, the LoongArch calling convention requires
10381 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
10382 // byte alignment. An aligned register should be used regardless of whether
10383 // the original argument was split during legalisation or not. The argument
10384 // will not be passed by registers if the original type is larger than
10385 // 2*GRLen, so the register alignment rule does not apply.
10386 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
10387 if (ArgFlags.isVarArg() &&
10388 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
10389 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
10390 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
10391 // Skip 'odd' register if necessary.
10392 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
10393 State.AllocateReg(ArgGPRs);
10394 }
10395
10396 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
10397 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
10398 State.getPendingArgFlags();
10399
10400 assert(PendingLocs.size() == PendingArgFlags.size() &&
10401 "PendingLocs and PendingArgFlags out of sync");
10402
10403 // FPR32 and FPR64 alias each other.
10404 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
10405 UseGPRForFloat = true;
10406
10407 if (UseGPRForFloat && ValVT == MVT::f32) {
10408 LocVT = GRLenVT;
10409 LocInfo = CCValAssign::BCvt;
10410 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
10411 LocVT = MVT::i64;
10412 LocInfo = CCValAssign::BCvt;
10413 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
10414 // Handle passing f64 on LA32D with a soft float ABI or when floating point
10415 // registers are exhausted.
10416 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
10417 // Depending on available argument GPRS, f64 may be passed in a pair of
10418 // GPRs, split between a GPR and the stack, or passed completely on the
10419 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
10420 // cases.
10421 MCRegister Reg = allocateArgGPR(State);
10422 if (!Reg) {
10423 int64_t StackOffset = State.AllocateStack(8, Align(8));
10424 State.addLoc(
10425 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10426 return false;
10427 }
10428 LocVT = MVT::i32;
10429 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10430 MCRegister HiReg = allocateArgGPR(State);
10431 if (HiReg) {
10432 State.addLoc(
10433 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
10434 } else {
10435 int64_t StackOffset = State.AllocateStack(4, Align(4));
10436 State.addLoc(
10437 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10438 }
10439 return false;
10440 }
10441
10442 // Split arguments might be passed indirectly, so keep track of the pending
10443 // values.
10444 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
10445 LocVT = GRLenVT;
10446 LocInfo = CCValAssign::Indirect;
10447 PendingLocs.push_back(
10448 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
10449 PendingArgFlags.push_back(ArgFlags);
10450 if (!ArgFlags.isSplitEnd()) {
10451 return false;
10452 }
10453 }
10454
10455 // If the split argument only had two elements, it should be passed directly
10456 // in registers or on the stack.
10457 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
10458 PendingLocs.size() <= 2) {
10459 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
10460 // Apply the normal calling convention rules to the first half of the
10461 // split argument.
10462 CCValAssign VA = PendingLocs[0];
10463 ISD::ArgFlagsTy AF = PendingArgFlags[0];
10464 PendingLocs.clear();
10465 PendingArgFlags.clear();
10466 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
10467 ArgFlags);
10468 }
10469
10470 // Allocate to a register if possible, or else a stack slot.
10471 Register Reg;
10472 unsigned StoreSizeBytes = GRLen / 8;
10473 Align StackAlign = Align(GRLen / 8);
10474
10475 if (ValVT == MVT::f32 && !UseGPRForFloat) {
10476 Reg = State.AllocateReg(ArgFPR32s);
10477 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
10478 Reg = State.AllocateReg(ArgFPR64s);
10479 } else if (ValVT.is128BitVector()) {
10480 Reg = State.AllocateReg(ArgVRs);
10481 UseGPRForFloat = false;
10482 StoreSizeBytes = 16;
10483 StackAlign = Align(16);
10484 } else if (ValVT.is256BitVector()) {
10485 Reg = State.AllocateReg(ArgXRs);
10486 UseGPRForFloat = false;
10487 StoreSizeBytes = 32;
10488 StackAlign = Align(32);
10489 } else {
10490 Reg = allocateArgGPR(State);
10491 }
10492
10493 unsigned StackOffset =
10494 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
10495
10496 // If we reach this point and PendingLocs is non-empty, we must be at the
10497 // end of a split argument that must be passed indirectly.
10498 if (!PendingLocs.empty()) {
10499 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
10500 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
10501 for (auto &It : PendingLocs) {
10502 if (Reg)
10503 It.convertToReg(Reg);
10504 else
10505 It.convertToMem(StackOffset);
10506 State.addLoc(It);
10507 }
10508 PendingLocs.clear();
10509 PendingArgFlags.clear();
10510 return false;
10511 }
10512 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
10513 "Expected an GRLenVT at this stage");
10514
10515 if (Reg) {
10516 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10517 return false;
10518 }
10519
10520 // When a floating-point value is passed on the stack, no bit-cast is needed.
10521 if (ValVT.isFloatingPoint()) {
10522 LocVT = ValVT;
10523 LocInfo = CCValAssign::Full;
10524 }
10525
10526 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
10527 return false;
10528}
10529
10530void LoongArchTargetLowering::analyzeInputArgs(
10531 MachineFunction &MF, CCState &CCInfo,
10532 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
10533 LoongArchCCAssignFn Fn) const {
10534 FunctionType *FType = MF.getFunction().getFunctionType();
10535 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
10536 MVT ArgVT = Ins[i].VT;
10537 Type *ArgTy = nullptr;
10538 if (IsRet)
10539 ArgTy = FType->getReturnType();
10540 else if (Ins[i].isOrigArg())
10541 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
10543 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10544 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
10545 CCInfo, IsRet, ArgTy)) {
10546 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
10547 << '\n');
10548 llvm_unreachable("");
10549 }
10550 }
10551}
10552
10553void LoongArchTargetLowering::analyzeOutputArgs(
10554 MachineFunction &MF, CCState &CCInfo,
10555 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
10556 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
10557 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10558 MVT ArgVT = Outs[i].VT;
10559 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
10561 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10562 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
10563 CCInfo, IsRet, OrigTy)) {
10564 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
10565 << "\n");
10566 llvm_unreachable("");
10567 }
10568 }
10569}
10570
10571// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
10572// values.
10574 const CCValAssign &VA, const SDLoc &DL) {
10575 switch (VA.getLocInfo()) {
10576 default:
10577 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10578 case CCValAssign::Full:
10580 break;
10581 case CCValAssign::BCvt:
10582 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10583 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
10584 else
10585 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10586 break;
10587 }
10588 return Val;
10589}
10590
10592 const CCValAssign &VA, const SDLoc &DL,
10593 const ISD::InputArg &In,
10597 EVT LocVT = VA.getLocVT();
10598 SDValue Val;
10599 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
10600 Register VReg = RegInfo.createVirtualRegister(RC);
10601 RegInfo.addLiveIn(VA.getLocReg(), VReg);
10602 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
10603
10604 // If input is sign extended from 32 bits, note it for the OptW pass.
10605 if (In.isOrigArg()) {
10606 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
10607 if (OrigArg->getType()->isIntegerTy()) {
10608 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
10609 // An input zero extended from i31 can also be considered sign extended.
10610 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
10611 (BitWidth < 32 && In.Flags.isZExt())) {
10614 LAFI->addSExt32Register(VReg);
10615 }
10616 }
10617 }
10618
10619 return convertLocVTToValVT(DAG, Val, VA, DL);
10620}
10621
10622// The caller is responsible for loading the full value if the argument is
10623// passed with CCValAssign::Indirect.
10625 const CCValAssign &VA, const SDLoc &DL) {
10627 MachineFrameInfo &MFI = MF.getFrameInfo();
10628 EVT ValVT = VA.getValVT();
10629 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
10630 /*IsImmutable=*/true);
10631 SDValue FIN = DAG.getFrameIndex(
10633
10634 ISD::LoadExtType ExtType;
10635 switch (VA.getLocInfo()) {
10636 default:
10637 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10638 case CCValAssign::Full:
10640 case CCValAssign::BCvt:
10641 ExtType = ISD::NON_EXTLOAD;
10642 break;
10643 }
10644 return DAG.getExtLoad(
10645 ExtType, DL, VA.getLocVT(), Chain, FIN,
10647}
10648
10650 const CCValAssign &VA,
10651 const CCValAssign &HiVA,
10652 const SDLoc &DL) {
10653 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
10654 "Unexpected VA");
10656 MachineFrameInfo &MFI = MF.getFrameInfo();
10658
10659 assert(VA.isRegLoc() && "Expected register VA assignment");
10660
10661 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10662 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
10663 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
10664 SDValue Hi;
10665 if (HiVA.isMemLoc()) {
10666 // Second half of f64 is passed on the stack.
10667 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
10668 /*IsImmutable=*/true);
10669 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
10670 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
10672 } else {
10673 // Second half of f64 is passed in another GPR.
10674 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10675 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
10676 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
10677 }
10678 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
10679}
10680
10682 const CCValAssign &VA, const SDLoc &DL) {
10683 EVT LocVT = VA.getLocVT();
10684
10685 switch (VA.getLocInfo()) {
10686 default:
10687 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10688 case CCValAssign::Full:
10689 break;
10690 case CCValAssign::BCvt:
10691 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10692 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
10693 else
10694 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10695 break;
10696 }
10697 return Val;
10698}
10699
10700static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
10701 CCValAssign::LocInfo LocInfo,
10702 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
10703 CCState &State) {
10704 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
10705 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
10706 // s0 s1 s2 s3 s4 s5 s6 s7 s8
10707 static const MCPhysReg GPRList[] = {
10708 LoongArch::R23, LoongArch::R24, LoongArch::R25,
10709 LoongArch::R26, LoongArch::R27, LoongArch::R28,
10710 LoongArch::R29, LoongArch::R30, LoongArch::R31};
10711 if (MCRegister Reg = State.AllocateReg(GPRList)) {
10712 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10713 return false;
10714 }
10715 }
10716
10717 if (LocVT == MVT::f32) {
10718 // Pass in STG registers: F1, F2, F3, F4
10719 // fs0,fs1,fs2,fs3
10720 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
10721 LoongArch::F26, LoongArch::F27};
10722 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
10723 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10724 return false;
10725 }
10726 }
10727
10728 if (LocVT == MVT::f64) {
10729 // Pass in STG registers: D1, D2, D3, D4
10730 // fs4,fs5,fs6,fs7
10731 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
10732 LoongArch::F30_64, LoongArch::F31_64};
10733 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
10734 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10735 return false;
10736 }
10737 }
10738
10739 report_fatal_error("No registers left in GHC calling convention");
10740 return true;
10741}
10742
10743// Transform physical registers into virtual registers.
10745 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10746 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
10747 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
10748
10750
10751 switch (CallConv) {
10752 default:
10753 llvm_unreachable("Unsupported calling convention");
10754 case CallingConv::C:
10755 case CallingConv::Fast:
10758 break;
10759 case CallingConv::GHC:
10760 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
10761 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
10763 "GHC calling convention requires the F and D extensions");
10764 }
10765
10766 const Function &Func = MF.getFunction();
10767 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10768 MVT GRLenVT = Subtarget.getGRLenVT();
10769 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
10770
10771 // Check if this function has any musttail calls. If so, incoming indirect
10772 // arg pointers must be saved in virtual registers so they survive across
10773 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
10774 // when needed to avoid adding register pressure to non-musttail functions.
10775 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
10776 return llvm::any_of(BB, [](const Instruction &I) {
10777 if (const auto *CI = dyn_cast<CallInst>(&I))
10778 return CI->isMustTailCall();
10779 return false;
10780 });
10781 });
10782 // Used with varargs to acumulate store chains.
10783 std::vector<SDValue> OutChains;
10784
10785 // Assign locations to all of the incoming arguments.
10787 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10788
10789 if (CallConv == CallingConv::GHC)
10791 else
10792 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
10793
10794 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10795 CCValAssign &VA = ArgLocs[i];
10796 SDValue ArgValue;
10797 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10798 // case.
10799 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10800 assert(VA.needsCustom());
10801 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10802 } else if (VA.isRegLoc())
10803 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10804 else
10805 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10806 if (VA.getLocInfo() == CCValAssign::Indirect) {
10807 // If the original argument was split and passed by reference, we need to
10808 // load all parts of it here (using the same address).
10809 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10811 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10812 if (HasMusttail) {
10815 Register VReg =
10816 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10817 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10818 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10819 }
10820 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10821 assert(ArgPartOffset == 0);
10822 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10823 CCValAssign &PartVA = ArgLocs[i + 1];
10824 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10825 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10826 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10827 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10829 ++i;
10830 ++InsIdx;
10831 }
10832 continue;
10833 }
10834 InVals.push_back(ArgValue);
10835 }
10836
10837 if (IsVarArg) {
10839 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10840 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10841 MachineFrameInfo &MFI = MF.getFrameInfo();
10842 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10843 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10844
10845 // Offset of the first variable argument from stack pointer, and size of
10846 // the vararg save area. For now, the varargs save area is either zero or
10847 // large enough to hold a0-a7.
10848 int VaArgOffset, VarArgsSaveSize;
10849
10850 // If all registers are allocated, then all varargs must be passed on the
10851 // stack and we don't need to save any argregs.
10852 if (ArgRegs.size() == Idx) {
10853 VaArgOffset = CCInfo.getStackSize();
10854 VarArgsSaveSize = 0;
10855 } else {
10856 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10857 VaArgOffset = -VarArgsSaveSize;
10858 }
10859
10860 // Record the frame index of the first variable argument
10861 // which is a value necessary to VASTART.
10862 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10863 LoongArchFI->setVarArgsFrameIndex(FI);
10864
10865 // If saving an odd number of registers then create an extra stack slot to
10866 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10867 // offsets to even-numbered registered remain 2*GRLen-aligned.
10868 if (Idx % 2) {
10869 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10870 true);
10871 VarArgsSaveSize += GRLenInBytes;
10872 }
10873
10874 // Copy the integer registers that may have been used for passing varargs
10875 // to the vararg save area.
10876 for (unsigned I = Idx; I < ArgRegs.size();
10877 ++I, VaArgOffset += GRLenInBytes) {
10878 const Register Reg = RegInfo.createVirtualRegister(RC);
10879 RegInfo.addLiveIn(ArgRegs[I], Reg);
10880 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10881 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10882 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10883 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10885 cast<StoreSDNode>(Store.getNode())
10886 ->getMemOperand()
10887 ->setValue((Value *)nullptr);
10888 OutChains.push_back(Store);
10889 }
10890 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10891 }
10892
10893 // All stores are grouped in one node to allow the matching between
10894 // the size of Ins and InVals. This only happens for vararg functions.
10895 if (!OutChains.empty()) {
10896 OutChains.push_back(Chain);
10897 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10898 }
10899
10900 return Chain;
10901}
10902
10904 return CI->isTailCall();
10905}
10906
10907// Check if the return value is used as only a return value, as otherwise
10908// we can't perform a tail-call.
10910 SDValue &Chain) const {
10911 if (N->getNumValues() != 1)
10912 return false;
10913 if (!N->hasNUsesOfValue(1, 0))
10914 return false;
10915
10916 SDNode *Copy = *N->user_begin();
10917 if (Copy->getOpcode() != ISD::CopyToReg)
10918 return false;
10919
10920 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10921 // isn't safe to perform a tail call.
10922 if (Copy->getGluedNode())
10923 return false;
10924
10925 // The copy must be used by a LoongArchISD::RET, and nothing else.
10926 bool HasRet = false;
10927 for (SDNode *Node : Copy->users()) {
10928 if (Node->getOpcode() != LoongArchISD::RET)
10929 return false;
10930 HasRet = true;
10931 }
10932
10933 if (!HasRet)
10934 return false;
10935
10936 Chain = Copy->getOperand(0);
10937 return true;
10938}
10939
10940// Check whether the call is eligible for tail call optimization.
10941bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10942 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10943 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10944
10945 auto CalleeCC = CLI.CallConv;
10946 auto &Outs = CLI.Outs;
10947 auto &Caller = MF.getFunction();
10948 auto CallerCC = Caller.getCallingConv();
10949
10950 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10951
10952 // Byval parameters hand the function a pointer directly into the stack area
10953 // we want to reuse during a tail call. Working around this *is* possible
10954 // but less efficient and uglier in LowerCall. For musttail, there is no
10955 // workaround today: a byval arg requires a local copy that becomes invalid
10956 // after the tail call deallocates the caller's frame, so rejecting here
10957 // (and triggering reportFatalInternalError in LowerCall) is safer than
10958 // miscompiling.
10959 for (auto &Arg : Outs)
10960 if (Arg.Flags.isByVal())
10961 return false;
10962
10963 // musttail bypasses the remaining checks: the checks either reject cases
10964 // we handle specially (indirect args are forwarded via incoming pointers,
10965 // stack-passed args reuse the matching incoming layout, sret is forwarded
10966 // like any other pointer arg) or are optimizations not applicable to
10967 // mandatory tail calls.
10968 if (IsMustTail)
10969 return true;
10970
10971 // Do not tail call opt if the stack is used to pass parameters.
10972 if (CCInfo.getStackSize() != 0)
10973 return false;
10974
10975 // Do not tail call opt if any parameters need to be passed indirectly.
10976 for (auto &VA : ArgLocs)
10977 if (VA.getLocInfo() == CCValAssign::Indirect)
10978 return false;
10979
10980 // Do not tail call opt if either caller or callee uses struct return
10981 // semantics.
10982 auto IsCallerStructRet = Caller.hasStructRetAttr();
10983 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10984 if (IsCallerStructRet || IsCalleeStructRet)
10985 return false;
10986
10987 // The callee has to preserve all registers the caller needs to preserve.
10988 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10989 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10990 if (CalleeCC != CallerCC) {
10991 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10992 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10993 return false;
10994 }
10995 return true;
10996}
10997
10999 return DAG.getDataLayout().getPrefTypeAlign(
11000 VT.getTypeForEVT(*DAG.getContext()));
11001}
11002
11003// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
11004// and output parameter nodes.
11005SDValue
11007 SmallVectorImpl<SDValue> &InVals) const {
11008 SelectionDAG &DAG = CLI.DAG;
11009 SDLoc &DL = CLI.DL;
11011 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
11013 SDValue Chain = CLI.Chain;
11014 SDValue Callee = CLI.Callee;
11015 CallingConv::ID CallConv = CLI.CallConv;
11016 bool IsVarArg = CLI.IsVarArg;
11017 EVT PtrVT = getPointerTy(DAG.getDataLayout());
11018 MVT GRLenVT = Subtarget.getGRLenVT();
11019 bool &IsTailCall = CLI.IsTailCall;
11020
11022
11023 // Analyze the operands of the call, assigning locations to each operand.
11025 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
11026
11027 if (CallConv == CallingConv::GHC)
11028 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
11029 else
11030 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
11031
11032 // Check if it's really possible to do a tail call.
11033 if (IsTailCall)
11034 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
11035
11036 if (IsTailCall)
11037 ++NumTailCalls;
11038 else if (CLI.CB && CLI.CB->isMustTailCall())
11039 report_fatal_error("failed to perform tail call elimination on a call "
11040 "site marked musttail");
11041
11042 // Get a count of how many bytes are to be pushed on the stack.
11043 unsigned NumBytes = ArgCCInfo.getStackSize();
11044
11045 // Create local copies for byval args.
11046 SmallVector<SDValue> ByValArgs;
11047 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
11048 ISD::ArgFlagsTy Flags = Outs[i].Flags;
11049 if (!Flags.isByVal())
11050 continue;
11051
11052 SDValue Arg = OutVals[i];
11053 unsigned Size = Flags.getByValSize();
11054 Align Alignment = Flags.getNonZeroByValAlign();
11055
11056 int FI =
11057 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
11058 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
11059 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
11060
11061 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
11062 /*IsVolatile=*/false,
11063 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
11065 ByValArgs.push_back(FIPtr);
11066 }
11067
11068 if (!IsTailCall)
11069 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
11070
11071 // Copy argument values to their designated locations.
11073 SmallVector<SDValue> MemOpChains;
11074 SDValue StackPtr;
11075 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
11076 ++i, ++OutIdx) {
11077 CCValAssign &VA = ArgLocs[i];
11078 SDValue ArgValue = OutVals[OutIdx];
11079 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
11080
11081 // Handle passing f64 on LA32D with a soft float ABI as a special case.
11082 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
11083 assert(VA.isRegLoc() && "Expected register VA assignment");
11084 assert(VA.needsCustom());
11085 SDValue SplitF64 =
11086 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
11087 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
11088 SDValue Lo = SplitF64.getValue(0);
11089 SDValue Hi = SplitF64.getValue(1);
11090
11091 Register RegLo = VA.getLocReg();
11092 RegsToPass.push_back(std::make_pair(RegLo, Lo));
11093
11094 // Get the CCValAssign for the Hi part.
11095 CCValAssign &HiVA = ArgLocs[++i];
11096
11097 if (HiVA.isMemLoc()) {
11098 // Second half of f64 is passed on the stack.
11099 if (!StackPtr.getNode())
11100 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
11102 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
11103 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
11104 // Emit the store.
11105 MemOpChains.push_back(DAG.getStore(
11106 Chain, DL, Hi, Address,
11108 } else {
11109 // Second half of f64 is passed in another GPR.
11110 Register RegHigh = HiVA.getLocReg();
11111 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
11112 }
11113 continue;
11114 }
11115
11116 // Promote the value if needed.
11117 // For now, only handle fully promoted and indirect arguments.
11118 if (VA.getLocInfo() == CCValAssign::Indirect) {
11119 // For musttail calls, reuse incoming indirect pointers instead of
11120 // creating new stack temporaries. The incoming pointers point to the
11121 // caller's caller's frame, which remains valid after a tail call.
11122 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
11125 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
11126
11127 // Resolve which formal parameter is being passed at this call
11128 // position.
11129 //
11130 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
11131 // but Outs[].OrigArgIndex is an index into a filtered arg list
11132 // (empty types removed, via CallLoweringInfo in the target-
11133 // independent layer). IncomingIndirectArgs is keyed by the
11134 // caller's unfiltered Argument::getArgNo(), so we have to walk
11135 // the caller's formals (same filter) to translate the index.
11136 // This target-independent asymmetry should be normalized so
11137 // backends do not need to re-derive the mapping.
11138 //
11139 // Steps:
11140 // 1. Find the call operand at filtered position CallArgIdx.
11141 // 2. If it is an Argument, use getArgNo() directly (same filter
11142 // for caller formals and call operands).
11143 // 3. Otherwise (computed value), walk the caller's formals and
11144 // skip empty types to map the filtered index to getArgNo().
11145 const Argument *FormalArg = nullptr;
11146 unsigned FilteredIdx = 0;
11147 for (const auto &CallArg : CLI.CB->args()) {
11148 if (CallArg->getType()->isEmptyTy())
11149 continue;
11150 if (FilteredIdx == CallArgIdx) {
11151 FormalArg = dyn_cast<Argument>(CallArg);
11152 break;
11153 }
11154 ++FilteredIdx;
11155 }
11156
11157 // For forwarded args, getArgNo() gives the unfiltered index directly.
11158 // For computed args, walk the caller's formals to resolve it.
11159 unsigned FormalArgIdx = CallArgIdx;
11160 if (FormalArg) {
11161 FormalArgIdx = FormalArg->getArgNo();
11162 } else {
11163 FilteredIdx = 0;
11164 for (const auto &Arg : MF.getFunction().args()) {
11165 if (Arg.getType()->isEmptyTy())
11166 continue;
11167 if (FilteredIdx == CallArgIdx) {
11168 FormalArgIdx = Arg.getArgNo();
11169 break;
11170 }
11171 ++FilteredIdx;
11172 }
11173 }
11174
11175 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
11176 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
11177 // Thread the CopyFromReg output chain through MemOpChains so the
11178 // TokenFactor below sequences the copy with any stores we emit
11179 // for this argument.
11180 MemOpChains.push_back(CopyOp.getValue(1));
11181 SDValue IncomingPtr = CopyOp;
11182
11183 if (!FormalArg) {
11184 // Computed value: store into the incoming indirect pointer for the
11185 // same-position formal parameter (musttail guarantees matching
11186 // prototypes, so types match). The pointer survives the tail call
11187 // since it points to the caller's caller's frame.
11188 //
11189 // The data-flow edge through IncomingPtr already prevents the
11190 // store from being scheduled before the CopyFromReg. Threading
11191 // CopyOp.getValue(1) (the copy's output chain) into the store
11192 // makes that ordering explicit on the chain edge as well, which
11193 // is the convention for memory ops chaining off their producers.
11194 MemOpChains.push_back(
11195 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
11197 // Store any split parts at their respective offsets.
11198 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
11199 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
11200 SDValue PartValue = OutVals[OutIdx + 1];
11201 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
11202 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
11203 SDValue Addr =
11204 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
11205 MemOpChains.push_back(
11206 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
11208 ++i;
11209 ++OutIdx;
11210 }
11211 }
11212 ArgValue = IncomingPtr;
11213
11214 // Skip any remaining split parts (for forwarded args, they are
11215 // covered by the forwarded pointer).
11216 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
11217 ++i;
11218 ++OutIdx;
11219 }
11220 } else {
11221 // Store the argument in a stack slot and pass its address.
11222 Align StackAlign =
11223 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
11224 getPrefTypeAlign(ArgValue.getValueType(), DAG));
11225 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
11226 // If the original argument was split and passed by reference, we need
11227 // to store the required parts of it here (and pass just one address).
11228 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
11229 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
11230 assert(ArgPartOffset == 0);
11231 // Calculate the total size to store. We don't have access to what we're
11232 // actually storing other than performing the loop and collecting the
11233 // info.
11235 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
11236 SDValue PartValue = OutVals[OutIdx + 1];
11237 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
11238 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
11239 EVT PartVT = PartValue.getValueType();
11240 StoredSize += PartVT.getStoreSize();
11241 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
11242 Parts.push_back(std::make_pair(PartValue, Offset));
11243 ++i;
11244 ++OutIdx;
11245 }
11246 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
11247 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
11248 MemOpChains.push_back(
11249 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
11251 for (const auto &Part : Parts) {
11252 SDValue PartValue = Part.first;
11253 SDValue PartOffset = Part.second;
11255 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
11256 MemOpChains.push_back(
11257 DAG.getStore(Chain, DL, PartValue, Address,
11259 }
11260 ArgValue = SpillSlot;
11261 }
11262 } else {
11263 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
11264 }
11265
11266 // Use local copy if it is a byval arg.
11267 if (Flags.isByVal())
11268 ArgValue = ByValArgs[j++];
11269
11270 if (VA.isRegLoc()) {
11271 // Queue up the argument copies and emit them at the end.
11272 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
11273 } else {
11274 assert(VA.isMemLoc() && "Argument not register or memory");
11275 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
11276 "Tail call not allowed if stack is used for passing parameters");
11277
11278 // Work out the address of the stack slot.
11279 if (!StackPtr.getNode())
11280 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
11282 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
11284
11285 // Emit the store.
11286 MemOpChains.push_back(
11287 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
11288 }
11289 }
11290
11291 // Join the stores, which are independent of one another.
11292 if (!MemOpChains.empty())
11293 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
11294
11295 SDValue Glue;
11296
11297 // Build a sequence of copy-to-reg nodes, chained and glued together.
11298 for (auto &Reg : RegsToPass) {
11299 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
11300 Glue = Chain.getValue(1);
11301 }
11302
11303 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
11304 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
11305 // split it and then direct call can be matched by PseudoCALL_SMALL.
11307 const GlobalValue *GV = S->getGlobal();
11308 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
11311 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
11312 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
11313 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
11316 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
11317 }
11318
11319 // The first call operand is the chain and the second is the target address.
11321 Ops.push_back(Chain);
11322 Ops.push_back(Callee);
11323
11324 // Add argument registers to the end of the list so that they are
11325 // known live into the call.
11326 for (auto &Reg : RegsToPass)
11327 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
11328
11329 if (!IsTailCall) {
11330 // Add a register mask operand representing the call-preserved registers.
11331 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
11332 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
11333 assert(Mask && "Missing call preserved mask for calling convention");
11334 Ops.push_back(DAG.getRegisterMask(Mask));
11335 }
11336
11337 // Glue the call to the argument copies, if any.
11338 if (Glue.getNode())
11339 Ops.push_back(Glue);
11340
11341 // Emit the call.
11342 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
11343 unsigned Op;
11344 switch (DAG.getTarget().getCodeModel()) {
11345 default:
11346 report_fatal_error("Unsupported code model");
11347 case CodeModel::Small:
11348 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
11349 break;
11350 case CodeModel::Medium:
11351 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
11352 break;
11353 case CodeModel::Large:
11354 assert(Subtarget.is64Bit() && "Large code model requires LA64");
11355 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
11356 break;
11357 }
11358
11359 if (IsTailCall) {
11361 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
11362 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
11363 return Ret;
11364 }
11365
11366 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
11367 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
11368 Glue = Chain.getValue(1);
11369
11370 // Mark the end of the call, which is glued to the call itself.
11371 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
11372 Glue = Chain.getValue(1);
11373
11374 // Assign locations to each value returned by this call.
11376 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
11377 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
11378
11379 // Copy all of the result registers out of their specified physreg.
11380 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
11381 auto &VA = RVLocs[i];
11382 // Copy the value out.
11383 SDValue RetValue =
11384 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
11385 // Glue the RetValue to the end of the call sequence.
11386 Chain = RetValue.getValue(1);
11387 Glue = RetValue.getValue(2);
11388
11389 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
11390 assert(VA.needsCustom());
11391 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
11392 MVT::i32, Glue);
11393 Chain = RetValue2.getValue(1);
11394 Glue = RetValue2.getValue(2);
11395 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
11396 RetValue, RetValue2);
11397 } else
11398 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
11399
11400 InVals.push_back(RetValue);
11401 }
11402
11403 return Chain;
11404}
11405
11407 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
11408 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
11409 const Type *RetTy) const {
11411 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
11412
11413 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
11414 LoongArchABI::ABI ABI =
11415 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
11416 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
11417 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
11418 return false;
11419 }
11420 return true;
11421}
11422
11424 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
11426 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
11427 SelectionDAG &DAG) const {
11428 // Stores the assignment of the return value to a location.
11430
11431 // Info about the registers and stack slot.
11432 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
11433 *DAG.getContext());
11434
11435 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
11436 nullptr, CC_LoongArch);
11437 if (CallConv == CallingConv::GHC && !RVLocs.empty())
11438 report_fatal_error("GHC functions return void only");
11439 SDValue Glue;
11440 SmallVector<SDValue, 4> RetOps(1, Chain);
11441
11442 // Copy the result values into the output registers.
11443 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
11444 SDValue Val = OutVals[OutIdx];
11445 CCValAssign &VA = RVLocs[i];
11446 assert(VA.isRegLoc() && "Can only return in registers!");
11447
11448 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
11449 // Handle returning f64 on LA32D with a soft float ABI.
11450 assert(VA.isRegLoc() && "Expected return via registers");
11451 assert(VA.needsCustom());
11452 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
11453 DAG.getVTList(MVT::i32, MVT::i32), Val);
11454 SDValue Lo = SplitF64.getValue(0);
11455 SDValue Hi = SplitF64.getValue(1);
11456 Register RegLo = VA.getLocReg();
11457 Register RegHi = RVLocs[++i].getLocReg();
11458
11459 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
11460 Glue = Chain.getValue(1);
11461 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
11462 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
11463 Glue = Chain.getValue(1);
11464 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
11465 } else {
11466 // Handle a 'normal' return.
11467 Val = convertValVTToLocVT(DAG, Val, VA, DL);
11468 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
11469
11470 // Guarantee that all emitted copies are stuck together.
11471 Glue = Chain.getValue(1);
11472 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
11473 }
11474 }
11475
11476 RetOps[0] = Chain; // Update chain.
11477
11478 // Add the glue node if we have it.
11479 if (Glue.getNode())
11480 RetOps.push_back(Glue);
11481
11482 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
11483}
11484
11485// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
11486// Note: The following prefixes are excluded:
11487// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
11488// as they can be represented using [x]vrepli.[whb]
11490 const APInt &SplatValue, const unsigned SplatBitSize) const {
11491 uint64_t RequiredImm = 0;
11492 uint64_t V = SplatValue.getZExtValue();
11493 if (SplatBitSize == 16 && !(V & 0x00FF)) {
11494 // 4'b0101
11495 RequiredImm = (0b10101 << 8) | (V >> 8);
11496 return {true, RequiredImm};
11497 } else if (SplatBitSize == 32) {
11498 // 4'b0001
11499 if (!(V & 0xFFFF00FF)) {
11500 RequiredImm = (0b10001 << 8) | (V >> 8);
11501 return {true, RequiredImm};
11502 }
11503 // 4'b0010
11504 if (!(V & 0xFF00FFFF)) {
11505 RequiredImm = (0b10010 << 8) | (V >> 16);
11506 return {true, RequiredImm};
11507 }
11508 // 4'b0011
11509 if (!(V & 0x00FFFFFF)) {
11510 RequiredImm = (0b10011 << 8) | (V >> 24);
11511 return {true, RequiredImm};
11512 }
11513 // 4'b0110
11514 if ((V & 0xFFFF00FF) == 0xFF) {
11515 RequiredImm = (0b10110 << 8) | (V >> 8);
11516 return {true, RequiredImm};
11517 }
11518 // 4'b0111
11519 if ((V & 0xFF00FFFF) == 0xFFFF) {
11520 RequiredImm = (0b10111 << 8) | (V >> 16);
11521 return {true, RequiredImm};
11522 }
11523 // 4'b1010
11524 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
11525 RequiredImm =
11526 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11527 return {true, RequiredImm};
11528 }
11529 } else if (SplatBitSize == 64) {
11530 // 4'b1011
11531 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
11532 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
11533 RequiredImm =
11534 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
11535 return {true, RequiredImm};
11536 }
11537 // 4'b1100
11538 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
11539 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
11540 RequiredImm =
11541 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
11542 return {true, RequiredImm};
11543 }
11544 // 4'b1001
11545 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
11546 uint8_t res = 0;
11547 for (int i = 0; i < 8; ++i) {
11548 uint8_t byte = x & 0xFF;
11549 if (byte == 0 || byte == 0xFF)
11550 res |= ((byte & 1) << i);
11551 else
11552 return {false, 0};
11553 x >>= 8;
11554 }
11555 return {true, res};
11556 };
11557 auto [IsSame, Suffix] = sameBitsPreByte(V);
11558 if (IsSame) {
11559 RequiredImm = (0b11001 << 8) | Suffix;
11560 return {true, RequiredImm};
11561 }
11562 }
11563 return {false, RequiredImm};
11564}
11565
11567 EVT VT) const {
11568 if (!Subtarget.hasExtLSX())
11569 return false;
11570
11571 if (VT == MVT::f32) {
11572 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
11573 return (masked == 0x3e000000 || masked == 0x40000000);
11574 }
11575
11576 if (VT == MVT::f64) {
11577 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
11578 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
11579 }
11580
11581 return false;
11582}
11583
11584// Only form FP_TO_SINT_SAT from clamp/NaN-guard idioms when it will be lowered
11585// to a single [X]VFTINTRZ/FTINTRZ, otherwise the generic expansion is worse
11586// than the original sequence.
11587bool LoongArchTargetLowering::shouldConvertFpToSat(unsigned Op, EVT FPVT,
11588 EVT VT) const {
11589 if (!isOperationLegalOrCustom(Op, VT))
11590 return false;
11591 if (VT.isVector())
11592 return FPVT.getScalarSizeInBits() == VT.getScalarSizeInBits();
11593 if (FPVT == MVT::f32)
11594 return VT.getSizeInBits() == 32 || Subtarget.hasBasicD();
11595 return FPVT == MVT::f64 && Subtarget.hasBasicD();
11596}
11597
11599LoongArchTargetLowering::getFPImmAction(const APFloat &Imm, EVT VT,
11600 bool ForCodeSize) const {
11601 // TODO: Maybe need more checks here after vector extension is supported.
11602 if (VT == MVT::f32 && !Subtarget.hasBasicF())
11604 if (VT == MVT::f64 && !Subtarget.hasBasicD())
11606 if (Imm.isZero() || isFPImmVLDILegal(Imm, VT))
11607 return FPImmAction::Legal;
11608
11609 // Immediates the size of a GPR are built from their bits. Others are built in
11610 // lowerConstantFP.
11611 if (VT.getSizeInBits() == Subtarget.getGRLen() && isFPImmCheapInGPR(Imm, VT))
11612 return FPImmAction::Bitcast;
11614}
11615
11617 EVT VT) const {
11618 // Count the instructions to generate the bits and move them to a float
11619 // register.
11620 auto Seq =
11621 LoongArchMatInt::generateInstSeq(Imm.bitcastToAPInt().getSExtValue());
11622 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
11623 return InsNum <= MaterializeFPImmInsNum || Imm.isOne();
11624}
11625
11627 return true;
11628}
11629
11631 return true;
11632}
11633
11634bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
11635 const Instruction *I) const {
11636 if (!Subtarget.is64Bit())
11637 return isa<LoadInst>(I) || isa<StoreInst>(I);
11638
11639 if (isa<LoadInst>(I))
11640 return true;
11641
11642 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
11643 // require fences beacuse we can use amswap_db.[w/d].
11644 Type *Ty = I->getOperand(0)->getType();
11645 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
11646 unsigned Size = Ty->getIntegerBitWidth();
11647 return (Size == 8 || Size == 16);
11648 }
11649
11650 return false;
11651}
11652
11654 LLVMContext &Context,
11655 EVT VT) const {
11656 if (!VT.isVector())
11657 return getPointerTy(DL);
11659}
11660
11662 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
11663 // Do not merge to float value size (128 or 256 bits) if no implicit
11664 // float attribute is set.
11665 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
11666 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
11667 if (NoFloat)
11668 return MemVT.getSizeInBits() <= MaxIntSize;
11669
11670 // Make sure we don't merge greater than our maximum supported vector width.
11671 if (Subtarget.hasExtLASX())
11672 MaxIntSize = 256;
11673 else if (Subtarget.hasExtLSX())
11674 MaxIntSize = 128;
11675
11676 return MemVT.getSizeInBits() <= MaxIntSize;
11677}
11678
11680 EVT VT = Y.getValueType();
11681
11682 if (VT.isVector())
11683 return Subtarget.hasExtLSX() && VT.isInteger();
11684
11685 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
11686}
11687
11690 MachineFunction &MF, unsigned Intrinsic) const {
11691 switch (Intrinsic) {
11692 default:
11693 return;
11694 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
11695 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
11696 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
11697 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
11698 IntrinsicInfo Info;
11700 Info.memVT = MVT::i32;
11701 Info.ptrVal = I.getArgOperand(0);
11702 Info.offset = 0;
11703 Info.align = Align(4);
11706 Infos.push_back(Info);
11707 return;
11708 // TODO: Add more Intrinsics later.
11709 }
11710 }
11711}
11712
11713// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
11714// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
11715// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
11716// regression, we need to implement it manually.
11719
11721 Op == AtomicRMWInst::And) &&
11722 "Unable to expand");
11723 unsigned MinWordSize = 4;
11724
11725 IRBuilder<> Builder(AI);
11726 LLVMContext &Ctx = Builder.getContext();
11727 const DataLayout &DL = AI->getDataLayout();
11728 Type *ValueType = AI->getType();
11729 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
11730
11731 Value *Addr = AI->getPointerOperand();
11732 PointerType *PtrTy = cast<PointerType>(Addr->getType());
11733 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
11734
11735 Value *AlignedAddr = Builder.CreateIntrinsic(
11736 Intrinsic::ptrmask, {PtrTy, IntTy},
11737 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
11738 "AlignedAddr");
11739
11740 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
11741 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
11742 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
11743 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
11744 Value *Mask = Builder.CreateShl(
11745 ConstantInt::get(WordType,
11746 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
11747 ShiftAmt, "Mask");
11748 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
11749 Value *ValOperand_Shifted =
11750 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
11751 ShiftAmt, "ValOperand_Shifted");
11752 Value *NewOperand;
11753 if (Op == AtomicRMWInst::And)
11754 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
11755 else
11756 NewOperand = ValOperand_Shifted;
11757
11758 AtomicRMWInst *NewAI =
11759 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
11760 AI->getOrdering(), AI->getSyncScopeID());
11761
11762 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
11763 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
11764 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
11765 AI->replaceAllUsesWith(FinalOldResult);
11766 AI->eraseFromParent();
11767}
11768
11771 const AtomicRMWInst *AI) const {
11772 // TODO: Add more AtomicRMWInst that needs to be extended.
11773
11774 // Since floating-point operation requires a non-trivial set of data
11775 // operations, use CmpXChg to expand.
11776 if (AI->isFloatingPointOperation() ||
11782
11783 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
11786 AI->getOperation() == AtomicRMWInst::Sub)) {
11788 }
11789
11790 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
11791 if (Subtarget.hasLAMCAS()) {
11792 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
11796 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
11798 }
11799
11800 if (Size == 8 || Size == 16)
11803}
11804
11805static Intrinsic::ID
11807 AtomicRMWInst::BinOp BinOp) {
11808 if (GRLen == 64) {
11809 switch (BinOp) {
11810 default:
11811 llvm_unreachable("Unexpected AtomicRMW BinOp");
11813 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
11814 case AtomicRMWInst::Add:
11815 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
11816 case AtomicRMWInst::Sub:
11817 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
11819 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
11821 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
11823 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
11824 case AtomicRMWInst::Max:
11825 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
11826 case AtomicRMWInst::Min:
11827 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11828 // TODO: support other AtomicRMWInst.
11829 }
11830 }
11831
11832 if (GRLen == 32) {
11833 switch (BinOp) {
11834 default:
11835 llvm_unreachable("Unexpected AtomicRMW BinOp");
11837 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11838 case AtomicRMWInst::Add:
11839 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11840 case AtomicRMWInst::Sub:
11841 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11843 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11845 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11847 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11848 case AtomicRMWInst::Max:
11849 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11850 case AtomicRMWInst::Min:
11851 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11852 // TODO: support other AtomicRMWInst.
11853 }
11854 }
11855
11856 llvm_unreachable("Unexpected GRLen\n");
11857}
11858
11861 const AtomicCmpXchgInst *CI) const {
11862
11863 if (Subtarget.hasLAMCAS())
11865
11867 if (Size == 8 || Size == 16)
11870}
11871
11873 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11874 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11875 unsigned GRLen = Subtarget.getGRLen();
11876 AtomicOrdering FailOrd = CI->getFailureOrdering();
11877 Value *FailureOrdering =
11878 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11879 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11880 if (GRLen == 64) {
11881 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11882 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11883 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11884 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11885 }
11886 Type *Tys[] = {AlignedAddr->getType()};
11887 Value *Result = Builder.CreateIntrinsic(
11888 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11889 if (GRLen == 64)
11890 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11891 return Result;
11892}
11893
11895 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11896 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11897 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11898 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11899 // mask, as this produces better code than the LL/SC loop emitted by
11900 // int_loongarch_masked_atomicrmw_xchg.
11901 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11904 if (CVal->isZero())
11905 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11906 Builder.CreateNot(Mask, "Inv_Mask"),
11907 AI->getAlign(), Ord);
11908 if (CVal->isMinusOne())
11909 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11910 AI->getAlign(), Ord);
11911 }
11912
11913 unsigned GRLen = Subtarget.getGRLen();
11914 Value *Ordering =
11915 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11916 Type *Tys[] = {AlignedAddr->getType()};
11918 AI->getModule(),
11920
11921 if (GRLen == 64) {
11922 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11923 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11924 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11925 }
11926
11927 Value *Result;
11928
11929 // Must pass the shift amount needed to sign extend the loaded value prior
11930 // to performing a signed comparison for min/max. ShiftAmt is the number of
11931 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11932 // is the number of bits to left+right shift the value in order to
11933 // sign-extend.
11934 if (AI->getOperation() == AtomicRMWInst::Min ||
11936 const DataLayout &DL = AI->getDataLayout();
11937 unsigned ValWidth =
11938 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11939 Value *SextShamt =
11940 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11941 Result = Builder.CreateCall(LlwOpScwLoop,
11942 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11943 } else {
11944 Result =
11945 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11946 }
11947
11948 if (GRLen == 64)
11949 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11950 return Result;
11951}
11952
11954 const MachineFunction &MF, EVT VT) const {
11955 VT = VT.getScalarType();
11956
11957 if (!VT.isSimple())
11958 return false;
11959
11960 switch (VT.getSimpleVT().SimpleTy) {
11961 case MVT::f32:
11962 case MVT::f64:
11963 return true;
11964 default:
11965 break;
11966 }
11967
11968 return false;
11969}
11970
11972 ExceptionHandling EH, const Constant *PersonalityFn) const {
11973 return LoongArch::R4;
11974}
11975
11977 ExceptionHandling EH, const Constant *PersonalityFn) const {
11978 return LoongArch::R5;
11979}
11980
11981//===----------------------------------------------------------------------===//
11982// Target Optimization Hooks
11983//===----------------------------------------------------------------------===//
11984
11987 // Feature FRECIPE instructions relative accuracy is 2^-14.
11988 // IEEE float has 23 digits and double has 52 digits.
11989 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11990 return RefinementSteps;
11991}
11992
11993static bool
11995 assert(Subtarget.hasFrecipe() &&
11996 "Reciprocal estimate queried on unsupported target");
11997
11998 if (!VT.isSimple())
11999 return false;
12000
12001 switch (VT.getSimpleVT().SimpleTy) {
12002 case MVT::f32:
12003 // f32 is the base type for reciprocal estimate instructions.
12004 return true;
12005
12006 case MVT::f64:
12007 return Subtarget.hasBasicD();
12008
12009 case MVT::v4f32:
12010 case MVT::v2f64:
12011 return Subtarget.hasExtLSX();
12012
12013 case MVT::v8f32:
12014 case MVT::v4f64:
12015 return Subtarget.hasExtLASX();
12016
12017 default:
12018 return false;
12019 }
12020}
12021
12023 SelectionDAG &DAG, int Enabled,
12024 int &RefinementSteps,
12025 bool &UseOneConstNR,
12026 bool Reciprocal) const {
12028 "Enabled should never be Disabled here");
12029
12030 if (!Subtarget.hasFrecipe())
12031 return SDValue();
12032
12033 SDLoc DL(Operand);
12034 EVT VT = Operand.getValueType();
12035
12036 // Check supported types.
12037 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
12038 return SDValue();
12039
12040 // Handle refinement steps.
12041 if (RefinementSteps == ReciprocalEstimate::Unspecified)
12042 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
12043
12044 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
12045 UseOneConstNR = false;
12046 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
12047
12048 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
12049 // are needed (which rely on the reciprocal form), return the raw reciprocal
12050 // estimate.
12051 if (Reciprocal || RefinementSteps > 0)
12052 return Rsqrt;
12053
12054 // Otherwise, return sqrt(x) by multiplying with the operand.
12055 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
12056}
12057
12059 SelectionDAG &DAG,
12060 int Enabled,
12061 int &RefinementSteps) const {
12063 "Enabled should never be Disabled here");
12064
12065 if (!Subtarget.hasFrecipe())
12066 return SDValue();
12067
12068 SDLoc DL(Operand);
12069 EVT VT = Operand.getValueType();
12070
12071 // Check supported types.
12072 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
12073 return SDValue();
12074
12075 if (RefinementSteps == ReciprocalEstimate::Unspecified)
12076 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
12077
12078 // FRECIPE computes 1.0 / x.
12079 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
12080}
12081
12082//===----------------------------------------------------------------------===//
12083// LoongArch Inline Assembly Support
12084//===----------------------------------------------------------------------===//
12085
12087LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
12088 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
12089 //
12090 // 'f': A floating-point register (if available).
12091 // 'k': A memory operand whose address is formed by a base register and
12092 // (optionally scaled) index register.
12093 // 'l': A signed 16-bit constant.
12094 // 'm': A memory operand whose address is formed by a base register and
12095 // offset that is suitable for use in instructions with the same
12096 // addressing mode as st.w and ld.w.
12097 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
12098 // instruction)
12099 // 'I': A signed 12-bit constant (for arithmetic instructions).
12100 // 'J': Integer zero.
12101 // 'K': An unsigned 12-bit constant (for logic instructions).
12102 // "ZB": An address that is held in a general-purpose register. The offset is
12103 // zero.
12104 // "ZC": A memory operand whose address is formed by a base register and
12105 // offset that is suitable for use in instructions with the same
12106 // addressing mode as ll.w and sc.w.
12107 if (Constraint.size() == 1) {
12108 switch (Constraint[0]) {
12109 default:
12110 break;
12111 case 'f':
12112 case 'q':
12113 return C_RegisterClass;
12114 case 'l':
12115 case 'I':
12116 case 'J':
12117 case 'K':
12118 return C_Immediate;
12119 case 'k':
12120 return C_Memory;
12121 }
12122 }
12123
12124 if (Constraint == "ZC" || Constraint == "ZB")
12125 return C_Memory;
12126
12127 // 'm' is handled here.
12128 return TargetLowering::getConstraintType(Constraint);
12129}
12130
12131InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
12132 StringRef ConstraintCode) const {
12133 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
12137 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
12138}
12139
12140std::pair<unsigned, const TargetRegisterClass *>
12141LoongArchTargetLowering::getRegForInlineAsmConstraint(
12142 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
12143 // First, see if this is a constraint that directly corresponds to a LoongArch
12144 // register class.
12145 if (Constraint.size() == 1) {
12146 switch (Constraint[0]) {
12147 case 'r':
12148 // TODO: Support fixed vectors up to GRLen?
12149 if (VT.isVector())
12150 break;
12151 return std::make_pair(0U, &LoongArch::GPRRegClass);
12152 case 'q':
12153 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
12154 case 'f':
12155 if (Subtarget.hasBasicF() && VT == MVT::f32)
12156 return std::make_pair(0U, &LoongArch::FPR32RegClass);
12157 if (Subtarget.hasBasicD() && VT == MVT::f64)
12158 return std::make_pair(0U, &LoongArch::FPR64RegClass);
12159 if (Subtarget.hasExtLSX() &&
12160 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
12161 return std::make_pair(0U, &LoongArch::LSX128RegClass);
12162 if (Subtarget.hasExtLSX() && VT == MVT::i128)
12163 return std::make_pair(0U, &LoongArch::LSX128RegClass);
12164 if (Subtarget.hasExtLASX() &&
12165 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
12166 return std::make_pair(0U, &LoongArch::LASX256RegClass);
12167 break;
12168 default:
12169 break;
12170 }
12171 }
12172
12173 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
12174 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
12175 // constraints while the official register name is prefixed with a '$'. So we
12176 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
12177 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
12178 // case insensitive, so no need to convert the constraint to upper case here.
12179 //
12180 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
12181 // decode the usage of register name aliases into their official names. And
12182 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
12183 // official register names.
12184 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
12185 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
12186 bool IsFP = Constraint[2] == 'f';
12187 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
12188 std::pair<unsigned, const TargetRegisterClass *> R;
12190 TRI, join_items("", Temp.first, Temp.second), VT);
12191 // Match those names to the widest floating point register type available.
12192 if (IsFP) {
12193 unsigned RegNo = R.first;
12194 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
12195 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
12196 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
12197 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
12198 }
12199 }
12200 }
12201 return R;
12202 }
12203
12204 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
12205}
12206
12207void LoongArchTargetLowering::LowerAsmOperandForConstraint(
12208 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
12209 SelectionDAG &DAG) const {
12210 // Currently only support length 1 constraints.
12211 if (Constraint.size() == 1) {
12212 switch (Constraint[0]) {
12213 case 'l':
12214 // Validate & create a 16-bit signed immediate operand.
12215 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
12216 uint64_t CVal = C->getSExtValue();
12217 if (isInt<16>(CVal))
12218 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
12219 Subtarget.getGRLenVT()));
12220 }
12221 return;
12222 case 'I':
12223 // Validate & create a 12-bit signed immediate operand.
12224 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
12225 uint64_t CVal = C->getSExtValue();
12226 if (isInt<12>(CVal))
12227 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
12228 Subtarget.getGRLenVT()));
12229 }
12230 return;
12231 case 'J':
12232 // Validate & create an integer zero operand.
12233 if (auto *C = dyn_cast<ConstantSDNode>(Op))
12234 if (C->getZExtValue() == 0)
12235 Ops.push_back(
12236 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
12237 return;
12238 case 'K':
12239 // Validate & create a 12-bit unsigned immediate operand.
12240 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
12241 uint64_t CVal = C->getZExtValue();
12242 if (isUInt<12>(CVal))
12243 Ops.push_back(
12244 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
12245 }
12246 return;
12247 default:
12248 break;
12249 }
12250 }
12252}
12253
12254#define GET_REGISTER_MATCHER
12255#include "LoongArchGenAsmMatcher.inc"
12256
12259 const MachineFunction &MF) const {
12260 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
12261 std::string NewRegName = Name.second.str();
12262 Register Reg = MatchRegisterAltName(NewRegName);
12263 if (!Reg)
12264 Reg = MatchRegisterName(NewRegName);
12265 if (!Reg)
12266 return Reg;
12267 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
12268 if (!ReservedRegs.test(Reg))
12269 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
12270 StringRef(RegName) + "\"."));
12271 return Reg;
12272}
12273
12275 EVT VT, SDValue C) const {
12276 // TODO: Support vectors.
12277 if (!VT.isScalarInteger())
12278 return false;
12279
12280 // Omit the optimization if the data size exceeds GRLen.
12281 if (VT.getSizeInBits() > Subtarget.getGRLen())
12282 return false;
12283
12284 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
12285 const APInt &Imm = ConstNode->getAPIntValue();
12286 // Break MUL into (SLLI + ADD/SUB) or ALSL.
12287 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
12288 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
12289 return true;
12290 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
12291 if (ConstNode->hasOneUse() &&
12292 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
12293 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
12294 return true;
12295 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
12296 // in which the immediate has two set bits. Or Break (MUL x, imm)
12297 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
12298 // equals to (1 << s0) - (1 << s1).
12299 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
12300 unsigned Shifts = Imm.countr_zero();
12301 // Reject immediates which can be composed via a single LUI.
12302 if (Shifts >= 12)
12303 return false;
12304 // Reject multiplications can be optimized to
12305 // (SLLI (ALSL x, x, 1/2/3/4), s).
12306 APInt ImmPop = Imm.ashr(Shifts);
12307 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
12308 return false;
12309 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
12310 // since it needs one more instruction than other 3 cases.
12311 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
12312 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
12313 (ImmSmall - Imm).isPowerOf2())
12314 return true;
12315 }
12316 }
12317
12318 return false;
12319}
12320
12322 const AddrMode &AM,
12323 Type *Ty, unsigned AS,
12324 Instruction *I) const {
12325 // LoongArch has four basic addressing modes:
12326 // 1. reg
12327 // 2. reg + 12-bit signed offset
12328 // 3. reg + 14-bit signed offset left-shifted by 2
12329 // 4. reg1 + reg2
12330 // TODO: Add more checks after support vector extension.
12331
12332 // No global is ever allowed as a base.
12333 if (AM.BaseGV)
12334 return false;
12335
12336 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
12337 // with `UAL` feature.
12338 if (!isInt<12>(AM.BaseOffs) &&
12339 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
12340 return false;
12341
12342 switch (AM.Scale) {
12343 case 0:
12344 // "r+i" or just "i", depending on HasBaseReg.
12345 break;
12346 case 1:
12347 // "r+r+i" is not allowed.
12348 if (AM.HasBaseReg && AM.BaseOffs)
12349 return false;
12350 // Otherwise we have "r+r" or "r+i".
12351 break;
12352 case 2:
12353 // "2*r+r" or "2*r+i" is not allowed.
12354 if (AM.HasBaseReg || AM.BaseOffs)
12355 return false;
12356 // Allow "2*r" as "r+r".
12357 break;
12358 default:
12359 return false;
12360 }
12361
12362 return true;
12363}
12364
12366 return isInt<12>(Imm);
12367}
12368
12370 return isInt<12>(Imm);
12371}
12372
12374 // Zexts are free if they can be combined with a load.
12375 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
12376 // poorly with type legalization of compares preferring sext.
12377 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
12378 EVT MemVT = LD->getMemoryVT();
12379 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
12380 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
12381 LD->getExtensionType() == ISD::ZEXTLOAD))
12382 return true;
12383 }
12384
12385 return TargetLowering::isZExtFree(Val, VT2);
12386}
12387
12389 EVT DstVT) const {
12390 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
12391}
12392
12394 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
12395}
12396
12398 // TODO: Support vectors.
12399 if (Y.getValueType().isVector())
12400 return false;
12401
12402 return true;
12403}
12404
12406 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
12407 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
12408}
12409
12411 Type *Ty, bool IsSigned) const {
12412 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
12413 return true;
12414
12415 return IsSigned;
12416}
12417
12419 // Return false to suppress the unnecessary extensions if the LibCall
12420 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
12421 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
12422 Type.getSizeInBits() < Subtarget.getGRLen()))
12423 return false;
12424 return true;
12425}
12426
12427// memcpy, and other memory intrinsics, typically tries to use wider load/store
12428// if the source/dest is aligned and the copy size is large enough. We therefore
12429// want to align such objects passed to memory intrinsics.
12431 unsigned &MinSize,
12432 Align &PrefAlign) const {
12433 if (!isa<MemIntrinsic>(CI))
12434 return false;
12435
12436 if (Subtarget.is64Bit()) {
12437 MinSize = 8;
12438 PrefAlign = Align(8);
12439 } else {
12440 MinSize = 4;
12441 PrefAlign = Align(4);
12442 }
12443
12444 return true;
12445}
12446
12449 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
12450 VT.getVectorElementType() != MVT::i1)
12451 return TypeWidenVector;
12452
12454}
12455
12456bool LoongArchTargetLowering::splitValueIntoRegisterParts(
12457 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
12458 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
12459 bool IsABIRegCopy = CC.has_value();
12460 EVT ValueVT = Val.getValueType();
12461
12462 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
12463 PartVT == MVT::f32) {
12464 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
12465 // nan, and cast to f32.
12466 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
12467 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
12468 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
12469 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
12470 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
12471 Parts[0] = Val;
12472 return true;
12473 }
12474
12475 return false;
12476}
12477
12478SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
12479 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
12480 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
12481 bool IsABIRegCopy = CC.has_value();
12482
12483 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
12484 PartVT == MVT::f32) {
12485 SDValue Val = Parts[0];
12486
12487 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
12488 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
12489 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
12490 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
12491 return Val;
12492 }
12493
12494 return SDValue();
12495}
12496
12497MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
12499 EVT VT) const {
12500 // Use f32 to pass f16.
12501 if (VT == MVT::f16 && Subtarget.hasBasicF())
12502 return MVT::f32;
12503
12505}
12506
12507unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
12509 // Use f32 to pass f16.
12510 if (VT == MVT::f16 && Subtarget.hasBasicF())
12511 return 1;
12512
12514}
12515
12517 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
12518 const SelectionDAG &DAG, unsigned Depth) const {
12519 unsigned Opc = Op.getOpcode();
12520 Known.resetAll();
12521 switch (Opc) {
12522 default:
12523 break;
12524 case LoongArchISD::VANYNONZERO:
12525 case LoongArchISD::VALLZERO:
12526 case LoongArchISD::VALL_ZERO:
12527 case LoongArchISD::VANY_ZERO:
12528 case LoongArchISD::VALL_NONZERO:
12529 case LoongArchISD::VANY_NONZERO: {
12530 // MOVCF2GR zero-extend the i1 cond to GPR.
12531 Known.Zero.setBitsFrom(1);
12532 break;
12533 }
12534 case LoongArchISD::VPICK_ZEXT_ELT: {
12535 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
12536 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
12537 unsigned VTBits = VT.getScalarSizeInBits();
12538 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
12539 Known.Zero.setBitsFrom(VTBits);
12540 break;
12541 }
12542 case LoongArchISD::BSTRINS: {
12543 // BSTRINS X, Y, msb, lsb: replace X[msb:lsb] with Y[msb-lsb:0].
12544 unsigned Msb = Op.getConstantOperandVal(2);
12545 unsigned Lsb = Op.getConstantOperandVal(3);
12546 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12547 KnownBits Known2 = DAG.computeKnownBits(Op.getOperand(1), Depth + 1);
12548 Known.insertBits(Known2.trunc(Msb - Lsb + 1), Lsb);
12549 break;
12550 }
12551 case LoongArchISD::BSTRPICK: {
12552 // BSTRPICK X, msb, lsb: zero-extend X[msb:lsb].
12553 unsigned BitWidth = Known.getBitWidth();
12554 unsigned Msb = Op.getConstantOperandVal(1);
12555 unsigned Lsb = Op.getConstantOperandVal(2);
12556 Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
12557 Known = Known.extractBits(Msb - Lsb + 1, Lsb).zext(BitWidth);
12558 break;
12559 }
12560 }
12561}
12562
12564 SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
12565 unsigned Depth) const {
12566 switch (Op.getOpcode()) {
12567 default:
12568 break;
12569 case LoongArchISD::BSTRINS: {
12570 unsigned BitWidth = Op.getScalarValueSizeInBits();
12571 unsigned Msb = Op.getConstantOperandVal(2);
12572 unsigned Lsb = Op.getConstantOperandVal(3);
12573 // The bits above msb come from X.
12574 if (Msb != BitWidth - 1) {
12575 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1);
12576 return std::min(Tmp, BitWidth - 1 - Msb);
12577 }
12578 // The high bits come from Y shifted left by lsb.
12579 unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(1), Depth + 1);
12580 return Tmp > Lsb ? Tmp - Lsb : 1;
12581 }
12582 }
12583 return 1;
12584}
12585
12587 SDValue Op, const APInt &OriginalDemandedBits,
12588 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
12589 unsigned Depth) const {
12590 EVT VT = Op.getValueType();
12591 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
12592 unsigned Opc = Op.getOpcode();
12593 switch (Opc) {
12594 default:
12595 break;
12596 case LoongArchISD::CRC_W_B_W:
12597 case LoongArchISD::CRC_W_H_W:
12598 case LoongArchISD::CRCC_W_B_W:
12599 case LoongArchISD::CRCC_W_H_W: {
12600 KnownBits KnownSrc;
12601 APInt DemandedSrcBits =
12602 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
12603 Opc == LoongArchISD::CRCC_W_B_W)
12604 ? 8
12605 : 16);
12606 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
12607 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
12608 }
12609 case LoongArchISD::VMSKLTZ:
12610 case LoongArchISD::XVMSKLTZ: {
12611 SDValue Src = Op.getOperand(0);
12612 MVT SrcVT = Src.getSimpleValueType();
12613 unsigned SrcBits = SrcVT.getScalarSizeInBits();
12614 unsigned NumElts = SrcVT.getVectorNumElements();
12615
12616 // If we don't need the sign bits at all just return zero.
12617 if (OriginalDemandedBits.countr_zero() >= NumElts)
12618 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
12619
12620 // Only demand the vector elements of the sign bits we need.
12621 APInt KnownUndef, KnownZero;
12622 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
12623 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
12624 TLO, Depth + 1))
12625 return true;
12626
12627 Known.Zero = KnownZero.zext(BitWidth);
12628 Known.Zero.setHighBits(BitWidth - NumElts);
12629
12630 // [X]VMSKLTZ only uses the MSB from each vector element.
12631 KnownBits KnownSrc;
12632 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
12633 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
12634 Depth + 1))
12635 return true;
12636
12637 if (KnownSrc.One[SrcBits - 1])
12638 Known.One.setLowBits(NumElts);
12639 else if (KnownSrc.Zero[SrcBits - 1])
12640 Known.Zero.setLowBits(NumElts);
12641
12642 // Attempt to avoid multi-use ops if we don't need anything from it.
12644 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
12645 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
12646 return false;
12647 }
12648 }
12649
12651 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
12652}
12653
12655 unsigned Opc = VecOp.getOpcode();
12656
12657 // Assume target opcodes can't be scalarized.
12658 // TODO - do we have any exceptions?
12659 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
12660 return false;
12661
12662 // If the vector op is not supported, try to convert to scalar.
12663 EVT VecVT = VecOp.getValueType();
12665 return true;
12666
12667 // If the vector op is supported, but the scalar op is not, the transform may
12668 // not be worthwhile.
12669 EVT ScalarVT = VecVT.getScalarType();
12670 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
12671}
12672
12675 unsigned Index) const {
12678
12679 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
12680 if (Index == 0)
12683}
12684
12686 unsigned Index) const {
12687 EVT EltVT = VT.getScalarType();
12688
12689 // Extract a scalar FP value from index 0 of a vector is free.
12690 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
12691}
12692
12694 const MachineFunction &MF) const {
12695
12696 // If the function specifically requests inline stack probes, emit them.
12697 if (MF.getFunction().hasFnAttribute("probe-stack"))
12698 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
12699 "inline-asm";
12700
12701 return false;
12702}
12703
12705 Align StackAlign) const {
12706 // The default stack probe size is 4096 if the function has no
12707 // stack-probe-size attribute.
12708 const Function &Fn = MF.getFunction();
12709 unsigned StackProbeSize =
12710 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
12711 // Round down to the stack alignment.
12712 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
12713 return StackProbeSize ? StackProbeSize : StackAlign.value();
12714}
12715
12716SDValue
12717LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
12718 SelectionDAG &DAG) const {
12720 if (!hasInlineStackProbe(MF))
12721 return SDValue();
12722
12723 const MVT GRLenVT = Subtarget.getGRLenVT();
12724 // Get the inputs.
12725 SDValue Chain = Op.getOperand(0);
12726 SDValue Size = Op.getOperand(1);
12727
12728 const MaybeAlign Align =
12729 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
12730 const SDLoc dl(Op);
12731 const EVT VT = Op.getValueType();
12732
12733 // Construct the new SP value in a GPR.
12734 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
12735 Chain = SP.getValue(1);
12736 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
12737 if (Align)
12738 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
12739 DAG.getSignedConstant(-Align->value(), dl, VT));
12740
12741 // Set the real SP to the new value with a probing loop.
12742 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
12743 return DAG.getMergeValues({SP, Chain}, dl);
12744}
12745
12748 MachineBasicBlock *MBB) const {
12749 MachineFunction &MF = *MBB->getParent();
12750 MachineBasicBlock::iterator MBBI = MI.getIterator();
12751 DebugLoc DL = MBB->findDebugLoc(MBBI);
12752 const Register TargetReg = MI.getOperand(0).getReg();
12753
12754 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
12755 const bool IsLA64 = Subtarget.is64Bit();
12756 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
12757 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
12758 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
12759
12760 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
12761 MachineBasicBlock *const LoopTestMBB =
12762 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12763 MF.insert(MBBInsertPoint, LoopTestMBB);
12764 MachineBasicBlock *const ExitMBB =
12765 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12766 MF.insert(MBBInsertPoint, ExitMBB);
12767 const Register SPReg = LoongArch::R3;
12768 const Register ScratchReg =
12769 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
12770
12771 // ScratchReg = ProbeSize
12772 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
12773
12774 // LoopTest:
12775 // sub.{w/d} $sp, $sp, ScratchReg
12776 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12777 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
12778 .addReg(SPReg)
12779 .addReg(ScratchReg);
12780
12781 // st.{w/d} $zero, $sp, 0
12782 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12783 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
12784 .addReg(LoongArch::R0)
12785 .addReg(SPReg)
12786 .addImm(0);
12787
12788 // bltu TargetReg, $sp, LoopTest
12789 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
12790 .addReg(TargetReg)
12791 .addReg(SPReg)
12792 .addMBB(LoopTestMBB);
12793
12794 // move $sp, TargetReg
12795 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
12796 .addReg(TargetReg)
12797 .addReg(LoongArch::R0);
12798
12799 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
12801
12802 LoopTestMBB->addSuccessor(ExitMBB);
12803 LoopTestMBB->addSuccessor(LoopTestMBB);
12804 MBB->addSuccessor(LoopTestMBB);
12805
12806 MI.eraseFromParent();
12807 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
12808 return ExitMBB->begin()->getParent();
12809}
static MCRegister MatchRegisterName(StringRef Name)
static SDValue performSHLCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
If the operand is a bitwise AND with a constant RHS, and the shift has a constant RHS and is the only...
static bool checkValueWidth(SDValue V, unsigned width, ISD::LoadExtType &ExtType)
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
unsigned NumParts
return SDValue()
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSELECT_CCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
const AArch64Subtarget & Subtarget
const TargetLowering & TLI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
uint64_t uint64_t
uint64_t Imm
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static MCRegister MatchRegisterAltName(StringRef Name)
Maps from the set of all alternative registernames to a register number.
Function Alias Analysis Results
static uint64_t getConstant(const Value *IndexValue)
static SDValue getTargetNode(ConstantPoolSDNode *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG, unsigned Flags)
bpf unwind BPF Unwind Lower
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static MachineBasicBlock * emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode)
static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static bool isSigned(unsigned Opcode)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RegName(no)
static SDValue performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
const MCPhysReg ArgFPR32s[]
static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 128-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
const MCPhysReg ArgVRs[]
static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKEV (if possible).
static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
static SDValue unpackF64OnLA32DSoftABI(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const CCValAssign &HiVA, const SDLoc &DL)
static bool fitsRegularPattern(typename SmallVectorImpl< ValType >::const_iterator Begin, unsigned CheckStride, typename SmallVectorImpl< ValType >::const_iterator End, ValType ExpectedIndex, unsigned ExpectedIndexStride)
Determine whether a range fits a regular pattern of values.
static SDValue lowerVECTOR_SHUFFLE_IsReverse(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE whose result is the reversed source vector.
static SDValue PromoteMaskArithmetic(SDValue N, const SDLoc &DL, EVT VT, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned Depth)
static SDValue performUINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performHorizWideningCombine(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static std::pair< SDValue, EVT > stripSignExtendInReg(SDValue V)
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static SDValue lowerVECTOR_SHUFFLE_XVPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI (if possible).
static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
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 performSIGN_EXTEND_INREGCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performDemandedBitsCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
static std::tuple< unsigned, SDValue, EVT > matchBinOpWithSharedOperand(SDValue BinV, SDValue X)
static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static SDValue performSPLIT_PAIR_F64Combine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performBITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static MachineBasicBlock * emitSplitPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG)
static SDValue performSETCC_BITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
@ NoMaterializeFPImm
@ MaterializeFPImm2Ins
@ MaterializeFPImm5Ins
@ MaterializeFPImm6Ins
@ MaterializeFPImm3Ins
@ MaterializeFPImm4Ins
static SDValue performEXTENDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
static bool buildVPERMIInfo(ArrayRef< int > Mask, SDValue V1, SDValue V2, SmallVectorImpl< SDValue > &SrcVec, unsigned &MaskImm)
static std::optional< bool > matchSetCC(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue Val)
static SDValue combineAndNotIntoVANDN(SDNode *N, const SDLoc &DL, SelectionDAG &DAG)
Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
static SDValue lowerBUILD_VECTORAsBroadCastLoad(BuildVectorSDNode *BVOp, const SDLoc &DL, SelectionDAG &DAG)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG)
static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size, unsigned Depth)
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
static SDValue lowerVECTOR_SHUFFLEAsShift(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as shift (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, Type *OrigTy, CCState &State)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVECTOR_SHUFFLE_VEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG)
static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKEV (if possible).
static MachineBasicBlock * emitPseudoVMSKCOND(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performVANDNCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
Do target-specific dag combines on LoongArchISD::VANDN nodes.
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVPERMIQ(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI_Q (if possible).
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
static cl::opt< MaterializeFPImm > MaterializeFPImmInsNum("loongarch-materialize-float-imm", cl::Hidden, cl::desc("Maximum number of instructions used (including code sequence " "to generate the value and moving the value to FPR) when " "materializing floating-point immediates (default = 3)"), cl::init(MaterializeFPImm3Ins), cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"), clEnumValN(MaterializeFPImm2Ins, "2", "Materialize FP immediate within 2 instructions"), clEnumValN(MaterializeFPImm3Ins, "3", "Materialize FP immediate within 3 instructions"), clEnumValN(MaterializeFPImm4Ins, "4", "Materialize FP immediate within 4 instructions"), clEnumValN(MaterializeFPImm5Ins, "5", "Materialize FP immediate within 5 instructions"), clEnumValN(MaterializeFPImm6Ins, "6", "Materialize FP immediate within 6 instructions " "(behaves same as 5 on loongarch64)")))
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
const MCPhysReg ArgXRs[]
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
static unsigned getLoongArchWOpcode(unsigned Opcode)
const MCPhysReg ArgFPR64s[]
static MachineBasicBlock * emitPseudoCTPOP(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performMOVGR2FR_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKOD (if possible).
static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL)
static SDValue isNOT(SDValue V, SelectionDAG &DAG)
static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 256-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
const MCPhysReg PreserveNoneArgGPRs[]
static void fillVector(ArrayRef< SDValue > Ops, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, SDValue &Vector, EVT ResTy)
static SDValue fillSubVectorFromBuildVector(BuildVectorSDNode *Node, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, EVT ResTy, unsigned first)
static bool isSelectPseudo(MachineInstr &MI)
static SDValue foldVMskZeroTest(SDValue LHS, SDValue RHS, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue foldBinOpIntoSelectIfProfitable(SDNode *BO, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
const MCPhysReg ArgGPRs[]
static SDValue lowerVECTOR_SHUFFLE_XVPERM(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERM (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVL (if possible).
static SDValue performFP_TO_INTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, unsigned ExtOpc=ISD::ANY_EXTEND)
static void replaceVecCondBranchResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
#define ASRT_LE_GT_CASE(NAME)
static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex)
static SDValue performBR_CCCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static void computeZeroableShuffleElements(ArrayRef< int > Mask, SDValue V1, SDValue V2, APInt &KnownUndef, APInt &KnownZero)
Compute whether each element of a shuffle is zeroable.
static SDValue combineFP_ROUND(SDValue N, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue performCONCAT_VECTORSCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue widenShuffleMask(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
static bool canonicalizeShuffleVectorByLane(const SDLoc &DL, MutableArrayRef< int > Mask, MVT VT, SDValue &V1, SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Shuffle vectors by lane to generate more optimized instructions.
static SDValue combineSubOfBoolean(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVECTOR_SHUFFLE_XVILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVH (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVSHUF (if possible).
static void replaceCMP_XCHG_128Results(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG)
static SDValue lowerVectorPickVE2GR(SDNode *N, SelectionDAG &DAG, unsigned ResOp)
static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue matchHalfOf128BitLanes(SDValue N, bool isLow)
#define IOCSRRD_CASE(NAME, NODE)
static int matchShuffleAsByteRotate(MVT VT, SDValue &V1, SDValue &V2, ArrayRef< int > Mask)
Attempts to match vector shuffle as byte rotation.
static SDValue lowerVECTOR_SHUFFLE_XVREPLVE0(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVREPLVE0 (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode, unsigned ScalarSizeInBits, ArrayRef< int > Mask, int MaskOffset, const APInt &Zeroable)
Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI instruction.
static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVL (if possible).
static SDValue performMULCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG)
static MachineBasicBlock * emitBuildPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
static void replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
#define CSR_CASE(ID)
static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode, unsigned BlockBits)
static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKOD (if possible).
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS, ISD::CondCode &CC, SelectionDAG &DAG)
static Register allocateArgGPR(CCState &State)
static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT, ArrayRef< int > Mask, SmallVectorImpl< int > &RepeatedMask)
Test whether a shuffle mask is equivalent within each sub-lane.
static SDValue convertRMEncoding(SelectionDAG &DAG, const SDLoc &DL, MVT GRLenVT, SDValue RMValue)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO)
static constexpr MCPhysReg SPReg
MachineBasicBlock * Folded
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
MachineInstr *& Lo
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue, bool AllowSymbol=false)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool isSequentialOrUndefInRange(ArrayRef< int > Mask, unsigned Pos, unsigned Size, int Low, int Step=1)
Return true if every element in Mask, beginning from position Pos and ending in Pos + Size,...
Value * RHS
Value * LHS
bool isZero() const
Definition APFloat.h:1579
APInt bitcastToAPInt() const
Definition APFloat.h:1475
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1350
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:367
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1659
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:431
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1261
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
bool isOne() const
Determine if this is a value of 1.
Definition APInt.h:385
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
Definition APInt.h:282
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition Argument.h:50
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
An instruction that atomically checks whether a specified value is in a memory location,...
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ UDecWrap
Decrement one until a minimum value or zero.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
bool isFloatingPointOperation() const
BinOp getOperation() const
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool test(unsigned Idx) const
Returns true if bit Idx is set.
Definition BitVector.h:483
size_type count() const
Returns the number of bits which are set.
Definition BitVector.h:182
A "pseudo-class" with methods for operating on BUILD_VECTORs.
LLVM_ABI bool isConstantSplat(APInt &SplatValue, APInt &SplatUndef, unsigned &SplatBitSize, bool &HasAnyUndefs, unsigned MinSplatBits=0, bool isBigEndian=false) const
Check if this is a constant splat, and if so, find the smallest element size that splats the vector.
CCState - This class holds information needed while lowering arguments and return values.
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
LLVM_ABI void AnalyzeCallOperands(const SmallVectorImpl< ISD::OutputArg > &Outs, CCAssignFn Fn)
AnalyzeCallOperands - Analyze the outgoing arguments to a call, incorporating info about the passed v...
uint64_t getStackSize() const
Returns the size of the currently allocated portion of the stack.
LLVM_ABI void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
CCValAssign - Represent assignment of one arg/retval to a location.
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP, bool IsCustom=false)
static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP)
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool needsCustom() const
int64_t getLocMemOffset() const
unsigned getValNo() const
static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
const APFloat & getValueAPF() const
This is the shared class of boolean and integer constants.
Definition Constants.h:87
bool isMinusOne() const
This function will return true iff every bit in this constant is set to true.
Definition Constants.h:231
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition Constants.h:219
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
Definition DataLayout.h:501
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
A debug info location.
Definition DebugLoc.h:126
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
iterator_range< arg_iterator > args()
Definition Function.h:886
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:766
uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const
For a string attribute Kind, parse attribute as an integer.
Definition Function.cpp:778
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:273
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Argument * getArg(unsigned i) const
Definition Function.h:880
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
bool isDSOLocal() const
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2987
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This class is used to represent ISD::LOAD nodes.
const SDValue & getBasePtr() const
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
void setIncomingIndirectArg(unsigned ArgIndex, Register Reg)
Register getIncomingIndirectArg(unsigned ArgIndex) const
bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override
Return true if result of the specified node is used by a return node only.
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override
This method will be invoked for all target nodes and for any target-independent nodes that the target...
Register getExceptionPointerRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps, bool &UseOneConstNR, bool Reciprocal) const override
Hooks for building estimates in place of slower divisions and square roots.
unsigned ComputeNumSignBitsForTargetNode(SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
This method can be implemented by targets that want to expose additional information about sign bits ...
bool isLegalICmpImmediate(int64_t Imm) const override
Return true if the specified immediate is legal icmp immediate, that is the target has icmp instructi...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
bool isFPImmCheapInGPR(const APFloat &Imm, EVT VT) const
Returns true if building Imm in a GPR and moving it to a float register is cheaper than loading it fr...
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< bool, uint64_t > isImmVLDILegalForMode1(const APInt &SplatValue, const unsigned SplatBitSize) const
Check if a constant splat can be generated using [x]vldi, where imm[12] is 1.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this function.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
Register getExceptionSelectorRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
bool isExtractVecEltCheap(EVT VT, unsigned Index) const override
Return true if extraction of a scalar element from the given vector type at the given index is cheap.
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override
Return true if sign-extension from FromTy to ToTy is cheaper than zero-extension.
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const override
Determine if the target supports unaligned memory accesses.
bool isCheapToSpeculateCtlz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic ctlz.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
bool shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, Align &PrefAlign) const override
Return true if the pointer arguments to CI should be aligned by aligning the object whose address is ...
Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override
Perform a masked atomicrmw using a target-specific intrinsic.
bool isZExtFree(SDValue Val, EVT VT2) const override
Return true if zero-extending the specific node Val to type VT2 is free (either because it's implicit...
void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
Determine which of the bits specified in Mask are known to be either zero or one and return them in t...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, unsigned Index) const override
Return the cost of extracting a subvector of type ResVT from a vector of type SrcVT,...
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
bool isLegalAddImmediate(int64_t Imm) const override
Return true if the specified immediate is legal add immediate, that is the target has add instruction...
bool isCheapToSpeculateCttz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic cttz.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
MachineBasicBlock * emitDynamicProbedAlloc(MachineInstr &MI, MachineBasicBlock *MBB) const
bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override
Returns true if arguments should be sign-extended in lib calls.
bool shouldScalarizeBinop(SDValue VecOp) const override
Try to convert an extract element of a vector binary operation into an extract element followed by a ...
bool isFPImmVLDILegal(const APFloat &Imm, EVT VT) const
bool shouldExtendTypeInLibCall(EVT Type) const override
Returns true if arguments should be extended in lib calls.
Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override
Return the register ID of the name passed in.
bool hasAndNot(SDValue Y) const override
Return true if the target has a bitwise and-not operation: X = ~A & B This can be used to simplify se...
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override
Return true if folding a constant offset with the given GlobalAddress is legal.
unsigned getStackProbeSize(const MachineFunction &MF, Align StackAlign) const
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const override
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
void emitExpandAtomicRMW(AtomicRMWInst *AI) const override
Perform a atomicrmw expansion using a target-specific way.
ISD::NodeType getExtendForAtomicCmpSwapArg() const override
Returns how the platform's atomic compare and swap expects its comparison value to be extended (ZERO_...
LoongArchTargetLowering(const TargetMachine &TM, const LoongArchSubtarget &STI)
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
bool hasAndNotCompare(SDValue Y) const override
Return true if the target should transform: (X & Y) == Y ---> (~X & Y) == 0 (X & Y) !...
SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps) const override
Return a reciprocal estimate value for the input operand.
bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const override
Returns if it's reasonable to merge stores to MemVT size.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context, const Type *RetTy) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
bool mayBeEmittedAsTailCall(const CallInst *CI) const override
Return true if the target may be able emit the call instruction as a tail call.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
bool hasFeature(unsigned Feature) const
Machine Value Type.
static MVT getFloatingPointVT(unsigned BitWidth)
bool is128BitVector() const
Return true if this is a 128-bit vector type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool is256BitVector() const
Return true if this is a 256-bit vector type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
MVT getDoubleNumVectorElementsVT() const
MVT getHalfNumVectorElementsVT() const
Return a VT for a vector type with the same element type but half the number of elements.
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
MVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
void push_back(MachineInstr *MI)
void setCallFrameSize(unsigned N)
Set the call frame size on entry to this basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
LLVM_ABI void collectDebugValues(SmallVectorImpl< MachineInstr * > &DbgValues)
Scan instructions immediately following MI and collect any matching DBG_VALUEs.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Align getAlign() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const MachinePointerInfo & getPointerInfo() const
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
Class to represent pointers.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
LLVM_ABI bool isOnlyUserOf(const SDNode *N) const
Return true if this node is the only use of N.
size_t use_size() const
Return the number of uses of this node.
MVT getSimpleValueType(unsigned ResNo) const
Return the type of a specified result as a simple type.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
ISD::CondCode getOperandCondCode(unsigned i) const
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
MVT getSimpleValueType() const
Return the simple ValueType of the referenced return value.
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue FoldSetCC(EVT VT, SDValue N1, SDValue N2, ISD::CondCode Cond, const SDLoc &dl, SDNodeFlags Flags={})
Constant fold a setcc to true or false.
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget=false, bool IsOpaque=false)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getFreeze(SDValue V)
Return a freeze using the SDLoc of the value operand.
bool isSafeToSpeculativelyExecute(unsigned Opcode) const
Some opcodes may create immediate undefined behavior when used with some values (integer division-by-...
SDValue getExtractSubvector(const SDLoc &DL, EVT VT, SDValue Vec, unsigned Idx)
Return the VT typed sub-vector of Vec at Idx.
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
LLVM_ABI SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
SDValue getInsertSubvector(const SDLoc &DL, SDValue Vec, SDValue SubVec, unsigned Idx)
Insert SubVec at the Idx element of Vec.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
LLVM_ABI SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align DstAlign, Align SrcAlign, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
const TargetLowering & getTargetLoweringInfo() const
static constexpr unsigned MaxRecursionDepth
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI bool isSplatValue(SDValue V, const APInt &DemandedElts, APInt &UndefElts, unsigned Depth=0) const
Test whether V has a splatted value for all the demanded elements.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
LLVM_ABI SDValue getNegative(SDValue Val, const SDLoc &DL, EVT VT)
Create negative operation as (SUB 0, Val).
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
LLVM_ABI SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT VT)
Return the expression required to zero extend the Op value assuming it was the smaller SrcTy value.
const DataLayout & getDataLayout() const
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
SDValue getSignedTargetConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI void ReplaceAllUsesWith(SDValue From, SDValue To)
Modify anything using 'From' to use 'To' instead.
LLVM_ABI SDValue getCommutedVectorShuffle(const ShuffleVectorSDNode &SV)
Returns an ISD::VECTOR_SHUFFLE node semantically equivalent to the shuffle node in input but with swa...
LLVM_ABI SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
LLVM_ABI std::pair< SDValue, SDValue > SplitVector(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the vector with EXTRACT_SUBVECTOR using the provided VTs and return the low/high part.
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
SDValue getCALLSEQ_START(SDValue Chain, uint64_t InSize, uint64_t OutSize, const SDLoc &DL)
Return a new CALLSEQ_START node, that starts new call frame, in which InSize bytes are set up inside ...
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Loads are not normal binary operators: their result type is not determined by their operands,...
LLVM_ABI SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDValue > Ops, SDNodeFlags Flags=SDNodeFlags())
LLVM_ABI SDValue getExternalSymbol(const char *Sym, EVT VT)
const TargetMachine & getTarget() const
LLVM_ABI SDValue WidenVector(const SDValue &N, const SDLoc &DL)
Widen the vector up to the next power of two using INSERT_SUBVECTOR.
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI unsigned ComputeNumSignBits(SDValue Op, unsigned Depth=0) const
Return the number of times the sign bit of the register is replicated into the other bits.
SDValue getTargetBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue getVectorIdxConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI void ReplaceAllUsesOfValueWith(SDValue From, SDValue To)
Replace any uses of From with To, leaving uses of other values produced by From.getNode() alone.
MachineFunction & getMachineFunction() const
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
LLVM_ABI SDValue getRegisterMask(const uint32_t *RegMask)
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVM_ABI SDValue getCondCode(ISD::CondCode Cond)
LLVM_ABI bool MaskedValueIsZero(SDValue Op, const APInt &Mask, unsigned Depth=0) const
Return true if 'Op & Mask' is known to be zero.
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
LLVM_ABI SDValue CreateStackTemporary(TypeSize Bytes, Align Alignment)
Create a stack temporary based on the size in bytes and the alignment.
SDValue getTargetConstantPool(const Constant *C, EVT VT, MaybeAlign Align=std::nullopt, int Offset=0, unsigned TargetFlags=0)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
SDValue getSplat(EVT VT, const SDLoc &DL, SDValue Op)
Returns a node representing a splat of one value into all lanes of the provided vector type.
LLVM_ABI std::pair< SDValue, SDValue > SplitScalar(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the scalar node with EXTRACT_ELEMENT using the provided VTs and return the low/high part.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
static LLVM_ABI bool isZeroEltSplatMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask chooses all elements with the same value as the first element of exa...
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
ArrayRef< int > getMask() const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:176
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
typename SuperClass::const_iterator const_iterator
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:31
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
TargetInstrInfo - Interface to description of machine instruction set.
void setBooleanVectorContents(BooleanContent Ty)
Specify how the target extends the result of a vector boolean value from a vector of i1 to a wider ty...
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
MachineBasicBlock * emitPatchPoint(MachineInstr &MI, MachineBasicBlock *MBB) const
Replace/modify any TargetFrameIndex operands with a targte-dependent sequence of memory operands that...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
const TargetMachine & getTargetMachine() const
virtual unsigned getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain targets require unusual breakdowns of certain types.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain combinations of ABIs, Targets and features require that types are legal for some operations a...
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
void setMaxBytesForAlignment(unsigned MaxBytes)
void setPrefLoopAlignment(Align Alignment)
Set the target's preferred loop alignment.
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
virtual TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const
Return the preferred vector type legalization action.
void setMinFunctionAlignment(Align Alignment)
Set the target's minimum function alignment.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
virtual EVT getTypeToTransformTo(LLVMContext &Context, EVT VT) const
For types supported by the target, this is an identity function.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
ExtractSubvectorCost
Enum that specifies how expensive lowering an EXTRACT_SUBVECTOR is.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setPrefFunctionAlignment(Align Alignment)
Set the target's preferred function alignment.
bool isOperationLegal(unsigned Op, EVT VT) const
Return true if the specified operation is legal on this target.
FPImmAction
How the legalizer should materialize a floating-point immediate.
@ ConstantPool
Load the immediate from the constant pool.
@ Legal
The target can instruction select the immediate natively.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
bool isOperationLegalOrCustom(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
LegalizeTypeAction getTypeAction(LLVMContext &Context, EVT VT) const
Return how we should legalize values of this type, either it is already legal (return 'Legal') or we ...
std::vector< ArgListEntry > ArgListTy
bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
bool SimplifyDemandedVectorElts(SDValue Op, const APInt &DemandedEltMask, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Vector Op.
virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const
SDValue SimplifyMultipleUseDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth=0) const
More limited version of SimplifyDemandedBits that can be used to "lookthrough" ops that don't contrib...
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
std::pair< SDValue, SDValue > LowerCallTo(CallLoweringInfo &CLI) const
This function lowers an abstract call to a function into an actual call.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Op.
virtual bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0) const
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
TargetLowering(const TargetLowering &)=delete
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::LibcallImpl LibcallImpl, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
Primary interface to the complete machine description for the target machine.
bool useTLSDESC() const
Returns true if this target uses TLS Descriptors.
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
bool shouldAssumeDSOLocal(const GlobalValue *GV) const
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
Value * getOperand(unsigned i) const
Definition User.h:207
This class is used to represent EVT's, which are used to parameterize some operations.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:548
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
Definition CallingConv.h:50
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ PreserveNone
Used for runtime calls that preserves none general registers.
Definition CallingConv.h:90
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI bool isConstantSplatVectorAllOnes(const SDNode *N, bool BuildVectorOnly=false)
Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where all of the elements are ~0 ...
bool isNON_EXTLoad(const SDNode *N)
Returns true if the specified node is a non-extending load.
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition ISDOpcodes.h:43
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:851
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
@ STRICT_FSETCC
STRICT_FSETCC/STRICT_FSETCCS - Constrained versions of SETCC, used for floating-point operands only.
Definition ISDOpcodes.h:516
@ DELETED_NODE
DELETED_NODE - This is an illegal value that is used to catch errors.
Definition ISDOpcodes.h:47
@ POISON
POISON - A poison node.
Definition ISDOpcodes.h:238
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:277
@ INSERT_SUBVECTOR
INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector with VECTOR2 inserted into VECTOR1.
Definition ISDOpcodes.h:605
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:811
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:885
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:523
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ GlobalAddress
Definition ISDOpcodes.h:90
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:912
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:589
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:420
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:771
@ 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:942
@ FP16_TO_FP
FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions and truncation for half-preci...
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:256
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ GlobalTLSAddress
Definition ISDOpcodes.h:91
@ SET_ROUNDING
Set rounding mode.
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:876
@ AVGCEILS
AVGCEILS/AVGCEILU - Rounding averaging add - Add two integers using an integer of type i[N+2],...
Definition ISDOpcodes.h:731
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:681
@ PREFETCH
PREFETCH - This corresponds to a prefetch intrinsic.
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ BR_CC
BR_CC - Conditional branch.
@ BR_JT
BR_JT - Jumptable branch.
@ FCANONICALIZE
Returns platform specific canonical encoding of a floating point number.
Definition ISDOpcodes.h:546
@ IS_FPCLASS
Performs a check of floating point class property, defined by IEEE-754.
Definition ISDOpcodes.h:553
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:377
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:828
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:235
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
@ VECREDUCE_ADD
Integer reductions may have a result type larger than the vector element type.
@ GET_ROUNDING
Returns current rounding mode: -1 Undefined 0 Round to 0 1 Round to nearest, ties to even 2 Round to ...
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:720
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:793
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:659
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:619
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Same as FMINNUM/FMAXNUM, except that a signaling NaN operand deterministi...
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition ISDOpcodes.h:141
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:581
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:226
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:882
@ 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:843
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ FMINNUM
FMINNUM/FMAXNUM - Same semantics as the llvm.minnum/maxnum intrinsics.
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:920
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:751
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:837
@ EH_DWARF_CFA
EH_DWARF_CFA - This node represents the pointer to the DWARF Canonical Frame Address (CFA),...
Definition ISDOpcodes.h:152
@ BF16_TO_FP
BF16_TO_FP, FP_TO_BF16 - These operators are used to perform promotions and truncation for bfloat16.
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:112
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:958
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:763
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ AVGFLOORS
AVGFLOORS/AVGFLOORU - Averaging add - Add two integers using an integer of type i[N+1],...
Definition ISDOpcodes.h:726
@ FREEZE
FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or is evaluated to UNDEF),...
Definition ISDOpcodes.h:243
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:570
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:55
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:991
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:953
@ FP_TO_SINT_SAT
FP_TO_[US]INT_SAT - Convert floating point value in operand 0 to a signed or unsigned scalar integer ...
Definition ISDOpcodes.h:977
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:888
@ 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:865
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition ISDOpcodes.h:64
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:368
@ ABDS
ABDS/ABDU - Absolute difference - Return the absolute difference between two numbers interpreted as s...
Definition ISDOpcodes.h:746
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
bool isExtVecInRegOpcode(unsigned Opcode)
LLVM_ABI bool isBuildVectorOfConstantSDNodes(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR node of all ConstantSDNode or undef.
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.
LLVM_ABI bool isConstantSplatVector(const SDNode *N, APInt &SplatValue)
Node predicates.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
LLVM_ABI bool isBuildVectorAllOnes(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are ~0 or undef.
LLVM_ABI NodeType getVecReduceBaseOpcode(unsigned VecReduceOpcode)
Get underlying scalar opcode for VECREDUCE opcode.
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
bool isNormalLoad(const SDNode *N)
Returns true if the specified node is a non-extending and unindexed load.
bool isIntEqualitySetCC(CondCode Code)
Return true if this is a setcc instruction that performs an equality comparison when used with intege...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
ABI getTargetABI(StringRef ABIName)
InstSeq generateInstSeq(int64_t Val)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:63
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
Definition PtrState.h:41
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
Definition Threading.h:280
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isIntOrFPConstant(SDValue V)
Return true if V is either a integer or FP constant.
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition bit.h:325
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
Definition MathExtras.h:546
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
LLVM_ABI bool widenShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Try to transform a shuffle mask by replacing elements with the scaled index for an equivalent mask of...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:183
constexpr unsigned BitWidth
std::string join_items(Sep Separator, Args &&... Items)
Joins the strings in the parameter pack Items, adding Separator between the elements....
ExceptionHandling
Definition CodeGen.h:54
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isOneConstant(SDValue V)
Returns true if V is a constant integer one.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
LLVM_ABI bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:881
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Extended Value Type.
Definition ValueTypes.h:35
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition ValueTypes.h:90
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition ValueTypes.h:433
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:160
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:322
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:338
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:170
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:411
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:423
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:354
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:245
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:419
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition ValueTypes.h:55
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:191
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:361
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:250
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:366
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:180
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:374
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:499
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:175
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
KnownBits trunc(unsigned BitWidth) const
Return known bits for a truncation of the value we're tracking.
Definition KnownBits.h:165
unsigned countMaxActiveBits() const
Returns the maximum number of bits needed to represent all possible unsigned values with these known ...
Definition KnownBits.h:310
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
This structure contains all information that is necessary for lowering calls.
SmallVector< ISD::InputArg, 32 > Ins
SmallVector< ISD::OutputArg, 32 > Outs
LLVM_ABI SDValue CombineTo(SDNode *N, ArrayRef< SDValue > To, bool AddTo=true)
This structure is used to pass arguments to makeLibCall function.
MakeLibCallOptions & setTypeListBeforeSoften(ArrayRef< EVT > OpsVT, EVT RetVT)
A convenience struct that encapsulates a DAG, and two SDValues for returning information from TargetL...