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
116
119 GRLenVT, Custom);
120
122
127
129 setOperationAction(ISD::TRAP, MVT::Other, Legal);
130
134
136
137 // BITREV/REVB requires the 32S feature.
138 if (STI.has32S()) {
139 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
140 // we get to know which of sll and revb.2h is faster.
143
144 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
145 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
146 // and i32 could still be byte-swapped relatively cheaply.
148 } else {
156 }
157
164
167
168 // Set operations for LA64 only.
169
170 if (Subtarget.is64Bit()) {
188
192 Custom);
194 }
195
196 // Set operations for LA32 only.
197
198 if (!Subtarget.is64Bit()) {
204 if (Subtarget.hasBasicD())
206 }
207
209
210 static const ISD::CondCode FPCCToExpand[] = {
213
214 // Set operations for 'F' feature.
215
216 if (Subtarget.hasBasicF()) {
217 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
218 setTruncStoreAction(MVT::f32, MVT::f16, Expand);
219 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::bf16, Expand);
220 setTruncStoreAction(MVT::f32, MVT::bf16, Expand);
221 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
222
241 Subtarget.isSoftFPABI() ? LibCall : Custom);
243 Subtarget.isSoftFPABI() ? LibCall : Custom);
246 Subtarget.isSoftFPABI() ? LibCall : Custom);
249
250 if (Subtarget.is64Bit())
252
253 if (!Subtarget.hasBasicD()) {
255 if (Subtarget.is64Bit()) {
258 }
259 }
260 }
261
262 // Set operations for 'D' feature.
263
264 if (Subtarget.hasBasicD()) {
265 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
266 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
267 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::bf16, Expand);
268 setTruncStoreAction(MVT::f64, MVT::bf16, Expand);
269 setTruncStoreAction(MVT::f64, MVT::f16, Expand);
270 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
271 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
272
292 Subtarget.isSoftFPABI() ? LibCall : Custom);
295 Subtarget.isSoftFPABI() ? LibCall : Custom);
296
297 if (Subtarget.is64Bit())
299 }
300
301 // Set operations for 'LSX' feature.
302
303 if (Subtarget.hasExtLSX()) {
305 // Expand all truncating stores and extending loads.
306 for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
307 setTruncStoreAction(VT, InnerVT, Expand);
310 setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
311 }
312 // By default everything must be expanded. Then we will selectively turn
313 // on ones that can be effectively codegen'd.
314 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
316 }
317
318 for (MVT VT : LSXVTs) {
322
326
331 }
332 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
335 Legal);
337 VT, Legal);
344 Expand);
359 }
360 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
362 for (MVT VT : {MVT::v8i16, MVT::v4i32, MVT::v2i64})
364 for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
367 }
369 for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
377 VT, Expand);
385 }
387 setOperationAction(ISD::FCEIL, {MVT::f32, MVT::f64}, Legal);
388 setOperationAction(ISD::FFLOOR, {MVT::f32, MVT::f64}, Legal);
389 setOperationAction(ISD::FTRUNC, {MVT::f32, MVT::f64}, Legal);
390 setOperationAction(ISD::FROUNDEVEN, {MVT::f32, MVT::f64}, Legal);
391
392 for (MVT VT :
393 {MVT::v16i8, MVT::v8i8, MVT::v4i8, MVT::v2i8, MVT::v8i16, MVT::v4i16,
394 MVT::v2i16, MVT::v4i32, MVT::v2i32, MVT::v2i64}) {
404 }
407 // We want to legalize this to an f64 load rather than an i64 load.
408 setOperationAction(ISD::LOAD, MVT::v2f32, Custom);
409 for (MVT VT : {MVT::v2i64, MVT::v4i32, MVT::v8i16})
411 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v16i32, MVT::v8i64,
412 MVT::v16i64})
414 }
415
416 // Set operations for 'LASX' feature.
417
418 if (Subtarget.hasExtLASX()) {
419 for (MVT VT : LASXVTs) {
423
429
433 }
434 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
437 Legal);
439 VT, Legal);
446 Expand);
462 }
463 for (MVT VT : {MVT::v32i8, MVT::v16i16, MVT::v8i32})
465 for (MVT VT : {MVT::v16i16, MVT::v8i32, MVT::v4i64})
467 for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
471 }
472 for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
480 VT, Expand);
488 }
491 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
495 }
496 for (MVT VT :
497 {MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
500 }
501 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32})
503 }
504
505 // Set DAG combine for LA32 and LA64.
506 if (Subtarget.hasBasicF()) {
508 }
509
514
515 // On targets with the 32S feature, `select` is expanded into
516 // maskeqz + masknez + or (3 instructions), which is more expensive than
517 // on most other architectures where a single cmov-like instruction
518 // suffices. Enable a combine that can turn
519 // select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
520 // select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
521 // for binop in {add, or, xor, sub}, replacing the 3-insn select (plus
522 // the original binop) with a single mask instruction plus the binop.
523 if (Subtarget.has32S())
525
526 // Set DAG combine for 'LSX' feature.
527
528 if (Subtarget.hasExtLSX()) {
540 }
541
542 // Set DAG combine for 'LASX' feature.
543 if (Subtarget.hasExtLASX()) {
546 }
547
548 // Compute derived properties from the register classes.
549 computeRegisterProperties(Subtarget.getRegisterInfo());
550
552
555
556 setMaxAtomicSizeInBitsSupported(Subtarget.getGRLen());
557
559
560 // Function alignments.
562 // Set preferred alignments.
563 setPrefFunctionAlignment(Subtarget.getPrefFunctionAlignment());
564 setPrefLoopAlignment(Subtarget.getPrefLoopAlignment());
565 setMaxBytesForAlignment(Subtarget.getMaxBytesForAlignment());
566
567 // cmpxchg sizes down to 8 bits become legal if LAMCAS is available.
568 if (Subtarget.hasLAMCAS())
570
571 if (Subtarget.hasSCQ()) {
574 }
575
576 // Disable strict node mutation.
577 IsStrictFPEnabled = true;
578}
579
581 const GlobalAddressSDNode *GA) const {
582 // In order to maximise the opportunity for common subexpression elimination,
583 // keep a separate ADD node for the global address offset instead of folding
584 // it in the global address node. Later peephole optimisations may choose to
585 // fold it back in when profitable.
586 return false;
587}
588
590 SelectionDAG &DAG) const {
591 switch (Op.getOpcode()) {
593 return lowerATOMIC_FENCE(Op, DAG);
595 return lowerEH_DWARF_CFA(Op, DAG);
597 return lowerGlobalAddress(Op, DAG);
599 return lowerGlobalTLSAddress(Op, DAG);
601 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
603 return lowerINTRINSIC_W_CHAIN(Op, DAG);
605 return lowerINTRINSIC_VOID(Op, DAG);
607 return lowerBlockAddress(Op, DAG);
608 case ISD::JumpTable:
609 return lowerJumpTable(Op, DAG);
610 case ISD::SHL_PARTS:
611 return lowerShiftLeftParts(Op, DAG);
612 case ISD::SRA_PARTS:
613 return lowerShiftRightParts(Op, DAG, true);
614 case ISD::SRL_PARTS:
615 return lowerShiftRightParts(Op, DAG, false);
617 return lowerConstantPool(Op, DAG);
618 case ISD::FP_TO_SINT:
619 return lowerFP_TO_SINT(Op, DAG);
620 case ISD::FP_TO_UINT:
621 return lowerFP_TO_UINT(Op, DAG);
622 case ISD::BITCAST:
623 return lowerBITCAST(Op, DAG);
624 case ISD::UINT_TO_FP:
625 return lowerUINT_TO_FP(Op, DAG);
626 case ISD::SINT_TO_FP:
627 return lowerSINT_TO_FP(Op, DAG);
628 case ISD::VASTART:
629 return lowerVASTART(Op, DAG);
630 case ISD::FRAMEADDR:
631 return lowerFRAMEADDR(Op, DAG);
632 case ISD::RETURNADDR:
633 return lowerRETURNADDR(Op, DAG);
635 return lowerSET_ROUNDING(Op, DAG);
637 return lowerGET_ROUNDING(Op, DAG);
639 return lowerWRITE_REGISTER(Op, DAG);
641 return lowerINSERT_VECTOR_ELT(Op, DAG);
643 return lowerEXTRACT_VECTOR_ELT(Op, DAG);
645 return lowerBUILD_VECTOR(Op, DAG);
647 return lowerCONCAT_VECTORS(Op, DAG);
649 return lowerVECTOR_SHUFFLE(Op, DAG);
650 case ISD::BITREVERSE:
651 return lowerBITREVERSE(Op, DAG);
653 return lowerSCALAR_TO_VECTOR(Op, DAG);
654 case ISD::PREFETCH:
655 return lowerPREFETCH(Op, DAG);
656 case ISD::SELECT:
657 return lowerSELECT(Op, DAG);
658 case ISD::BRCOND:
659 return lowerBRCOND(Op, DAG);
660 case ISD::FP_TO_FP16:
661 return lowerFP_TO_FP16(Op, DAG);
662 case ISD::FP16_TO_FP:
663 return lowerFP16_TO_FP(Op, DAG);
664 case ISD::FP_TO_BF16:
665 return lowerFP_TO_BF16(Op, DAG);
666 case ISD::BF16_TO_FP:
667 return lowerBF16_TO_FP(Op, DAG);
669 return lowerVECREDUCE_ADD(Op, DAG);
670 case ISD::ROTL:
671 case ISD::ROTR:
672 return lowerRotate(Op, DAG);
680 return lowerVECREDUCE(Op, DAG);
681 case ISD::ConstantFP:
682 return lowerConstantFP(Op, DAG);
683 case ISD::SETCC:
684 return lowerSETCC(Op, DAG);
685 case ISD::FP_ROUND:
686 return lowerFP_ROUND(Op, DAG);
687 case ISD::FP_EXTEND:
688 return lowerFP_EXTEND(Op, DAG);
690 return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
692 return lowerDYNAMIC_STACKALLOC(Op, DAG);
693 case ISD::ANY_EXTEND:
694 return lowerANY_EXTEND(Op, DAG);
695 }
696 return SDValue();
697}
698
699// Helper to attempt to return a cheaper, bit-inverted version of \p V.
701 // TODO: don't always ignore oneuse constraints.
702 V = peekThroughBitcasts(V);
703 EVT VT = V.getValueType();
704
705 // Match not(xor X, -1) -> X.
706 if (V.getOpcode() == ISD::XOR &&
707 (ISD::isBuildVectorAllOnes(V.getOperand(1).getNode()) ||
708 isAllOnesConstant(V.getOperand(1))))
709 return V.getOperand(0);
710
711 // Match not(extract_subvector(not(X)) -> extract_subvector(X).
712 if (V.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
713 (isNullConstant(V.getOperand(1)) || V.getOperand(0).hasOneUse())) {
714 if (SDValue Not = isNOT(V.getOperand(0), DAG)) {
715 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
716 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(Not), VT, Not,
717 V.getOperand(1));
718 }
719 }
720
721 // Match not(SplatVector(not(X)) -> SplatVector(X).
722 if (V.getOpcode() == ISD::BUILD_VECTOR) {
723 if (SDValue SplatValue =
724 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
725 if (!V->isOnlyUserOf(SplatValue.getNode()))
726 return SDValue();
727
728 if (SDValue Not = isNOT(SplatValue, DAG)) {
729 Not = DAG.getBitcast(V.getOperand(0).getValueType(), Not);
730 return DAG.getSplat(VT, SDLoc(Not), Not);
731 }
732 }
733 }
734
735 // Match not(or(not(X),not(Y))) -> and(X, Y).
736 if (V.getOpcode() == ISD::OR && DAG.getTargetLoweringInfo().isTypeLegal(VT) &&
737 V.getOperand(0).hasOneUse() && V.getOperand(1).hasOneUse()) {
738 // TODO: Handle cases with single NOT operand -> VANDN
739 if (SDValue Op1 = isNOT(V.getOperand(1), DAG))
740 if (SDValue Op0 = isNOT(V.getOperand(0), DAG))
741 return DAG.getNode(ISD::AND, SDLoc(V), VT, DAG.getBitcast(VT, Op0),
742 DAG.getBitcast(VT, Op1));
743 }
744
745 // TODO: Add more matching patterns. Such as,
746 // not(concat_vectors(not(X), not(Y))) -> concat_vectors(X, Y).
747 // not(slt(C, X)) -> slt(X - 1, C)
748 return SDValue();
749}
750
751// Combine two ISD::FP_ROUND / LoongArchISD::VFCVT nodes with same type to
752// LoongArchISD::VFCVT. For example:
753// x1 = fp_round x, 0
754// y1 = fp_round y, 0
755// z = concat_vectors x1, y1
756// Or
757// x1 = LoongArch::VFCVT undef, x
758// y1 = LoongArch::VFCVT undef, y
759// z = LoongArchISD::VPACKEV y1, x1; or LoongArchISD::VPERMI y1, x1, 68
760// can be combined to:
761// z = LoongArch::VFCVT y, x
763 const LoongArchSubtarget &Subtarget) {
764 assert(((N->getOpcode() == ISD::CONCAT_VECTORS && N->getNumOperands() == 2) ||
765 (N->getOpcode() == LoongArchISD::VPACKEV) ||
766 (N->getOpcode() == LoongArchISD::VPERMI)) &&
767 "Invalid Node");
768
769 SDValue Op0 = peekThroughBitcasts(N->getOperand(0));
770 SDValue Op1 = peekThroughBitcasts(N->getOperand(1));
771 unsigned Opcode0 = Op0.getOpcode();
772 unsigned Opcode1 = Op1.getOpcode();
773 if (Opcode0 != Opcode1)
774 return SDValue();
775
776 if (Opcode0 != ISD::FP_ROUND && Opcode0 != LoongArchISD::VFCVT)
777 return SDValue();
778
779 // Check if two nodes have only one use.
780 if (!Op0.hasOneUse() || !Op1.hasOneUse())
781 return SDValue();
782
783 EVT VT = N.getValueType();
784 EVT SVT0 = Op0.getValueType();
785 EVT SVT1 = Op1.getValueType();
786 // Check if two nodes have the same result type.
787 if (SVT0 != SVT1)
788 return SDValue();
789
790 // Check if two nodes have the same operand type.
791 EVT SSVT0 = Op0.getOperand(0).getValueType();
792 EVT SSVT1 = Op1.getOperand(0).getValueType();
793 if (SSVT0 != SSVT1)
794 return SDValue();
795
796 if (N->getOpcode() == ISD::CONCAT_VECTORS && Opcode0 == ISD::FP_ROUND) {
797 if (Subtarget.hasExtLASX() && VT.is256BitVector() && SVT0 == MVT::v4f32 &&
798 SSVT0 == MVT::v4f64) {
799 // A vector_shuffle is required in the final step, as xvfcvt instruction
800 // operates on each 128-bit segament as a lane.
801 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v8f32,
802 Op1.getOperand(0), Op0.getOperand(0));
803 SDValue Undef = DAG.getUNDEF(Res.getValueType());
804 // After VFCVT, the high part of Res comes from the high parts of Op0 and
805 // Op1, and the low part comes from the low parts of Op0 and Op1. However,
806 // the desired order requires Op0 to fully occupy the lower half and Op1
807 // the upper half of Res. The Mask reorders the elements of Res to achieve
808 // this:
809 // - The first four elements (0, 1, 4, 5) come from Op0.
810 // - The next four elements (2, 3, 6, 7) come from Op1.
811 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
812 Res = DAG.getVectorShuffle(Res.getValueType(), DL, Res, Undef, Mask);
813 return DAG.getBitcast(VT, Res);
814 }
815 }
816
817 if ((N->getOpcode() == LoongArchISD::VPACKEV ||
818 N->getOpcode() == LoongArchISD::VPERMI) &&
819 Opcode0 == LoongArchISD::VFCVT) {
820 // For VPACKEV or VPERMI, check if the first operation of VFCVT is undef.
821 if (!Op0.getOperand(0).isUndef() || !Op1.getOperand(0).isUndef())
822 return SDValue();
823
824 if (!Subtarget.hasExtLSX() || SVT0 != MVT::v4f32 || SSVT0 != MVT::v2f64)
825 return SDValue();
826
827 if (N->getOpcode() == LoongArchISD::VPACKEV &&
828 (VT == MVT::v2i64 || VT == MVT::v2f64)) {
829 SDValue Res = DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32,
830 Op0.getOperand(1), Op1.getOperand(1));
831 return DAG.getBitcast(VT, Res);
832 }
833
834 if (N->getOpcode() == LoongArchISD::VPERMI && VT == MVT::v4f32) {
835 int64_t Imm = cast<ConstantSDNode>(N->getOperand(2))->getSExtValue();
836 if (Imm != 68)
837 return SDValue();
838 return DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Op0.getOperand(1),
839 Op1.getOperand(1));
840 }
841 }
842
843 return SDValue();
844}
845
846SDValue LoongArchTargetLowering::lowerFP_ROUND(SDValue Op,
847 SelectionDAG &DAG) const {
848 SDLoc DL(Op);
849 SDValue In = Op.getOperand(0);
850 MVT VT = Op.getSimpleValueType();
851 MVT SVT = In.getSimpleValueType();
852
853 if (VT == MVT::v4f32 && SVT == MVT::v4f64) {
854 SDValue Lo, Hi;
855 std::tie(Lo, Hi) = DAG.SplitVector(In, DL);
856 return DAG.getNode(LoongArchISD::VFCVT, DL, VT, Hi, Lo);
857 }
858
859 return SDValue();
860}
861
862SDValue LoongArchTargetLowering::lowerFP_EXTEND(SDValue Op,
863 SelectionDAG &DAG) const {
864
865 SDLoc DL(Op);
866 EVT VT = Op.getValueType();
867 SDValue Src = Op->getOperand(0);
868 EVT SVT = Src.getValueType();
869
870 bool V2F32ToV2F64 =
871 VT == MVT::v2f64 && SVT == MVT::v2f32 && Subtarget.hasExtLSX();
872 bool V4F32ToV4F64 =
873 VT == MVT::v4f64 && SVT == MVT::v4f32 && Subtarget.hasExtLASX();
874 if (!V2F32ToV2F64 && !V4F32ToV4F64)
875 return SDValue();
876
877 // Check if Op is the high part of vector.
878 auto CheckVecHighPart = [](SDValue Op) {
880 if (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
881 SDValue SOp = Op.getOperand(0);
882 EVT SVT = SOp.getValueType();
883 if (!SVT.isVector() || (SVT.getVectorNumElements() % 2 != 0))
884 return SDValue();
885
886 const uint64_t Imm = Op.getConstantOperandVal(1);
887 if (Imm == SVT.getVectorNumElements() / 2)
888 return SOp;
889 return SDValue();
890 }
891 return SDValue();
892 };
893
894 unsigned Opcode;
895 SDValue VFCVTOp;
896 EVT WideOpVT = SVT.getSimpleVT().getDoubleNumVectorElementsVT();
897 SDValue ZeroIdx = DAG.getVectorIdxConstant(0, DL);
898
899 // If the operand of ISD::FP_EXTEND comes from the high part of vector,
900 // generate LoongArchISD::VFCVTH, otherwise LoongArchISD::VFCVTL.
901 if (SDValue V = CheckVecHighPart(Src)) {
902 assert(V.getValueSizeInBits() == WideOpVT.getSizeInBits() &&
903 "Unexpected wide vector");
904 Opcode = LoongArchISD::VFCVTH;
905 VFCVTOp = DAG.getBitcast(WideOpVT, V);
906 } else {
907 Opcode = LoongArchISD::VFCVTL;
908 VFCVTOp = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WideOpVT,
909 DAG.getUNDEF(WideOpVT), Src, ZeroIdx);
910 }
911
912 // v2f64 = fp_extend v2f32
913 if (V2F32ToV2F64)
914 return DAG.getNode(Opcode, DL, VT, VFCVTOp);
915
916 // v4f64 = fp_extend v4f32
917 if (V4F32ToV4F64) {
918 // XVFCVT instruction operates on each 128-bit segment as a lane, so a
919 // vector_shuffle is required firstly.
920 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
921 SDValue Res = DAG.getVectorShuffle(WideOpVT, DL, VFCVTOp,
922 DAG.getUNDEF(WideOpVT), Mask);
923 Res = DAG.getNode(Opcode, DL, VT, Res);
924 return Res;
925 }
926
927 return SDValue();
928}
929
930SDValue LoongArchTargetLowering::lowerConstantFP(SDValue Op,
931 SelectionDAG &DAG) const {
932 EVT VT = Op.getValueType();
933 ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
934 const APFloat &FPVal = CFP->getValueAPF();
935 SDLoc DL(CFP);
936
937 assert((VT == MVT::f32 && Subtarget.hasBasicF()) ||
938 (VT == MVT::f64 && Subtarget.hasBasicD()));
939
940 // If value is 0.0 or -0.0, just ignore it.
941 if (FPVal.isZero())
942 return SDValue();
943
944 // If lsx enabled, use cheaper 'vldi' instruction if possible.
945 if (isFPImmVLDILegal(FPVal, VT))
946 return SDValue();
947
948 // Construct as integer, and move to float register.
949 APInt INTVal = FPVal.bitcastToAPInt();
950
951 // If more than MaterializeFPImmInsNum instructions will be used to
952 // generate the INTVal and move it to float register, fallback to
953 // use floating point load from the constant pool.
955 int InsNum = Seq.size() + ((VT == MVT::f64 && !Subtarget.is64Bit()) ? 2 : 1);
956 if (InsNum > MaterializeFPImmInsNum && !FPVal.isOne())
957 return SDValue();
958
959 switch (VT.getSimpleVT().SimpleTy) {
960 default:
961 llvm_unreachable("Unexpected floating point type!");
962 break;
963 case MVT::f32: {
964 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i32);
965 if (Subtarget.is64Bit())
966 NewVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, NewVal);
967 return DAG.getNode(Subtarget.is64Bit() ? LoongArchISD::MOVGR2FR_W_LA64
968 : LoongArchISD::MOVGR2FR_W,
969 DL, VT, NewVal);
970 }
971 case MVT::f64: {
972 if (Subtarget.is64Bit()) {
973 SDValue NewVal = DAG.getConstant(INTVal, DL, MVT::i64);
974 return DAG.getNode(LoongArchISD::MOVGR2FR_D, DL, VT, NewVal);
975 }
976 SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
977 SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
978 return DAG.getNode(LoongArchISD::MOVGR2FR_D_LO_HI, DL, VT, Lo, Hi);
979 }
980 }
981
982 return SDValue();
983}
984
985// Ensure SETCC result and operand have the same bit width; isel does not
986// support mismatched widths.
987SDValue LoongArchTargetLowering::lowerSETCC(SDValue Op,
988 SelectionDAG &DAG) const {
989 SDLoc DL(Op);
990 EVT ResultVT = Op.getValueType();
991 EVT OperandVT = Op.getOperand(0).getValueType();
992
993 EVT SetCCResultVT =
994 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), OperandVT);
995
996 if (ResultVT == SetCCResultVT)
997 return Op;
998
999 assert(Op.getOperand(0).getValueType() == Op.getOperand(1).getValueType() &&
1000 "SETCC operands must have the same type!");
1001
1002 SDValue SetCCNode =
1003 DAG.getNode(ISD::SETCC, DL, SetCCResultVT, Op.getOperand(0),
1004 Op.getOperand(1), Op.getOperand(2));
1005
1006 if (ResultVT.bitsGT(SetCCResultVT))
1007 SetCCNode = DAG.getNode(ISD::SIGN_EXTEND, DL, ResultVT, SetCCNode);
1008 else if (ResultVT.bitsLT(SetCCResultVT))
1009 SetCCNode = DAG.getNode(ISD::TRUNCATE, DL, ResultVT, SetCCNode);
1010
1011 return SetCCNode;
1012}
1013
1014// Lower sext_invec using vslti instructions.
1015// For example:
1016// %b = sext <4 x i16> %a to <4 x i32>
1017// can be lowered to:
1018// VSLTI_H vr2, vr1, 0
1019// VILVL.H vr1, vr2, vr1
1020SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
1021 SDValue Op, SelectionDAG &DAG) const {
1022 SDLoc DL(Op);
1023 SDValue Src = Op.getOperand(0);
1024 MVT SrcVT = Src.getSimpleValueType();
1025 MVT DstVT = Op.getSimpleValueType();
1026
1027 if (!SrcVT.is128BitVector())
1028 return SDValue();
1029
1030 // lower to VSLTI + VILVL if extend could be done in single step.
1031 if (DstVT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits() == 2) {
1032 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
1033 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Src, Zero,
1034 DAG.getCondCode(ISD::SETLT));
1035 SDValue LoInterleaved =
1036 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Src);
1037
1038 return DAG.getBitcast(DstVT, LoInterleaved);
1039 }
1040
1041 return SDValue();
1042}
1043
1044// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
1045SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
1046 SelectionDAG &DAG) const {
1047 assert(Subtarget.hasExtLASX());
1048 // We don't have corresponding instrunction for ANY_EXTEND, lowering it to
1049 // ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
1050 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
1051 Op.getOperand(0));
1052}
1053
1054// Lower vecreduce_add using vhaddw instructions.
1055// For Example:
1056// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)
1057// can be lowered to:
1058// VHADDW_D_W vr0, vr0, vr0
1059// VHADDW_Q_D vr0, vr0, vr0
1060// VPICKVE2GR_D a0, vr0, 0
1061// ADDI_W a0, a0, 0
1062SDValue LoongArchTargetLowering::lowerVECREDUCE_ADD(SDValue Op,
1063 SelectionDAG &DAG) const {
1064
1065 SDLoc DL(Op);
1066 MVT OpVT = Op.getSimpleValueType();
1067 SDValue Val = Op.getOperand(0);
1068
1069 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1070 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1071 unsigned ResBits = OpVT.getScalarSizeInBits();
1072
1073 unsigned LegalVecSize = 128;
1074 bool isLASX256Vector =
1075 Subtarget.hasExtLASX() && Val.getValueSizeInBits() == 256;
1076
1077 // Ensure operand type legal or enable it legal.
1078 while (!isTypeLegal(Val.getSimpleValueType())) {
1079 Val = DAG.WidenVector(Val, DL);
1080 }
1081
1082 // NumEles is designed for iterations count, v4i32 for LSX
1083 // and v8i32 for LASX should have the same count.
1084 if (isLASX256Vector) {
1085 NumEles /= 2;
1086 LegalVecSize = 256;
1087 }
1088
1089 EleBits *= 2;
1090 for (unsigned i = 1; i < NumEles; i *= 2, EleBits *= 2) {
1091 EleBits = std::min(EleBits, 64u);
1092 MVT IntTy = MVT::getIntegerVT(EleBits);
1093 MVT VecTy = MVT::getVectorVT(IntTy, LegalVecSize / EleBits);
1094 Val = DAG.getNode(LoongArchISD::VHADDW, DL, VecTy, Val, Val);
1095 }
1096
1097 if (isLASX256Vector) {
1098 SDValue Tmp = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, Val,
1099 DAG.getConstant(2, DL, Subtarget.getGRLenVT()));
1100 Val = DAG.getNode(ISD::ADD, DL, MVT::v4i64, Tmp, Val);
1101 }
1102
1103 Val = DAG.getBitcast(MVT::getVectorVT(OpVT, LegalVecSize / ResBits), Val);
1104 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1105 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
1106}
1107
1108// Lower vecreduce_and/or/xor/[s/u]max/[s/u]min.
1109// For Example:
1110// call i32 @llvm.vector.reduce.smax.v4i32(<4 x i32> %a)
1111// can be lowered to:
1112// VBSRL_V vr1, vr0, 8
1113// VMAX_W vr0, vr1, vr0
1114// VBSRL_V vr1, vr0, 4
1115// VMAX_W vr0, vr1, vr0
1116// VPICKVE2GR_W a0, vr0, 0
1117// For 256 bit vector, it is illegal and will be spilt into
1118// two 128 bit vector by default then processed by this.
1119SDValue LoongArchTargetLowering::lowerVECREDUCE(SDValue Op,
1120 SelectionDAG &DAG) const {
1121 SDLoc DL(Op);
1122
1123 MVT OpVT = Op.getSimpleValueType();
1124 SDValue Val = Op.getOperand(0);
1125
1126 unsigned NumEles = Val.getSimpleValueType().getVectorNumElements();
1127 unsigned EleBits = Val.getSimpleValueType().getScalarSizeInBits();
1128
1129 // Ensure operand type legal or enable it legal.
1130 while (!isTypeLegal(Val.getSimpleValueType())) {
1131 Val = DAG.WidenVector(Val, DL);
1132 }
1133
1134 unsigned Opcode = ISD::getVecReduceBaseOpcode(Op.getOpcode());
1135 MVT VecTy = Val.getSimpleValueType();
1136 MVT GRLenVT = Subtarget.getGRLenVT();
1137
1138 for (int i = NumEles; i > 1; i /= 2) {
1139 SDValue ShiftAmt = DAG.getConstant(i * EleBits / 16, DL, GRLenVT);
1140 SDValue Tmp = DAG.getNode(LoongArchISD::VBSRL, DL, VecTy, Val, ShiftAmt);
1141 Val = DAG.getNode(Opcode, DL, VecTy, Tmp, Val);
1142 }
1143
1144 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, OpVT, Val,
1145 DAG.getConstant(0, DL, GRLenVT));
1146}
1147
1148SDValue LoongArchTargetLowering::lowerPREFETCH(SDValue Op,
1149 SelectionDAG &DAG) const {
1150 unsigned IsData = Op.getConstantOperandVal(4);
1151
1152 // We don't support non-data prefetch.
1153 // Just preserve the chain.
1154 if (!IsData)
1155 return Op.getOperand(0);
1156
1157 return Op;
1158}
1159
1160SDValue LoongArchTargetLowering::lowerRotate(SDValue Op,
1161 SelectionDAG &DAG) const {
1162 MVT VT = Op.getSimpleValueType();
1163 assert(VT.isVector() && "Unexpected type");
1164
1165 SDLoc DL(Op);
1166 SDValue R = Op.getOperand(0);
1167 SDValue Amt = Op.getOperand(1);
1168 unsigned Opcode = Op.getOpcode();
1169 unsigned EltSizeInBits = VT.getScalarSizeInBits();
1170
1171 auto checkCstSplat = [](SDValue V, APInt &CstSplatValue) {
1172 if (V.getOpcode() != ISD::BUILD_VECTOR)
1173 return false;
1174 if (SDValue SplatValue =
1175 cast<BuildVectorSDNode>(V.getNode())->getSplatValue()) {
1176 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
1177 CstSplatValue = C->getAPIntValue();
1178 return true;
1179 }
1180 }
1181 return false;
1182 };
1183
1184 // Check for constant splat rotation amount.
1185 APInt CstSplatValue;
1186 bool IsCstSplat = checkCstSplat(Amt, CstSplatValue);
1187 bool isROTL = Opcode == ISD::ROTL;
1188
1189 // Check for splat rotate by zero.
1190 if (IsCstSplat && CstSplatValue.urem(EltSizeInBits) == 0)
1191 return R;
1192
1193 // LoongArch targets always prefer ISD::ROTR.
1194 if (isROTL) {
1195 SDValue Zero = DAG.getConstant(0, DL, VT);
1196 return DAG.getNode(ISD::ROTR, DL, VT, R,
1197 DAG.getNode(ISD::SUB, DL, VT, Zero, Amt));
1198 }
1199
1200 // Rotate by a immediate.
1201 if (IsCstSplat) {
1202 // ISD::ROTR: Attemp to rotate by a positive immediate.
1203 SDValue Bits = DAG.getConstant(EltSizeInBits, DL, VT);
1204 if (SDValue Urem =
1205 DAG.FoldConstantArithmetic(ISD::UREM, DL, VT, {Amt, Bits}))
1206 return DAG.getNode(Opcode, DL, VT, R, Urem);
1207 }
1208
1209 return Op;
1210}
1211
1212// Return true if Val is equal to (setcc LHS, RHS, CC).
1213// Return false if Val is the inverse of (setcc LHS, RHS, CC).
1214// Otherwise, return std::nullopt.
1215static std::optional<bool> matchSetCC(SDValue LHS, SDValue RHS,
1216 ISD::CondCode CC, SDValue Val) {
1217 assert(Val->getOpcode() == ISD::SETCC);
1218 SDValue LHS2 = Val.getOperand(0);
1219 SDValue RHS2 = Val.getOperand(1);
1220 ISD::CondCode CC2 = cast<CondCodeSDNode>(Val.getOperand(2))->get();
1221
1222 if (LHS == LHS2 && RHS == RHS2) {
1223 if (CC == CC2)
1224 return true;
1225 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1226 return false;
1227 } else if (LHS == RHS2 && RHS == LHS2) {
1229 if (CC == CC2)
1230 return true;
1231 if (CC == ISD::getSetCCInverse(CC2, LHS2.getValueType()))
1232 return false;
1233 }
1234
1235 return std::nullopt;
1236}
1237
1239 const LoongArchSubtarget &Subtarget) {
1240 SDValue CondV = N->getOperand(0);
1241 SDValue TrueV = N->getOperand(1);
1242 SDValue FalseV = N->getOperand(2);
1243 MVT VT = N->getSimpleValueType(0);
1244 SDLoc DL(N);
1245
1246 // (select c, -1, y) -> -c | y
1247 if (isAllOnesConstant(TrueV)) {
1248 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1249 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
1250 }
1251 // (select c, y, -1) -> (c-1) | y
1252 if (isAllOnesConstant(FalseV)) {
1253 SDValue Neg =
1254 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1255 return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(TrueV));
1256 }
1257
1258 // (select c, 0, y) -> (c-1) & y
1259 if (isNullConstant(TrueV)) {
1260 SDValue Neg =
1261 DAG.getNode(ISD::ADD, DL, VT, CondV, DAG.getAllOnesConstant(DL, VT));
1262 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(FalseV));
1263 }
1264 // (select c, y, 0) -> -c & y
1265 if (isNullConstant(FalseV)) {
1266 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1267 return DAG.getNode(ISD::AND, DL, VT, Neg, DAG.getFreeze(TrueV));
1268 }
1269
1270 // select c, ~x, x --> xor -c, x
1271 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
1272 const APInt &TrueVal = TrueV->getAsAPIntVal();
1273 const APInt &FalseVal = FalseV->getAsAPIntVal();
1274 if (~TrueVal == FalseVal) {
1275 SDValue Neg = DAG.getNegative(CondV, DL, VT);
1276 return DAG.getNode(ISD::XOR, DL, VT, Neg, FalseV);
1277 }
1278 }
1279
1280 // Try to fold (select (setcc lhs, rhs, cc), truev, falsev) into bitwise ops
1281 // when both truev and falsev are also setcc.
1282 if (CondV.getOpcode() == ISD::SETCC && TrueV.getOpcode() == ISD::SETCC &&
1283 FalseV.getOpcode() == ISD::SETCC) {
1284 SDValue LHS = CondV.getOperand(0);
1285 SDValue RHS = CondV.getOperand(1);
1286 ISD::CondCode CC = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1287
1288 // (select x, x, y) -> x | y
1289 // (select !x, x, y) -> x & y
1290 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, TrueV)) {
1291 return DAG.getNode(*MatchResult ? ISD::OR : ISD::AND, DL, VT, TrueV,
1292 DAG.getFreeze(FalseV));
1293 }
1294 // (select x, y, x) -> x & y
1295 // (select !x, y, x) -> x | y
1296 if (std::optional<bool> MatchResult = matchSetCC(LHS, RHS, CC, FalseV)) {
1297 return DAG.getNode(*MatchResult ? ISD::AND : ISD::OR, DL, VT,
1298 DAG.getFreeze(TrueV), FalseV);
1299 }
1300 }
1301
1302 return SDValue();
1303}
1304
1305// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
1306// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
1307// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
1308// being `0` or `-1`. In such cases we can replace `select` with `and`.
1309// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
1310// than `c0`?
1311static SDValue
1313 const LoongArchSubtarget &Subtarget) {
1314 unsigned SelOpNo = 0;
1315 SDValue Sel = BO->getOperand(0);
1316 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
1317 SelOpNo = 1;
1318 Sel = BO->getOperand(1);
1319 }
1320
1321 if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
1322 return SDValue();
1323
1324 unsigned ConstSelOpNo = 1;
1325 unsigned OtherSelOpNo = 2;
1326 if (!isa<ConstantSDNode>(Sel->getOperand(ConstSelOpNo))) {
1327 ConstSelOpNo = 2;
1328 OtherSelOpNo = 1;
1329 }
1330 SDValue ConstSelOp = Sel->getOperand(ConstSelOpNo);
1331 ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
1332 if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
1333 return SDValue();
1334
1335 SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
1336 ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
1337 if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
1338 return SDValue();
1339
1340 SDLoc DL(Sel);
1341 EVT VT = BO->getValueType(0);
1342
1343 SDValue NewConstOps[2] = {ConstSelOp, ConstBinOp};
1344 if (SelOpNo == 1)
1345 std::swap(NewConstOps[0], NewConstOps[1]);
1346
1347 SDValue NewConstOp =
1348 DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT, NewConstOps);
1349 if (!NewConstOp)
1350 return SDValue();
1351
1352 const APInt &NewConstAPInt = NewConstOp->getAsAPIntVal();
1353 if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
1354 return SDValue();
1355
1356 SDValue OtherSelOp = Sel->getOperand(OtherSelOpNo);
1357 SDValue NewNonConstOps[2] = {OtherSelOp, ConstBinOp};
1358 if (SelOpNo == 1)
1359 std::swap(NewNonConstOps[0], NewNonConstOps[1]);
1360 SDValue NewNonConstOp = DAG.getNode(BO->getOpcode(), DL, VT, NewNonConstOps);
1361
1362 SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
1363 SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
1364 return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
1365}
1366
1367// Changes the condition code and swaps operands if necessary, so the SetCC
1368// operation matches one of the comparisons supported directly by branches
1369// in the LoongArch ISA. May adjust compares to favor compare with 0 over
1370// compare with 1/-1.
1372 ISD::CondCode &CC, SelectionDAG &DAG) {
1373 // If this is a single bit test that can't be handled by ANDI, shift the
1374 // bit to be tested to the MSB and perform a signed compare with 0.
1375 if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
1376 LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
1377 isa<ConstantSDNode>(LHS.getOperand(1))) {
1378 uint64_t Mask = LHS.getConstantOperandVal(1);
1379 if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
1380 unsigned ShAmt = 0;
1381 if (isPowerOf2_64(Mask)) {
1382 CC = CC == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
1383 ShAmt = LHS.getValueSizeInBits() - 1 - Log2_64(Mask);
1384 } else {
1385 ShAmt = LHS.getValueSizeInBits() - llvm::bit_width(Mask);
1386 }
1387
1388 LHS = LHS.getOperand(0);
1389 if (ShAmt != 0)
1390 LHS = DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS,
1391 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
1392 return;
1393 }
1394 }
1395
1396 if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
1397 int64_t C = RHSC->getSExtValue();
1398 switch (CC) {
1399 default:
1400 break;
1401 case ISD::SETGT:
1402 // Convert X > -1 to X >= 0.
1403 if (C == -1) {
1404 RHS = DAG.getConstant(0, DL, RHS.getValueType());
1405 CC = ISD::SETGE;
1406 return;
1407 }
1408 break;
1409 case ISD::SETLT:
1410 // Convert X < 1 to 0 >= X.
1411 if (C == 1) {
1412 RHS = LHS;
1413 LHS = DAG.getConstant(0, DL, RHS.getValueType());
1414 CC = ISD::SETGE;
1415 return;
1416 }
1417 break;
1418 }
1419 }
1420
1421 switch (CC) {
1422 default:
1423 break;
1424 case ISD::SETGT:
1425 case ISD::SETLE:
1426 case ISD::SETUGT:
1427 case ISD::SETULE:
1429 std::swap(LHS, RHS);
1430 break;
1431 }
1432}
1433
1434SDValue LoongArchTargetLowering::lowerSELECT(SDValue Op,
1435 SelectionDAG &DAG) const {
1436 SDValue CondV = Op.getOperand(0);
1437 SDValue TrueV = Op.getOperand(1);
1438 SDValue FalseV = Op.getOperand(2);
1439 SDLoc DL(Op);
1440 MVT VT = Op.getSimpleValueType();
1441 MVT GRLenVT = Subtarget.getGRLenVT();
1442
1443 if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
1444 return V;
1445
1446 if (Op.hasOneUse()) {
1447 unsigned UseOpc = Op->user_begin()->getOpcode();
1448 if (isBinOp(UseOpc) && DAG.isSafeToSpeculativelyExecute(UseOpc)) {
1449 SDNode *BinOp = *Op->user_begin();
1450 if (SDValue NewSel = foldBinOpIntoSelectIfProfitable(*Op->user_begin(),
1451 DAG, Subtarget)) {
1452 DAG.ReplaceAllUsesWith(BinOp, &NewSel);
1453 // Opcode check is necessary because foldBinOpIntoSelectIfProfitable
1454 // may return a constant node and cause crash in lowerSELECT.
1455 if (NewSel.getOpcode() == ISD::SELECT)
1456 return lowerSELECT(NewSel, DAG);
1457 return NewSel;
1458 }
1459 }
1460 }
1461
1462 // If the condition is not an integer SETCC which operates on GRLenVT, we need
1463 // to emit a LoongArchISD::SELECT_CC comparing the condition to zero. i.e.:
1464 // (select condv, truev, falsev)
1465 // -> (loongarchisd::select_cc condv, zero, setne, truev, falsev)
1466 if (CondV.getOpcode() != ISD::SETCC ||
1467 CondV.getOperand(0).getSimpleValueType() != GRLenVT) {
1468 SDValue Zero = DAG.getConstant(0, DL, GRLenVT);
1469 SDValue SetNE = DAG.getCondCode(ISD::SETNE);
1470
1471 SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
1472
1473 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1474 }
1475
1476 // If the CondV is the output of a SETCC node which operates on GRLenVT
1477 // inputs, then merge the SETCC node into the lowered LoongArchISD::SELECT_CC
1478 // to take advantage of the integer compare+branch instructions. i.e.: (select
1479 // (setcc lhs, rhs, cc), truev, falsev)
1480 // -> (loongarchisd::select_cc lhs, rhs, cc, truev, falsev)
1481 SDValue LHS = CondV.getOperand(0);
1482 SDValue RHS = CondV.getOperand(1);
1483 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1484
1485 // Special case for a select of 2 constants that have a difference of 1.
1486 // Normally this is done by DAGCombine, but if the select is introduced by
1487 // type legalization or op legalization, we miss it. Restricting to SETLT
1488 // case for now because that is what signed saturating add/sub need.
1489 // FIXME: We don't need the condition to be SETLT or even a SETCC,
1490 // but we would probably want to swap the true/false values if the condition
1491 // is SETGE/SETLE to avoid an XORI.
1492 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
1493 CCVal == ISD::SETLT) {
1494 const APInt &TrueVal = TrueV->getAsAPIntVal();
1495 const APInt &FalseVal = FalseV->getAsAPIntVal();
1496 if (TrueVal - 1 == FalseVal)
1497 return DAG.getNode(ISD::ADD, DL, VT, CondV, FalseV);
1498 if (TrueVal + 1 == FalseVal)
1499 return DAG.getNode(ISD::SUB, DL, VT, FalseV, CondV);
1500 }
1501
1502 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1503 // 1 < x ? x : 1 -> 0 < x ? x : 1
1504 if (isOneConstant(LHS) && (CCVal == ISD::SETLT || CCVal == ISD::SETULT) &&
1505 RHS == TrueV && LHS == FalseV) {
1506 LHS = DAG.getConstant(0, DL, VT);
1507 // 0 <u x is the same as x != 0.
1508 if (CCVal == ISD::SETULT) {
1509 std::swap(LHS, RHS);
1510 CCVal = ISD::SETNE;
1511 }
1512 }
1513
1514 // x <s -1 ? x : -1 -> x <s 0 ? x : -1
1515 if (isAllOnesConstant(RHS) && CCVal == ISD::SETLT && LHS == TrueV &&
1516 RHS == FalseV) {
1517 RHS = DAG.getConstant(0, DL, VT);
1518 }
1519
1520 SDValue TargetCC = DAG.getCondCode(CCVal);
1521
1522 if (isa<ConstantSDNode>(TrueV) && !isa<ConstantSDNode>(FalseV)) {
1523 // (select (setcc lhs, rhs, CC), constant, falsev)
1524 // -> (select (setcc lhs, rhs, InverseCC), falsev, constant)
1525 std::swap(TrueV, FalseV);
1526 TargetCC = DAG.getCondCode(ISD::getSetCCInverse(CCVal, LHS.getValueType()));
1527 }
1528
1529 SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
1530 return DAG.getNode(LoongArchISD::SELECT_CC, DL, VT, Ops);
1531}
1532
1533SDValue LoongArchTargetLowering::lowerBRCOND(SDValue Op,
1534 SelectionDAG &DAG) const {
1535 SDValue CondV = Op.getOperand(1);
1536 SDLoc DL(Op);
1537 MVT GRLenVT = Subtarget.getGRLenVT();
1538
1539 if (CondV.getOpcode() == ISD::SETCC) {
1540 if (CondV.getOperand(0).getValueType() == GRLenVT) {
1541 SDValue LHS = CondV.getOperand(0);
1542 SDValue RHS = CondV.getOperand(1);
1543 ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
1544
1545 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
1546
1547 SDValue TargetCC = DAG.getCondCode(CCVal);
1548 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1549 Op.getOperand(0), LHS, RHS, TargetCC,
1550 Op.getOperand(2));
1551 } else if (CondV.getOperand(0).getValueType().isFloatingPoint()) {
1552 return DAG.getNode(LoongArchISD::BRCOND, DL, Op.getValueType(),
1553 Op.getOperand(0), CondV, Op.getOperand(2));
1554 }
1555 }
1556
1557 return DAG.getNode(LoongArchISD::BR_CC, DL, Op.getValueType(),
1558 Op.getOperand(0), CondV, DAG.getConstant(0, DL, GRLenVT),
1559 DAG.getCondCode(ISD::SETNE), Op.getOperand(2));
1560}
1561
1562SDValue
1563LoongArchTargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,
1564 SelectionDAG &DAG) const {
1565 SDLoc DL(Op);
1566 MVT OpVT = Op.getSimpleValueType();
1567
1568 SDValue Vector = DAG.getUNDEF(OpVT);
1569 SDValue Val = Op.getOperand(0);
1570 SDValue Idx = DAG.getConstant(0, DL, Subtarget.getGRLenVT());
1571
1572 return DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, OpVT, Vector, Val, Idx);
1573}
1574
1575SDValue LoongArchTargetLowering::lowerBITREVERSE(SDValue Op,
1576 SelectionDAG &DAG) const {
1577 EVT ResTy = Op->getValueType(0);
1578 SDValue Src = Op->getOperand(0);
1579 SDLoc DL(Op);
1580
1581 // LoongArchISD::BITREV_8B is not supported on LA32.
1582 if (!Subtarget.is64Bit() && (ResTy == MVT::v16i8 || ResTy == MVT::v32i8))
1583 return SDValue();
1584
1585 EVT NewVT = ResTy.is128BitVector() ? MVT::v2i64 : MVT::v4i64;
1586 unsigned int OrigEltNum = ResTy.getVectorNumElements();
1587 unsigned int NewEltNum = NewVT.getVectorNumElements();
1588
1589 SDValue NewSrc = DAG.getNode(ISD::BITCAST, DL, NewVT, Src);
1590
1592 for (unsigned int i = 0; i < NewEltNum; i++) {
1593 SDValue Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, NewSrc,
1594 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
1595 unsigned RevOp = (ResTy == MVT::v16i8 || ResTy == MVT::v32i8)
1596 ? (unsigned)LoongArchISD::BITREV_8B
1597 : (unsigned)ISD::BITREVERSE;
1598 Ops.push_back(DAG.getNode(RevOp, DL, MVT::i64, Op));
1599 }
1600 SDValue Res =
1601 DAG.getNode(ISD::BITCAST, DL, ResTy, DAG.getBuildVector(NewVT, DL, Ops));
1602
1603 switch (ResTy.getSimpleVT().SimpleTy) {
1604 default:
1605 return SDValue();
1606 case MVT::v16i8:
1607 case MVT::v32i8:
1608 return Res;
1609 case MVT::v8i16:
1610 case MVT::v16i16:
1611 case MVT::v4i32:
1612 case MVT::v8i32: {
1614 for (unsigned int i = 0; i < NewEltNum; i++)
1615 for (int j = OrigEltNum / NewEltNum - 1; j >= 0; j--)
1616 Mask.push_back(j + (OrigEltNum / NewEltNum) * i);
1617 return DAG.getVectorShuffle(ResTy, DL, Res, DAG.getUNDEF(ResTy), Mask);
1618 }
1619 }
1620}
1621
1622// Widen element type to get a new mask value (if possible).
1623// For example:
1624// shufflevector <4 x i32> %a, <4 x i32> %b,
1625// <4 x i32> <i32 6, i32 7, i32 2, i32 3>
1626// is equivalent to:
1627// shufflevector <2 x i64> %a, <2 x i64> %b, <2 x i32> <i32 3, i32 1>
1628// can be lowered to:
1629// VPACKOD_D vr0, vr0, vr1
1631 SDValue V1, SDValue V2, SelectionDAG &DAG) {
1632 unsigned EltBits = VT.getScalarSizeInBits();
1633
1634 if (EltBits > 32 || EltBits == 1)
1635 return SDValue();
1636
1637 SmallVector<int, 8> NewMask;
1638 if (widenShuffleMaskElts(Mask, NewMask)) {
1639 MVT NewEltVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(EltBits * 2)
1640 : MVT::getIntegerVT(EltBits * 2);
1641 MVT NewVT = MVT::getVectorVT(NewEltVT, VT.getVectorNumElements() / 2);
1642 if (DAG.getTargetLoweringInfo().isTypeLegal(NewVT)) {
1643 SDValue NewV1 = DAG.getBitcast(NewVT, V1);
1644 SDValue NewV2 = DAG.getBitcast(NewVT, V2);
1645 return DAG.getBitcast(
1646 VT, DAG.getVectorShuffle(NewVT, DL, NewV1, NewV2, NewMask));
1647 }
1648 }
1649
1650 return SDValue();
1651}
1652
1653/// Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI
1654/// instruction.
1655// The funciton matches elements from one of the input vector shuffled to the
1656// left or right with zeroable elements 'shifted in'. It handles both the
1657// strictly bit-wise element shifts and the byte shfit across an entire 128-bit
1658// lane.
1659// Mostly copied from X86.
1660static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
1661 unsigned ScalarSizeInBits, ArrayRef<int> Mask,
1662 int MaskOffset, const APInt &Zeroable) {
1663 int Size = Mask.size();
1664 unsigned SizeInBits = Size * ScalarSizeInBits;
1665
1666 auto CheckZeros = [&](int Shift, int Scale, bool Left) {
1667 for (int i = 0; i < Size; i += Scale)
1668 for (int j = 0; j < Shift; ++j)
1669 if (!Zeroable[i + j + (Left ? 0 : (Scale - Shift))])
1670 return false;
1671
1672 return true;
1673 };
1674
1675 auto isSequentialOrUndefInRange = [&](unsigned Pos, unsigned Size, int Low,
1676 int Step = 1) {
1677 for (unsigned i = Pos, e = Pos + Size; i != e; ++i, Low += Step)
1678 if (!(Mask[i] == -1 || Mask[i] == Low))
1679 return false;
1680 return true;
1681 };
1682
1683 auto MatchShift = [&](int Shift, int Scale, bool Left) {
1684 for (int i = 0; i != Size; i += Scale) {
1685 unsigned Pos = Left ? i + Shift : i;
1686 unsigned Low = Left ? i : i + Shift;
1687 unsigned Len = Scale - Shift;
1688 if (!isSequentialOrUndefInRange(Pos, Len, Low + MaskOffset))
1689 return -1;
1690 }
1691
1692 int ShiftEltBits = ScalarSizeInBits * Scale;
1693 bool ByteShift = ShiftEltBits > 64;
1694 Opcode = Left ? (ByteShift ? LoongArchISD::VBSLL : LoongArchISD::VSLLI)
1695 : (ByteShift ? LoongArchISD::VBSRL : LoongArchISD::VSRLI);
1696 int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
1697
1698 // Normalize the scale for byte shifts to still produce an i64 element
1699 // type.
1700 Scale = ByteShift ? Scale / 2 : Scale;
1701
1702 // We need to round trip through the appropriate type for the shift.
1703 MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
1704 ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
1705 : MVT::getVectorVT(ShiftSVT, Size / Scale);
1706 return (int)ShiftAmt;
1707 };
1708
1709 unsigned MaxWidth = 128;
1710 for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
1711 for (int Shift = 1; Shift != Scale; ++Shift)
1712 for (bool Left : {true, false})
1713 if (CheckZeros(Shift, Scale, Left)) {
1714 int ShiftAmt = MatchShift(Shift, Scale, Left);
1715 if (0 < ShiftAmt)
1716 return ShiftAmt;
1717 }
1718
1719 // no match
1720 return -1;
1721}
1722
1723/// Lower VECTOR_SHUFFLE as shift (if possible).
1724///
1725/// For example:
1726/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1727/// <4 x i32> <i32 4, i32 0, i32 1, i32 2>
1728/// is lowered to:
1729/// (VBSLL_V $v0, $v0, 4)
1730///
1731/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1732/// <4 x i32> <i32 4, i32 0, i32 4, i32 2>
1733/// is lowered to:
1734/// (VSLLI_D $v0, $v0, 32)
1736 MVT VT, SDValue V1, SDValue V2,
1737 SelectionDAG &DAG,
1738 const LoongArchSubtarget &Subtarget,
1739 const APInt &Zeroable) {
1740 int Size = Mask.size();
1741 assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
1742
1743 MVT ShiftVT;
1744 SDValue V = V1;
1745 unsigned Opcode;
1746
1747 // Try to match shuffle against V1 shift.
1748 int ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1749 Mask, 0, Zeroable);
1750
1751 // If V1 failed, try to match shuffle against V2 shift.
1752 if (ShiftAmt < 0) {
1753 ShiftAmt = matchShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
1754 Mask, Size, Zeroable);
1755 V = V2;
1756 }
1757
1758 if (ShiftAmt < 0)
1759 return SDValue();
1760
1761 assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
1762 "Illegal integer vector type");
1763 V = DAG.getBitcast(ShiftVT, V);
1764 V = DAG.getNode(Opcode, DL, ShiftVT, V,
1765 DAG.getConstant(ShiftAmt, DL, Subtarget.getGRLenVT()));
1766 return DAG.getBitcast(VT, V);
1767}
1768
1769/// Determine whether a range fits a regular pattern of values.
1770/// This function accounts for the possibility of jumping over the End iterator.
1771template <typename ValType>
1772static bool
1774 unsigned CheckStride,
1776 ValType ExpectedIndex, unsigned ExpectedIndexStride) {
1777 auto &I = Begin;
1778
1779 while (I != End) {
1780 if (*I != -1 && *I != ExpectedIndex)
1781 return false;
1782 ExpectedIndex += ExpectedIndexStride;
1783
1784 // Incrementing past End is undefined behaviour so we must increment one
1785 // step at a time and check for End at each step.
1786 for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
1787 ; // Empty loop body.
1788 }
1789 return true;
1790}
1791
1792/// Compute whether each element of a shuffle is zeroable.
1793///
1794/// A "zeroable" vector shuffle element is one which can be lowered to zero.
1796 SDValue V2, APInt &KnownUndef,
1797 APInt &KnownZero) {
1798 int Size = Mask.size();
1799 KnownUndef = KnownZero = APInt::getZero(Size);
1800
1802 V2 = peekThroughBitcasts(V2);
1803
1804 bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
1805 bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
1806
1807 int VectorSizeInBits = V1.getValueSizeInBits();
1808 int ScalarSizeInBits = VectorSizeInBits / Size;
1809 assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
1810 (void)ScalarSizeInBits;
1811
1812 for (int i = 0; i < Size; ++i) {
1813 int M = Mask[i];
1814 if (M < 0) {
1815 KnownUndef.setBit(i);
1816 continue;
1817 }
1818 if ((M >= 0 && M < Size && V1IsZero) || (M >= Size && V2IsZero)) {
1819 KnownZero.setBit(i);
1820 continue;
1821 }
1822 }
1823}
1824
1825/// Test whether a shuffle mask is equivalent within each sub-lane.
1826///
1827/// The specific repeated shuffle mask is populated in \p RepeatedMask, as it is
1828/// non-trivial to compute in the face of undef lanes. The representation is
1829/// suitable for use with existing 128-bit shuffles as entries from the second
1830/// vector have been remapped to [LaneSize, 2*LaneSize).
1831static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
1832 ArrayRef<int> Mask,
1833 SmallVectorImpl<int> &RepeatedMask) {
1834 auto LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
1835 RepeatedMask.assign(LaneSize, -1);
1836 int Size = Mask.size();
1837 for (int i = 0; i < Size; ++i) {
1838 assert(Mask[i] == -1 || Mask[i] >= 0);
1839 if (Mask[i] < 0)
1840 continue;
1841 if ((Mask[i] % Size) / LaneSize != i / LaneSize)
1842 // This entry crosses lanes, so there is no way to model this shuffle.
1843 return false;
1844
1845 // Ok, handle the in-lane shuffles by detecting if and when they repeat.
1846 // Adjust second vector indices to start at LaneSize instead of Size.
1847 int LocalM =
1848 Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
1849 if (RepeatedMask[i % LaneSize] < 0)
1850 // This is the first non-undef entry in this slot of a 128-bit lane.
1851 RepeatedMask[i % LaneSize] = LocalM;
1852 else if (RepeatedMask[i % LaneSize] != LocalM)
1853 // Found a mismatch with the repeated mask.
1854 return false;
1855 }
1856 return true;
1857}
1858
1859/// Attempts to match vector shuffle as byte rotation.
1861 ArrayRef<int> Mask) {
1862
1863 SDValue Lo, Hi;
1864 SmallVector<int, 16> RepeatedMask;
1865
1866 if (!isRepeatedShuffleMask(128, VT, Mask, RepeatedMask))
1867 return -1;
1868
1869 int NumElts = RepeatedMask.size();
1870 int Rotation = 0;
1871 int Scale = 16 / NumElts;
1872
1873 for (int i = 0; i < NumElts; ++i) {
1874 int M = RepeatedMask[i];
1875 assert((M == -1 || (0 <= M && M < (2 * NumElts))) &&
1876 "Unexpected mask index.");
1877 if (M < 0)
1878 continue;
1879
1880 // Determine where a rotated vector would have started.
1881 int StartIdx = i - (M % NumElts);
1882 if (StartIdx == 0)
1883 return -1;
1884
1885 // If we found the tail of a vector the rotation must be the missing
1886 // front. If we found the head of a vector, it must be how much of the
1887 // head.
1888 int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
1889
1890 if (Rotation == 0)
1891 Rotation = CandidateRotation;
1892 else if (Rotation != CandidateRotation)
1893 return -1;
1894
1895 // Compute which value this mask is pointing at.
1896 SDValue MaskV = M < NumElts ? V1 : V2;
1897
1898 // Compute which of the two target values this index should be assigned
1899 // to. This reflects whether the high elements are remaining or the low
1900 // elements are remaining.
1901 SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
1902
1903 // Either set up this value if we've not encountered it before, or check
1904 // that it remains consistent.
1905 if (!TargetV)
1906 TargetV = MaskV;
1907 else if (TargetV != MaskV)
1908 return -1;
1909 }
1910
1911 // Check that we successfully analyzed the mask, and normalize the results.
1912 assert(Rotation != 0 && "Failed to locate a viable rotation!");
1913 assert((Lo || Hi) && "Failed to find a rotated input vector!");
1914 if (!Lo)
1915 Lo = Hi;
1916 else if (!Hi)
1917 Hi = Lo;
1918
1919 V1 = Lo;
1920 V2 = Hi;
1921
1922 return Rotation * Scale;
1923}
1924
1925/// Lower VECTOR_SHUFFLE as byte rotate (if possible).
1926///
1927/// For example:
1928/// %shuffle = shufflevector <2 x i64> %a, <2 x i64> %b,
1929/// <2 x i32> <i32 3, i32 0>
1930/// is lowered to:
1931/// (VBSRL_V $v1, $v1, 8)
1932/// (VBSLL_V $v0, $v0, 8)
1933/// (VOR_V $v0, $V0, $v1)
1934static SDValue
1936 SDValue V1, SDValue V2, SelectionDAG &DAG,
1937 const LoongArchSubtarget &Subtarget) {
1938
1939 SDValue Lo = V1, Hi = V2;
1940 int ByteRotation = matchShuffleAsByteRotate(VT, Lo, Hi, Mask);
1941 if (ByteRotation <= 0)
1942 return SDValue();
1943
1944 MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
1945 Lo = DAG.getBitcast(ByteVT, Lo);
1946 Hi = DAG.getBitcast(ByteVT, Hi);
1947
1948 int LoByteShift = 16 - ByteRotation;
1949 int HiByteShift = ByteRotation;
1950 MVT GRLenVT = Subtarget.getGRLenVT();
1951
1952 SDValue LoShift = DAG.getNode(LoongArchISD::VBSLL, DL, ByteVT, Lo,
1953 DAG.getConstant(LoByteShift, DL, GRLenVT));
1954 SDValue HiShift = DAG.getNode(LoongArchISD::VBSRL, DL, ByteVT, Hi,
1955 DAG.getConstant(HiByteShift, DL, GRLenVT));
1956 return DAG.getBitcast(VT, DAG.getNode(ISD::OR, DL, ByteVT, LoShift, HiShift));
1957}
1958
1959/// Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
1960///
1961/// For example:
1962/// %2 = shufflevector <4 x i32> %0, <4 x i32> zeroinitializer,
1963/// <4 x i32> <i32 0, i32 4, i32 1, i32 4>
1964/// %3 = bitcast <4 x i32> %2 to <2 x i64>
1965/// is lowered to:
1966/// (VREPLI $v1, 0)
1967/// (VILVL $v0, $v1, $v0)
1969 ArrayRef<int> Mask, MVT VT,
1970 SDValue V1, SDValue V2,
1971 SelectionDAG &DAG,
1972 const APInt &Zeroable) {
1973 int Bits = VT.getSizeInBits();
1974 int EltBits = VT.getScalarSizeInBits();
1975 int NumElements = VT.getVectorNumElements();
1976
1977 if (Zeroable.isAllOnes())
1978 return DAG.getConstant(0, DL, VT);
1979
1980 // Define a helper function to check a particular ext-scale and lower to it if
1981 // valid.
1982 auto Lower = [&](int Scale) -> SDValue {
1983 SDValue InputV;
1984 bool AnyExt = true;
1985 int Offset = 0;
1986 for (int i = 0; i < NumElements; i++) {
1987 int M = Mask[i];
1988 if (M < 0)
1989 continue;
1990 if (i % Scale != 0) {
1991 // Each of the extended elements need to be zeroable.
1992 if (!Zeroable[i])
1993 return SDValue();
1994
1995 AnyExt = false;
1996 continue;
1997 }
1998
1999 // Each of the base elements needs to be consecutive indices into the
2000 // same input vector.
2001 SDValue V = M < NumElements ? V1 : V2;
2002 M = M % NumElements;
2003 if (!InputV) {
2004 InputV = V;
2005 Offset = M - (i / Scale);
2006
2007 // These offset can't be handled
2008 if (Offset % (NumElements / Scale))
2009 return SDValue();
2010 } else if (InputV != V)
2011 return SDValue();
2012
2013 if (M != (Offset + (i / Scale)))
2014 return SDValue(); // Non-consecutive strided elements.
2015 }
2016
2017 // If we fail to find an input, we have a zero-shuffle which should always
2018 // have already been handled.
2019 if (!InputV)
2020 return SDValue();
2021
2022 do {
2023 unsigned VilVLoHi = LoongArchISD::VILVL;
2024 if (Offset >= (NumElements / 2)) {
2025 VilVLoHi = LoongArchISD::VILVH;
2026 Offset -= (NumElements / 2);
2027 }
2028
2029 MVT InputVT = MVT::getVectorVT(MVT::getIntegerVT(EltBits), NumElements);
2030 SDValue Ext =
2031 AnyExt ? DAG.getFreeze(InputV) : DAG.getConstant(0, DL, InputVT);
2032 InputV = DAG.getBitcast(InputVT, InputV);
2033 Ext = DAG.getBitcast(InputVT, Ext);
2034 InputV = DAG.getNode(VilVLoHi, DL, InputVT, Ext, InputV);
2035 Scale /= 2;
2036 EltBits *= 2;
2037 NumElements /= 2;
2038 } while (Scale > 1);
2039 return DAG.getBitcast(VT, InputV);
2040 };
2041
2042 // Each iteration, try extending the elements half as much, but into twice as
2043 // many elements.
2044 for (int NumExtElements = Bits / 64; NumExtElements < NumElements;
2045 NumExtElements *= 2) {
2046 if (SDValue V = Lower(NumElements / NumExtElements))
2047 return V;
2048 }
2049 return SDValue();
2050}
2051
2052/// Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
2053///
2054/// VREPLVEI performs vector broadcast based on an element specified by an
2055/// integer immediate, with its mask being similar to:
2056/// <x, x, x, ...>
2057/// where x is any valid index.
2058///
2059/// When undef's appear in the mask they are treated as if they were whatever
2060/// value is necessary in order to fit the above form.
2061static SDValue
2063 SDValue V1, SelectionDAG &DAG,
2064 const LoongArchSubtarget &Subtarget) {
2065 int SplatIndex = -1;
2066 for (const auto &M : Mask) {
2067 if (M != -1) {
2068 SplatIndex = M;
2069 break;
2070 }
2071 }
2072
2073 if (SplatIndex == -1)
2074 return DAG.getUNDEF(VT);
2075
2076 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2077 if (fitsRegularPattern<int>(Mask.begin(), 1, Mask.end(), SplatIndex, 0)) {
2078 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2079 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2080 }
2081
2082 return SDValue();
2083}
2084
2085/// Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
2086///
2087/// VSHUF4I splits the vector into blocks of four elements, then shuffles these
2088/// elements according to a <4 x i2> constant (encoded as an integer immediate).
2089///
2090/// It is therefore possible to lower into VSHUF4I when the mask takes the form:
2091/// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
2092/// When undef's appear they are treated as if they were whatever value is
2093/// necessary in order to fit the above forms.
2094///
2095/// For example:
2096/// %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
2097/// <8 x i32> <i32 3, i32 2, i32 1, i32 0,
2098/// i32 7, i32 6, i32 5, i32 4>
2099/// is lowered to:
2100/// (VSHUF4I_H $v0, $v1, 27)
2101/// where the 27 comes from:
2102/// 3 + (2 << 2) + (1 << 4) + (0 << 6)
2103static SDValue
2105 SDValue V1, SDValue V2, SelectionDAG &DAG,
2106 const LoongArchSubtarget &Subtarget) {
2107
2108 unsigned SubVecSize = 4;
2109 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2110 SubVecSize = 2;
2111
2112 int SubMask[4] = {-1, -1, -1, -1};
2113 for (unsigned i = 0; i < SubVecSize; ++i) {
2114 for (unsigned j = i; j < Mask.size(); j += SubVecSize) {
2115 int M = Mask[j];
2116
2117 // Convert from vector index to 4-element subvector index
2118 // If an index refers to an element outside of the subvector then give up
2119 if (M != -1) {
2120 M -= 4 * (j / SubVecSize);
2121 if (M < 0 || M >= 4)
2122 return SDValue();
2123 }
2124
2125 // If the mask has an undef, replace it with the current index.
2126 // Note that it might still be undef if the current index is also undef
2127 if (SubMask[i] == -1)
2128 SubMask[i] = M;
2129 // Check that non-undef values are the same as in the mask. If they
2130 // aren't then give up
2131 else if (M != -1 && M != SubMask[i])
2132 return SDValue();
2133 }
2134 }
2135
2136 // Calculate the immediate. Replace any remaining undefs with zero
2137 int Imm = 0;
2138 for (int i = SubVecSize - 1; i >= 0; --i) {
2139 int M = SubMask[i];
2140
2141 if (M == -1)
2142 M = 0;
2143
2144 Imm <<= 2;
2145 Imm |= M & 0x3;
2146 }
2147
2148 MVT GRLenVT = Subtarget.getGRLenVT();
2149
2150 // Return vshuf4i.d
2151 if (VT == MVT::v2f64 || VT == MVT::v2i64)
2152 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2153 DAG.getConstant(Imm, DL, GRLenVT));
2154
2155 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT, V1,
2156 DAG.getConstant(Imm, DL, GRLenVT));
2157}
2158
2159/// Lower VECTOR_SHUFFLE whose result is the reversed source vector.
2160///
2161/// It is possible to do optimization for VECTOR_SHUFFLE performing vector
2162/// reverse whose mask likes:
2163/// <7, 6, 5, 4, 3, 2, 1, 0>
2164///
2165/// When undef's appear in the mask they are treated as if they were whatever
2166/// value is necessary in order to fit the above forms.
2167static SDValue
2169 SDValue V1, SelectionDAG &DAG,
2170 const LoongArchSubtarget &Subtarget) {
2171 // Only vectors with i8/i16 elements which cannot match other patterns
2172 // directly needs to do this.
2173 if (VT != MVT::v16i8 && VT != MVT::v8i16 && VT != MVT::v32i8 &&
2174 VT != MVT::v16i16)
2175 return SDValue();
2176
2177 if (!ShuffleVectorInst::isReverseMask(Mask, Mask.size()))
2178 return SDValue();
2179
2180 int WidenNumElts = VT.getVectorNumElements() / 4;
2181 SmallVector<int, 16> WidenMask(WidenNumElts, -1);
2182 for (int i = 0; i < WidenNumElts; ++i)
2183 WidenMask[i] = WidenNumElts - 1 - i;
2184
2185 MVT WidenVT = MVT::getVectorVT(
2186 VT.getVectorElementType() == MVT::i8 ? MVT::i32 : MVT::i64, WidenNumElts);
2187 SDValue NewV1 = DAG.getBitcast(WidenVT, V1);
2188 SDValue WidenRev = DAG.getVectorShuffle(WidenVT, DL, NewV1,
2189 DAG.getUNDEF(WidenVT), WidenMask);
2190
2191 return DAG.getNode(LoongArchISD::VSHUF4I, DL, VT,
2192 DAG.getBitcast(VT, WidenRev),
2193 DAG.getConstant(27, DL, Subtarget.getGRLenVT()));
2194}
2195
2196/// Lower VECTOR_SHUFFLE into VPACKEV (if possible).
2197///
2198/// VPACKEV interleaves the even elements from each vector.
2199///
2200/// It is possible to lower into VPACKEV when the mask consists of two of the
2201/// following forms interleaved:
2202/// <0, 2, 4, ...>
2203/// <n, n+2, n+4, ...>
2204/// where n is the number of elements in the vector.
2205/// For example:
2206/// <0, 0, 2, 2, 4, 4, ...>
2207/// <0, n, 2, n+2, 4, n+4, ...>
2208///
2209/// When undef's appear in the mask they are treated as if they were whatever
2210/// value is necessary in order to fit the above forms.
2212 MVT VT, SDValue V1, SDValue V2,
2213 SelectionDAG &DAG) {
2214
2215 const auto &Begin = Mask.begin();
2216 const auto &End = Mask.end();
2217 SDValue OriV1 = V1, OriV2 = V2;
2218
2219 if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
2220 V1 = OriV1;
2221 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 2))
2222 V1 = OriV2;
2223 else
2224 return SDValue();
2225
2226 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
2227 V2 = OriV1;
2228 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 2))
2229 V2 = OriV2;
2230 else
2231 return SDValue();
2232
2233 return DAG.getNode(LoongArchISD::VPACKEV, DL, VT, V2, V1);
2234}
2235
2236/// Lower VECTOR_SHUFFLE into VPACKOD (if possible).
2237///
2238/// VPACKOD interleaves the odd elements from each vector.
2239///
2240/// It is possible to lower into VPACKOD when the mask consists of two of the
2241/// following forms interleaved:
2242/// <1, 3, 5, ...>
2243/// <n+1, n+3, n+5, ...>
2244/// where n is the number of elements in the vector.
2245/// For example:
2246/// <1, 1, 3, 3, 5, 5, ...>
2247/// <1, n+1, 3, n+3, 5, n+5, ...>
2248///
2249/// When undef's appear in the mask they are treated as if they were whatever
2250/// value is necessary in order to fit the above forms.
2252 MVT VT, SDValue V1, SDValue V2,
2253 SelectionDAG &DAG) {
2254
2255 const auto &Begin = Mask.begin();
2256 const auto &End = Mask.end();
2257 SDValue OriV1 = V1, OriV2 = V2;
2258
2259 if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
2260 V1 = OriV1;
2261 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + 1, 2))
2262 V1 = OriV2;
2263 else
2264 return SDValue();
2265
2266 if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
2267 V2 = OriV1;
2268 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + 1, 2))
2269 V2 = OriV2;
2270 else
2271 return SDValue();
2272
2273 return DAG.getNode(LoongArchISD::VPACKOD, DL, VT, V2, V1);
2274}
2275
2276/// Lower VECTOR_SHUFFLE into VILVH (if possible).
2277///
2278/// VILVH interleaves consecutive elements from the left (highest-indexed) half
2279/// of each vector.
2280///
2281/// It is possible to lower into VILVH when the mask consists of two of the
2282/// following forms interleaved:
2283/// <x, x+1, x+2, ...>
2284/// <n+x, n+x+1, n+x+2, ...>
2285/// where n is the number of elements in the vector and x is half n.
2286/// For example:
2287/// <x, x, x+1, x+1, x+2, x+2, ...>
2288/// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
2289///
2290/// When undef's appear in the mask they are treated as if they were whatever
2291/// value is necessary in order to fit the above forms.
2293 MVT VT, SDValue V1, SDValue V2,
2294 SelectionDAG &DAG) {
2295
2296 const auto &Begin = Mask.begin();
2297 const auto &End = Mask.end();
2298 unsigned HalfSize = Mask.size() / 2;
2299 SDValue OriV1 = V1, OriV2 = V2;
2300
2301 if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
2302 V1 = OriV1;
2303 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size() + HalfSize, 1))
2304 V1 = OriV2;
2305 else
2306 return SDValue();
2307
2308 if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
2309 V2 = OriV1;
2310 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size() + HalfSize,
2311 1))
2312 V2 = OriV2;
2313 else
2314 return SDValue();
2315
2316 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2317}
2318
2319/// Lower VECTOR_SHUFFLE into VILVL (if possible).
2320///
2321/// VILVL interleaves consecutive elements from the right (lowest-indexed) half
2322/// of each vector.
2323///
2324/// It is possible to lower into VILVL when the mask consists of two of the
2325/// following forms interleaved:
2326/// <0, 1, 2, ...>
2327/// <n, n+1, n+2, ...>
2328/// where n is the number of elements in the vector.
2329/// For example:
2330/// <0, 0, 1, 1, 2, 2, ...>
2331/// <0, n, 1, n+1, 2, n+2, ...>
2332///
2333/// When undef's appear in the mask they are treated as if they were whatever
2334/// value is necessary in order to fit the above forms.
2336 MVT VT, SDValue V1, SDValue V2,
2337 SelectionDAG &DAG) {
2338
2339 const auto &Begin = Mask.begin();
2340 const auto &End = Mask.end();
2341 SDValue OriV1 = V1, OriV2 = V2;
2342
2343 if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
2344 V1 = OriV1;
2345 else if (fitsRegularPattern<int>(Begin, 2, End, Mask.size(), 1))
2346 V1 = OriV2;
2347 else
2348 return SDValue();
2349
2350 if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
2351 V2 = OriV1;
2352 else if (fitsRegularPattern<int>(Begin + 1, 2, End, Mask.size(), 1))
2353 V2 = OriV2;
2354 else
2355 return SDValue();
2356
2357 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2358}
2359
2360/// Lower VECTOR_SHUFFLE into VPICKEV (if possible).
2361///
2362/// VPICKEV copies the even elements of each vector into the result vector.
2363///
2364/// It is possible to lower into VPICKEV when the mask consists of two of the
2365/// following forms concatenated:
2366/// <0, 2, 4, ...>
2367/// <n, n+2, n+4, ...>
2368/// where n is the number of elements in the vector.
2369/// For example:
2370/// <0, 2, 4, ..., 0, 2, 4, ...>
2371/// <0, 2, 4, ..., n, n+2, n+4, ...>
2372///
2373/// When undef's appear in the mask they are treated as if they were whatever
2374/// value is necessary in order to fit the above forms.
2376 MVT VT, SDValue V1, SDValue V2,
2377 SelectionDAG &DAG) {
2378
2379 const auto &Begin = Mask.begin();
2380 const auto &Mid = Mask.begin() + Mask.size() / 2;
2381 const auto &End = Mask.end();
2382 SDValue OriV1 = V1, OriV2 = V2;
2383
2384 if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
2385 V1 = OriV1;
2386 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size(), 2))
2387 V1 = OriV2;
2388 else
2389 return SDValue();
2390
2391 if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
2392 V2 = OriV1;
2393 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size(), 2))
2394 V2 = OriV2;
2395
2396 else
2397 return SDValue();
2398
2399 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2400}
2401
2402/// Lower VECTOR_SHUFFLE into VPICKOD (if possible).
2403///
2404/// VPICKOD copies the odd elements of each vector into the result vector.
2405///
2406/// It is possible to lower into VPICKOD when the mask consists of two of the
2407/// following forms concatenated:
2408/// <1, 3, 5, ...>
2409/// <n+1, n+3, n+5, ...>
2410/// where n is the number of elements in the vector.
2411/// For example:
2412/// <1, 3, 5, ..., 1, 3, 5, ...>
2413/// <1, 3, 5, ..., n+1, n+3, n+5, ...>
2414///
2415/// When undef's appear in the mask they are treated as if they were whatever
2416/// value is necessary in order to fit the above forms.
2418 MVT VT, SDValue V1, SDValue V2,
2419 SelectionDAG &DAG) {
2420
2421 const auto &Begin = Mask.begin();
2422 const auto &Mid = Mask.begin() + Mask.size() / 2;
2423 const auto &End = Mask.end();
2424 SDValue OriV1 = V1, OriV2 = V2;
2425
2426 if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
2427 V1 = OriV1;
2428 else if (fitsRegularPattern<int>(Begin, 1, Mid, Mask.size() + 1, 2))
2429 V1 = OriV2;
2430 else
2431 return SDValue();
2432
2433 if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
2434 V2 = OriV1;
2435 else if (fitsRegularPattern<int>(Mid, 1, End, Mask.size() + 1, 2))
2436 V2 = OriV2;
2437 else
2438 return SDValue();
2439
2440 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
2441}
2442
2443/// Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
2444///
2445/// VEXTRINS copies one element of a vector into any place of the result
2446/// vector and makes no change to the rest elements of the result vector.
2447///
2448/// It is possible to lower into VEXTRINS when the mask takes the form:
2449/// <0, 1, 2, ..., n+i, ..., n-1> or <n, n+1, n+2, ..., i, ..., 2n-1> or
2450/// <0, 1, 2, ..., i, ..., n-1> or <n, n+1, n+2, ..., n+i, ..., 2n-1>
2451/// where n is the number of elements in the vector and i is in [0, n).
2452/// For example:
2453/// <0, 1, 2, 3, 4, 5, 6, 8> , <2, 9, 10, 11, 12, 13, 14, 15> ,
2454/// <0, 1, 2, 6, 4, 5, 6, 7> , <8, 9, 10, 11, 12, 9, 14, 15>
2455///
2456/// When undef's appear in the mask they are treated as if they were whatever
2457/// value is necessary in order to fit the above forms.
2458static SDValue
2460 SDValue V1, SDValue V2, SelectionDAG &DAG,
2461 const LoongArchSubtarget &Subtarget) {
2462 unsigned NumElts = VT.getVectorNumElements();
2463 MVT EltVT = VT.getVectorElementType();
2464 MVT GRLenVT = Subtarget.getGRLenVT();
2465
2466 if (Mask.size() != NumElts)
2467 return SDValue();
2468
2469 auto tryLowerToExtrAndIns = [&](unsigned Base) -> SDValue {
2470 int DiffCount = 0;
2471 int DiffPos = -1;
2472 for (unsigned i = 0; i < NumElts; ++i) {
2473 if (Mask[i] == -1)
2474 continue;
2475 if (Mask[i] != int(Base + i)) {
2476 ++DiffCount;
2477 DiffPos = int(i);
2478 if (DiffCount > 1)
2479 return SDValue();
2480 }
2481 }
2482
2483 // Need exactly one differing element to lower into VEXTRINS.
2484 if (DiffCount != 1)
2485 return SDValue();
2486
2487 // DiffMask must be in [0, 2N).
2488 int DiffMask = Mask[DiffPos];
2489 if (DiffMask < 0 || DiffMask >= int(2 * NumElts))
2490 return SDValue();
2491
2492 // Determine source vector and source index.
2493 SDValue SrcVec;
2494 unsigned SrcIdx;
2495 if (unsigned(DiffMask) < NumElts) {
2496 SrcVec = V1;
2497 SrcIdx = unsigned(DiffMask);
2498 } else {
2499 SrcVec = V2;
2500 SrcIdx = unsigned(DiffMask) - NumElts;
2501 }
2502
2503 // Replace with EXTRACT_VECTOR_ELT + INSERT_VECTOR_ELT, it will match the
2504 // patterns of VEXTRINS in tablegen.
2505 SDValue Extracted = DAG.getNode(
2506 ISD::EXTRACT_VECTOR_ELT, DL, EltVT.isFloatingPoint() ? EltVT : GRLenVT,
2507 SrcVec, DAG.getConstant(SrcIdx, DL, GRLenVT));
2508 SDValue Result =
2509 DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, (Base == 0) ? V1 : V2,
2510 Extracted, DAG.getConstant(DiffPos, DL, GRLenVT));
2511
2512 return Result;
2513 };
2514
2515 // Try [0, n-1) insertion then [n, 2n-1) insertion.
2516 if (SDValue Result = tryLowerToExtrAndIns(0))
2517 return Result;
2518 return tryLowerToExtrAndIns(NumElts);
2519}
2520
2521// Check the Mask and then build SrcVec and MaskImm infos which will
2522// be used to build LoongArchISD nodes for VPERMI_W or XVPERMI_W.
2523// On success, return true. Otherwise, return false.
2526 unsigned &MaskImm) {
2527 unsigned MaskSize = Mask.size();
2528
2529 auto isValid = [&](int M, int Off) {
2530 return (M == -1) || (M >= Off && M < Off + 4);
2531 };
2532
2533 auto buildImm = [&](int MLo, int MHi, unsigned Off, unsigned I) {
2534 auto immPart = [&](int M, unsigned Off) {
2535 return (M == -1 ? 0 : (M - Off)) & 0x3;
2536 };
2537 MaskImm |= immPart(MLo, Off) << (I * 2);
2538 MaskImm |= immPart(MHi, Off) << ((I + 1) * 2);
2539 };
2540
2541 for (unsigned i = 0; i < 4; i += 2) {
2542 int MLo = Mask[i];
2543 int MHi = Mask[i + 1];
2544
2545 if (MaskSize == 8) { // Only v8i32/v8f32 need this check.
2546 auto isValid2 = [&](int &M, int M2) {
2547 // If high half index is undef, it's always valid.
2548 if (M2 == -1)
2549 return true;
2550 if (M == -1) {
2551 // If low half index is undef, use index from high half,
2552 // remapped to low half.
2553 if ((M2 % MaskSize) < 4)
2554 return false;
2555 M = M2 - 4;
2556 return true;
2557 }
2558 // Index in low half must be same as index in high half.
2559 return M2 == M + 4;
2560 };
2561 if (!isValid2(MLo, Mask[i + 4]) || !isValid2(MHi, Mask[i + 5]))
2562 return false;
2563 }
2564
2565 if (isValid(MLo, 0) && isValid(MHi, 0)) {
2566 SrcVec.push_back(V1);
2567 buildImm(MLo, MHi, 0, i);
2568 } else if (isValid(MLo, MaskSize) && isValid(MHi, MaskSize)) {
2569 SrcVec.push_back(V2);
2570 buildImm(MLo, MHi, MaskSize, i);
2571 } else {
2572 return false;
2573 }
2574 }
2575
2576 return true;
2577}
2578
2579/// Lower VECTOR_SHUFFLE into VPERMI (if possible).
2580///
2581/// VPERMI selects two elements from each of the two vectors based on the
2582/// mask and places them in the corresponding positions of the result vector
2583/// in order. Only v4i32 and v4f32 types are allowed.
2584///
2585/// It is possible to lower into VPERMI when the mask consists of two of the
2586/// following forms concatenated:
2587/// <i, j, u, v>
2588/// <u, v, i, j>
2589/// where i,j are in [0,4) and u,v are in [4, 8).
2590/// For example:
2591/// <2, 3, 4, 5>
2592/// <5, 7, 0, 2>
2593///
2594/// When undef's appear in the mask they are treated as if they were whatever
2595/// value is necessary in order to fit the above forms.
2597 MVT VT, SDValue V1, SDValue V2,
2598 SelectionDAG &DAG,
2599 const LoongArchSubtarget &Subtarget) {
2600 if ((VT != MVT::v4i32 && VT != MVT::v4f32) ||
2601 Mask.size() != VT.getVectorNumElements())
2602 return SDValue();
2603
2605 unsigned MaskImm = 0;
2606 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2607 return SDValue();
2608
2609 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2610 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2611}
2612
2613/// Lower VECTOR_SHUFFLE into VSHUF.
2614///
2615/// This mostly consists of converting the shuffle mask into a BUILD_VECTOR and
2616/// adding it as an operand to the resulting VSHUF.
2618 MVT VT, SDValue V1, SDValue V2,
2619 SelectionDAG &DAG,
2620 const LoongArchSubtarget &Subtarget) {
2621
2623 for (auto M : Mask)
2624 Ops.push_back(DAG.getSignedConstant(M, DL, Subtarget.getGRLenVT()));
2625
2626 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
2627 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
2628
2629 // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
2630 // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
2631 // VSHF concatenates the vectors in a bitwise fashion:
2632 // <0b00, 0b01> + <0b10, 0b11> ->
2633 // 0b0100 + 0b1110 -> 0b01001110
2634 // <0b10, 0b11, 0b00, 0b01>
2635 // We must therefore swap the operands to get the correct result.
2636 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
2637}
2638
2639/// Dispatching routine to lower various 128-bit LoongArch vector shuffles.
2640///
2641/// This routine breaks down the specific type of 128-bit shuffle and
2642/// dispatches to the lowering routines accordingly.
2644 SDValue V1, SDValue V2, SelectionDAG &DAG,
2645 const LoongArchSubtarget &Subtarget) {
2646 assert((VT.SimpleTy == MVT::v16i8 || VT.SimpleTy == MVT::v8i16 ||
2647 VT.SimpleTy == MVT::v4i32 || VT.SimpleTy == MVT::v2i64 ||
2648 VT.SimpleTy == MVT::v4f32 || VT.SimpleTy == MVT::v2f64) &&
2649 "Vector type is unsupported for lsx!");
2650 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
2651 "Two operands have different types!");
2652 assert(VT.getVectorNumElements() == Mask.size() &&
2653 "Unexpected mask size for shuffle!");
2654 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
2655
2656 APInt KnownUndef, KnownZero;
2657 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
2658 APInt Zeroable = KnownUndef | KnownZero;
2659
2660 SDValue Result;
2661 // TODO: Add more comparison patterns.
2662 if (V2.isUndef()) {
2663 if ((Result =
2664 lowerVECTOR_SHUFFLE_VREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
2665 return Result;
2666 if ((Result =
2667 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2668 return Result;
2669 if ((Result =
2670 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
2671 return Result;
2672
2673 // TODO: This comment may be enabled in the future to better match the
2674 // pattern for instruction selection.
2675 /* V2 = V1; */
2676 }
2677
2678 // It is recommended not to change the pattern comparison order for better
2679 // performance.
2680 if ((Result = lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG)))
2681 return Result;
2682 if ((Result = lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG)))
2683 return Result;
2684 if ((Result = lowerVECTOR_SHUFFLE_VILVH(DL, Mask, VT, V1, V2, DAG)))
2685 return Result;
2686 if ((Result = lowerVECTOR_SHUFFLE_VILVL(DL, Mask, VT, V1, V2, DAG)))
2687 return Result;
2688 if ((Result = lowerVECTOR_SHUFFLE_VPICKEV(DL, Mask, VT, V1, V2, DAG)))
2689 return Result;
2690 if ((Result = lowerVECTOR_SHUFFLE_VPICKOD(DL, Mask, VT, V1, V2, DAG)))
2691 return Result;
2692 if ((VT.SimpleTy == MVT::v2i64 || VT.SimpleTy == MVT::v2f64) &&
2693 (Result =
2694 lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2695 return Result;
2696 if ((Result =
2697 lowerVECTOR_SHUFFLE_VEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2698 return Result;
2699 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
2700 Zeroable)))
2701 return Result;
2702 if ((Result =
2703 lowerVECTOR_SHUFFLE_VPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2704 return Result;
2705 if ((Result = lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(DL, Mask, VT, V1, V2, DAG,
2706 Zeroable)))
2707 return Result;
2708 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
2709 Subtarget)))
2710 return Result;
2711 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
2712 return NewShuffle;
2713 if ((Result =
2714 lowerVECTOR_SHUFFLE_VSHUF(DL, Mask, VT, V1, V2, DAG, Subtarget)))
2715 return Result;
2716 return SDValue();
2717}
2718
2719/// Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
2720///
2721/// It is a XVREPLVEI when the mask is:
2722/// <x, x, x, ..., x+n, x+n, x+n, ...>
2723/// where the number of x is equal to n and n is half the length of vector.
2724///
2725/// When undef's appear in the mask they are treated as if they were whatever
2726/// value is necessary in order to fit the above form.
2727static SDValue
2729 SDValue V1, SelectionDAG &DAG,
2730 const LoongArchSubtarget &Subtarget) {
2731 int SplatIndex = -1;
2732 for (const auto &M : Mask) {
2733 if (M != -1) {
2734 SplatIndex = M;
2735 break;
2736 }
2737 }
2738
2739 if (SplatIndex == -1)
2740 return DAG.getUNDEF(VT);
2741
2742 const auto &Begin = Mask.begin();
2743 const auto &End = Mask.end();
2744 int HalfSize = Mask.size() / 2;
2745
2746 if (SplatIndex >= HalfSize)
2747 return SDValue();
2748
2749 assert(SplatIndex < (int)Mask.size() && "Out of bounds mask index");
2750 if (fitsRegularPattern<int>(Begin, 1, End - HalfSize, SplatIndex, 0) &&
2751 fitsRegularPattern<int>(Begin + HalfSize, 1, End, SplatIndex + HalfSize,
2752 0)) {
2753 return DAG.getNode(LoongArchISD::VREPLVEI, DL, VT, V1,
2754 DAG.getConstant(SplatIndex, DL, Subtarget.getGRLenVT()));
2755 }
2756
2757 return SDValue();
2758}
2759
2760/// Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
2761static SDValue
2763 SDValue V1, SDValue V2, SelectionDAG &DAG,
2764 const LoongArchSubtarget &Subtarget) {
2765 // XVSHUF4I_D must be handled separately because it is different from other
2766 // types of [X]VSHUF4I instructions.
2767 if (Mask.size() == 4) {
2768 unsigned MaskImm = 0;
2769 for (int i = 1; i >= 0; --i) {
2770 int MLo = Mask[i];
2771 int MHi = Mask[i + 2];
2772 if (!(MLo == -1 || (MLo >= 0 && MLo <= 1) || (MLo >= 4 && MLo <= 5)) ||
2773 !(MHi == -1 || (MHi >= 2 && MHi <= 3) || (MHi >= 6 && MHi <= 7)))
2774 return SDValue();
2775 if (MHi != -1 && MLo != -1 && MHi != MLo + 2)
2776 return SDValue();
2777
2778 MaskImm <<= 2;
2779 if (MLo != -1)
2780 MaskImm |= ((MLo <= 1) ? MLo : (MLo - 2)) & 0x3;
2781 else if (MHi != -1)
2782 MaskImm |= ((MHi <= 3) ? (MHi - 2) : (MHi - 4)) & 0x3;
2783 }
2784
2785 return DAG.getNode(LoongArchISD::VSHUF4I_D, DL, VT, V1, V2,
2786 DAG.getConstant(MaskImm, DL, Subtarget.getGRLenVT()));
2787 }
2788
2789 return lowerVECTOR_SHUFFLE_VSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget);
2790}
2791
2792/// Lower VECTOR_SHUFFLE into XVPERMI (if possible).
2793static SDValue
2795 SDValue V1, SDValue V2, SelectionDAG &DAG,
2796 const LoongArchSubtarget &Subtarget) {
2797 MVT GRLenVT = Subtarget.getGRLenVT();
2798 unsigned MaskSize = Mask.size();
2799 if (MaskSize != VT.getVectorNumElements())
2800 return SDValue();
2801
2802 // Consider XVPERMI_W.
2803 if (VT == MVT::v8i32 || VT == MVT::v8f32) {
2805 unsigned MaskImm = 0;
2806 if (!buildVPERMIInfo(Mask, V1, V2, SrcVec, MaskImm))
2807 return SDValue();
2808
2809 return DAG.getNode(LoongArchISD::VPERMI, DL, VT, SrcVec[1], SrcVec[0],
2810 DAG.getConstant(MaskImm, DL, GRLenVT));
2811 }
2812
2813 // Consider XVPERMI_D.
2814 if (VT == MVT::v4i64 || VT == MVT::v4f64) {
2815 unsigned MaskImm = 0;
2816 for (unsigned i = 0; i < MaskSize; ++i) {
2817 if (Mask[i] == -1)
2818 continue;
2819 if (Mask[i] >= (int)MaskSize)
2820 return SDValue();
2821 MaskImm |= Mask[i] << (i * 2);
2822 }
2823
2824 return DAG.getNode(LoongArchISD::XVPERMI, DL, VT, V1,
2825 DAG.getConstant(MaskImm, DL, GRLenVT));
2826 }
2827
2828 return SDValue();
2829}
2830
2831/// Lower VECTOR_SHUFFLE into XVPERM (if possible).
2833 MVT VT, SDValue V1, SelectionDAG &DAG,
2834 const LoongArchSubtarget &Subtarget) {
2835 // LoongArch LASX only have XVPERM_W.
2836 if (Mask.size() != 8 || (VT != MVT::v8i32 && VT != MVT::v8f32))
2837 return SDValue();
2838
2839 unsigned NumElts = VT.getVectorNumElements();
2840 unsigned HalfSize = NumElts / 2;
2841 bool FrontLo = true, FrontHi = true;
2842 bool BackLo = true, BackHi = true;
2843
2844 auto inRange = [](int val, int low, int high) {
2845 return (val == -1) || (val >= low && val < high);
2846 };
2847
2848 for (unsigned i = 0; i < HalfSize; ++i) {
2849 int Fronti = Mask[i];
2850 int Backi = Mask[i + HalfSize];
2851
2852 FrontLo &= inRange(Fronti, 0, HalfSize);
2853 FrontHi &= inRange(Fronti, HalfSize, NumElts);
2854 BackLo &= inRange(Backi, 0, HalfSize);
2855 BackHi &= inRange(Backi, HalfSize, NumElts);
2856 }
2857
2858 // If both the lower and upper 128-bit parts access only one half of the
2859 // vector (either lower or upper), avoid using xvperm.w. The latency of
2860 // xvperm.w(3) is higher than using xvshuf(1) and xvori(1).
2861 if ((FrontLo || FrontHi) && (BackLo || BackHi))
2862 return SDValue();
2863
2865 MVT GRLenVT = Subtarget.getGRLenVT();
2866 for (unsigned i = 0; i < NumElts; ++i)
2867 Masks.push_back(Mask[i] == -1 ? DAG.getUNDEF(GRLenVT)
2868 : DAG.getConstant(Mask[i], DL, GRLenVT));
2869 SDValue MaskVec = DAG.getBuildVector(MVT::v8i32, DL, Masks);
2870
2871 return DAG.getNode(LoongArchISD::XVPERM, DL, VT, V1, MaskVec);
2872}
2873
2874/// Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
2876 MVT VT, SDValue V1, SDValue V2,
2877 SelectionDAG &DAG) {
2878 return lowerVECTOR_SHUFFLE_VPACKEV(DL, Mask, VT, V1, V2, DAG);
2879}
2880
2881/// Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
2883 MVT VT, SDValue V1, SDValue V2,
2884 SelectionDAG &DAG) {
2885 return lowerVECTOR_SHUFFLE_VPACKOD(DL, Mask, VT, V1, V2, DAG);
2886}
2887
2888/// Lower VECTOR_SHUFFLE into XVILVH (if possible).
2890 MVT VT, SDValue V1, SDValue V2,
2891 SelectionDAG &DAG) {
2892
2893 const auto &Begin = Mask.begin();
2894 const auto &End = Mask.end();
2895 unsigned HalfSize = Mask.size() / 2;
2896 unsigned LeftSize = HalfSize / 2;
2897 SDValue OriV1 = V1, OriV2 = V2;
2898
2899 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, HalfSize - LeftSize,
2900 1) &&
2901 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize + LeftSize, 1))
2902 V1 = OriV1;
2903 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize,
2904 Mask.size() + HalfSize - LeftSize, 1) &&
2905 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2906 Mask.size() + HalfSize + LeftSize, 1))
2907 V1 = OriV2;
2908 else
2909 return SDValue();
2910
2911 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, HalfSize - LeftSize,
2912 1) &&
2913 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize + LeftSize,
2914 1))
2915 V2 = OriV1;
2916 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize,
2917 Mask.size() + HalfSize - LeftSize, 1) &&
2918 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2919 Mask.size() + HalfSize + LeftSize, 1))
2920 V2 = OriV2;
2921 else
2922 return SDValue();
2923
2924 return DAG.getNode(LoongArchISD::VILVH, DL, VT, V2, V1);
2925}
2926
2927/// Lower VECTOR_SHUFFLE into XVILVL (if possible).
2929 MVT VT, SDValue V1, SDValue V2,
2930 SelectionDAG &DAG) {
2931
2932 const auto &Begin = Mask.begin();
2933 const auto &End = Mask.end();
2934 unsigned HalfSize = Mask.size() / 2;
2935 SDValue OriV1 = V1, OriV2 = V2;
2936
2937 if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, 0, 1) &&
2938 fitsRegularPattern<int>(Begin + HalfSize, 2, End, HalfSize, 1))
2939 V1 = OriV1;
2940 else if (fitsRegularPattern<int>(Begin, 2, End - HalfSize, Mask.size(), 1) &&
2941 fitsRegularPattern<int>(Begin + HalfSize, 2, End,
2942 Mask.size() + HalfSize, 1))
2943 V1 = OriV2;
2944 else
2945 return SDValue();
2946
2947 if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, 0, 1) &&
2948 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End, HalfSize, 1))
2949 V2 = OriV1;
2950 else if (fitsRegularPattern<int>(Begin + 1, 2, End - HalfSize, Mask.size(),
2951 1) &&
2952 fitsRegularPattern<int>(Begin + 1 + HalfSize, 2, End,
2953 Mask.size() + HalfSize, 1))
2954 V2 = OriV2;
2955 else
2956 return SDValue();
2957
2958 return DAG.getNode(LoongArchISD::VILVL, DL, VT, V2, V1);
2959}
2960
2961/// Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
2963 MVT VT, SDValue V1, SDValue V2,
2964 SelectionDAG &DAG) {
2965
2966 const auto &Begin = Mask.begin();
2967 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
2968 const auto &Mid = Mask.begin() + Mask.size() / 2;
2969 const auto &RightMid = Mask.end() - Mask.size() / 4;
2970 const auto &End = Mask.end();
2971 unsigned HalfSize = Mask.size() / 2;
2972 SDValue OriV1 = V1, OriV2 = V2;
2973
2974 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 0, 2) &&
2975 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize, 2))
2976 V1 = OriV1;
2977 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size(), 2) &&
2978 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize, 2))
2979 V1 = OriV2;
2980 else
2981 return SDValue();
2982
2983 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 0, 2) &&
2984 fitsRegularPattern<int>(RightMid, 1, End, HalfSize, 2))
2985 V2 = OriV1;
2986 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size(), 2) &&
2987 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize, 2))
2988 V2 = OriV2;
2989
2990 else
2991 return SDValue();
2992
2993 return DAG.getNode(LoongArchISD::VPICKEV, DL, VT, V2, V1);
2994}
2995
2996/// Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
2998 MVT VT, SDValue V1, SDValue V2,
2999 SelectionDAG &DAG) {
3000
3001 const auto &Begin = Mask.begin();
3002 const auto &LeftMid = Mask.begin() + Mask.size() / 4;
3003 const auto &Mid = Mask.begin() + Mask.size() / 2;
3004 const auto &RightMid = Mask.end() - Mask.size() / 4;
3005 const auto &End = Mask.end();
3006 unsigned HalfSize = Mask.size() / 2;
3007 SDValue OriV1 = V1, OriV2 = V2;
3008
3009 if (fitsRegularPattern<int>(Begin, 1, LeftMid, 1, 2) &&
3010 fitsRegularPattern<int>(Mid, 1, RightMid, HalfSize + 1, 2))
3011 V1 = OriV1;
3012 else if (fitsRegularPattern<int>(Begin, 1, LeftMid, Mask.size() + 1, 2) &&
3013 fitsRegularPattern<int>(Mid, 1, RightMid, Mask.size() + HalfSize + 1,
3014 2))
3015 V1 = OriV2;
3016 else
3017 return SDValue();
3018
3019 if (fitsRegularPattern<int>(LeftMid, 1, Mid, 1, 2) &&
3020 fitsRegularPattern<int>(RightMid, 1, End, HalfSize + 1, 2))
3021 V2 = OriV1;
3022 else if (fitsRegularPattern<int>(LeftMid, 1, Mid, Mask.size() + 1, 2) &&
3023 fitsRegularPattern<int>(RightMid, 1, End, Mask.size() + HalfSize + 1,
3024 2))
3025 V2 = OriV2;
3026 else
3027 return SDValue();
3028
3029 return DAG.getNode(LoongArchISD::VPICKOD, DL, VT, V2, V1);
3030}
3031
3032/// Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
3033static SDValue
3035 SDValue V1, SDValue V2, SelectionDAG &DAG,
3036 const LoongArchSubtarget &Subtarget) {
3037 int NumElts = VT.getVectorNumElements();
3038 int HalfSize = NumElts / 2;
3039 MVT EltVT = VT.getVectorElementType();
3040 MVT GRLenVT = Subtarget.getGRLenVT();
3041
3042 if ((int)Mask.size() != NumElts)
3043 return SDValue();
3044
3045 auto tryLowerToExtrAndIns = [&](int Base) -> SDValue {
3046 SmallVector<int> DiffPos;
3047 for (int i = 0; i < NumElts; ++i) {
3048 if (Mask[i] == -1)
3049 continue;
3050 if (Mask[i] != Base + i) {
3051 DiffPos.push_back(i);
3052 if (DiffPos.size() > 2)
3053 return SDValue();
3054 }
3055 }
3056
3057 // Need exactly two differing element to lower into XVEXTRINS.
3058 // If only one differing element, the element at a distance of
3059 // HalfSize from it must be undef.
3060 if (DiffPos.size() == 1) {
3061 if (DiffPos[0] < HalfSize && Mask[DiffPos[0] + HalfSize] == -1)
3062 DiffPos.push_back(DiffPos[0] + HalfSize);
3063 else if (DiffPos[0] >= HalfSize && Mask[DiffPos[0] - HalfSize] == -1)
3064 DiffPos.insert(DiffPos.begin(), DiffPos[0] - HalfSize);
3065 else
3066 return SDValue();
3067 }
3068 if (DiffPos.size() != 2 || DiffPos[1] != DiffPos[0] + HalfSize)
3069 return SDValue();
3070
3071 // DiffMask must be in its low or high part.
3072 int DiffMaskLo = Mask[DiffPos[0]];
3073 int DiffMaskHi = Mask[DiffPos[1]];
3074 DiffMaskLo = DiffMaskLo == -1 ? DiffMaskHi - HalfSize : DiffMaskLo;
3075 DiffMaskHi = DiffMaskHi == -1 ? DiffMaskLo + HalfSize : DiffMaskHi;
3076 if (!(DiffMaskLo >= 0 && DiffMaskLo < HalfSize) &&
3077 !(DiffMaskLo >= NumElts && DiffMaskLo < NumElts + HalfSize))
3078 return SDValue();
3079 if (!(DiffMaskHi >= HalfSize && DiffMaskHi < NumElts) &&
3080 !(DiffMaskHi >= NumElts + HalfSize && DiffMaskHi < 2 * NumElts))
3081 return SDValue();
3082 if (DiffMaskHi != DiffMaskLo + HalfSize)
3083 return SDValue();
3084
3085 // Determine source vector and source index.
3086 SDValue SrcVec = (DiffMaskLo < HalfSize) ? V1 : V2;
3087 int SrcIdxLo =
3088 (DiffMaskLo < HalfSize) ? DiffMaskLo : (DiffMaskLo - NumElts);
3089 bool IsEltFP = EltVT.isFloatingPoint();
3090
3091 // Replace with 2*EXTRACT_VECTOR_ELT + 2*INSERT_VECTOR_ELT, it will match
3092 // the patterns of XVEXTRINS in tablegen.
3093 SDValue BaseVec = (Base == 0) ? V1 : V2;
3094 SDValue EltLo =
3095 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3096 SrcVec, DAG.getConstant(SrcIdxLo, DL, GRLenVT));
3097 SDValue InsLo = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, BaseVec, EltLo,
3098 DAG.getConstant(DiffPos[0], DL, GRLenVT));
3099 SDValue EltHi =
3100 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IsEltFP ? EltVT : GRLenVT,
3101 SrcVec, DAG.getConstant(SrcIdxLo + HalfSize, DL, GRLenVT));
3102 SDValue Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, VT, InsLo, EltHi,
3103 DAG.getConstant(DiffPos[1], DL, GRLenVT));
3104
3105 return Result;
3106 };
3107
3108 // Try [0, n-1) insertion then [n, 2n-1) insertion.
3109 if (SDValue Result = tryLowerToExtrAndIns(0))
3110 return Result;
3111 return tryLowerToExtrAndIns(NumElts);
3112}
3113
3114/// Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
3115static SDValue
3117 SDValue V1, SDValue V2, SelectionDAG &DAG,
3118 const LoongArchSubtarget &Subtarget) {
3119 // LoongArch LASX only supports xvinsve0.{w/d}.
3120 if (VT != MVT::v8i32 && VT != MVT::v8f32 && VT != MVT::v4i64 &&
3121 VT != MVT::v4f64)
3122 return SDValue();
3123
3124 MVT GRLenVT = Subtarget.getGRLenVT();
3125 int MaskSize = Mask.size();
3126 assert(MaskSize == (int)VT.getVectorNumElements() && "Unexpected mask size");
3127
3128 // Check if exactly one element of the Mask is replaced by 'Replaced', while
3129 // all other elements are either 'Base + i' or undef (-1). On success, return
3130 // the index of the replaced element. Otherwise, just return -1.
3131 auto checkReplaceOne = [&](int Base, int Replaced) -> int {
3132 int Idx = -1;
3133 for (int i = 0; i < MaskSize; ++i) {
3134 if (Mask[i] == Base + i || Mask[i] == -1)
3135 continue;
3136 if (Mask[i] != Replaced)
3137 return -1;
3138 if (Idx == -1)
3139 Idx = i;
3140 else
3141 return -1;
3142 }
3143 return Idx;
3144 };
3145
3146 // Case 1: the lowest element of V2 replaces one element in V1.
3147 int Idx = checkReplaceOne(0, MaskSize);
3148 if (Idx != -1)
3149 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V1, V2,
3150 DAG.getConstant(Idx, DL, GRLenVT));
3151
3152 // Case 2: the lowest element of V1 replaces one element in V2.
3153 Idx = checkReplaceOne(MaskSize, 0);
3154 if (Idx != -1)
3155 return DAG.getNode(LoongArchISD::XVINSVE0, DL, VT, V2, V1,
3156 DAG.getConstant(Idx, DL, GRLenVT));
3157
3158 return SDValue();
3159}
3160
3161/// Lower VECTOR_SHUFFLE into XVSHUF (if possible).
3163 MVT VT, SDValue V1, SDValue V2,
3164 SelectionDAG &DAG) {
3165
3166 int MaskSize = Mask.size();
3167 int HalfSize = Mask.size() / 2;
3168 const auto &Begin = Mask.begin();
3169 const auto &Mid = Mask.begin() + HalfSize;
3170 const auto &End = Mask.end();
3171
3172 // VECTOR_SHUFFLE concatenates the vectors:
3173 // <0, 1, 2, 3, 4, 5, 6, 7> + <8, 9, 10, 11, 12, 13, 14, 15>
3174 // shuffling ->
3175 // <0, 1, 2, 3, 8, 9, 10, 11> <4, 5, 6, 7, 12, 13, 14, 15>
3176 //
3177 // XVSHUF concatenates the vectors:
3178 // <a0, a1, a2, a3, b0, b1, b2, b3> + <a4, a5, a6, a7, b4, b5, b6, b7>
3179 // shuffling ->
3180 // <a0, a1, a2, a3, a4, a5, a6, a7> + <b0, b1, b2, b3, b4, b5, b6, b7>
3181 SmallVector<SDValue, 8> MaskAlloc;
3182 for (auto it = Begin; it < Mid; it++) {
3183 if (*it < 0) // UNDEF
3184 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3185 else if ((*it >= 0 && *it < HalfSize) ||
3186 (*it >= MaskSize && *it < MaskSize + HalfSize)) {
3187 int M = *it < HalfSize ? *it : *it - HalfSize;
3188 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3189 } else
3190 return SDValue();
3191 }
3192 assert((int)MaskAlloc.size() == HalfSize && "xvshuf convert failed!");
3193
3194 for (auto it = Mid; it < End; it++) {
3195 if (*it < 0) // UNDEF
3196 MaskAlloc.push_back(DAG.getTargetConstant(0, DL, MVT::i64));
3197 else if ((*it >= HalfSize && *it < MaskSize) ||
3198 (*it >= MaskSize + HalfSize && *it < MaskSize * 2)) {
3199 int M = *it < MaskSize ? *it - HalfSize : *it - MaskSize;
3200 MaskAlloc.push_back(DAG.getTargetConstant(M, DL, MVT::i64));
3201 } else
3202 return SDValue();
3203 }
3204 assert((int)MaskAlloc.size() == MaskSize && "xvshuf convert failed!");
3205
3206 EVT MaskVecTy = VT.changeVectorElementTypeToInteger();
3207 SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, MaskAlloc);
3208 return DAG.getNode(LoongArchISD::VSHUF, DL, VT, MaskVec, V2, V1);
3209}
3210
3211/// Shuffle vectors by lane to generate more optimized instructions.
3212/// 256-bit shuffles are always considered as 2-lane 128-bit shuffles.
3213///
3214/// Therefore, except for the following four cases, other cases are regarded
3215/// as cross-lane shuffles, where optimization is relatively limited.
3216///
3217/// - Shuffle high, low lanes of two inputs vector
3218/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 3, 6>
3219/// - Shuffle low, high lanes of two inputs vector
3220/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 0, 5>
3221/// - Shuffle low, low lanes of two inputs vector
3222/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <3, 6, 3, 6>
3223/// - Shuffle high, high lanes of two inputs vector
3224/// <0, 1, 2, 3> + <4, 5, 6, 7> --- <0, 5, 0, 5>
3225///
3226/// The first case is the closest to LoongArch instructions and the other
3227/// cases need to be converted to it for processing.
3228///
3229/// This function will return true for the last three cases above and will
3230/// modify V1, V2 and Mask. Otherwise, return false for the first case and
3231/// cross-lane shuffle cases.
3233 const SDLoc &DL, MutableArrayRef<int> Mask, MVT VT, SDValue &V1,
3234 SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
3235
3236 enum HalfMaskType { HighLaneTy, LowLaneTy, None };
3237
3238 int MaskSize = Mask.size();
3239 int HalfSize = Mask.size() / 2;
3240 MVT GRLenVT = Subtarget.getGRLenVT();
3241
3242 HalfMaskType preMask = None, postMask = None;
3243
3244 if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3245 return M < 0 || (M >= 0 && M < HalfSize) ||
3246 (M >= MaskSize && M < MaskSize + HalfSize);
3247 }))
3248 preMask = HighLaneTy;
3249 else if (std::all_of(Mask.begin(), Mask.begin() + HalfSize, [&](int M) {
3250 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3251 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3252 }))
3253 preMask = LowLaneTy;
3254
3255 if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3256 return M < 0 || (M >= HalfSize && M < MaskSize) ||
3257 (M >= MaskSize + HalfSize && M < MaskSize * 2);
3258 }))
3259 postMask = LowLaneTy;
3260 else if (std::all_of(Mask.begin() + HalfSize, Mask.end(), [&](int M) {
3261 return M < 0 || (M >= 0 && M < HalfSize) ||
3262 (M >= MaskSize && M < MaskSize + HalfSize);
3263 }))
3264 postMask = HighLaneTy;
3265
3266 // The pre-half of mask is high lane type, and the post-half of mask
3267 // is low lane type, which is closest to the LoongArch instructions.
3268 //
3269 // Note: In the LoongArch architecture, the high lane of mask corresponds
3270 // to the lower 128-bit of vector register, and the low lane of mask
3271 // corresponds the higher 128-bit of vector register.
3272 if (preMask == HighLaneTy && postMask == LowLaneTy) {
3273 return false;
3274 }
3275 if (preMask == LowLaneTy && postMask == HighLaneTy) {
3276 V1 = DAG.getBitcast(MVT::v4i64, V1);
3277 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3278 DAG.getConstant(0b01001110, DL, GRLenVT));
3279 V1 = DAG.getBitcast(VT, V1);
3280
3281 if (!V2.isUndef()) {
3282 V2 = DAG.getBitcast(MVT::v4i64, V2);
3283 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3284 DAG.getConstant(0b01001110, DL, GRLenVT));
3285 V2 = DAG.getBitcast(VT, V2);
3286 }
3287
3288 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3289 *it = *it < 0 ? *it : *it - HalfSize;
3290 }
3291 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3292 *it = *it < 0 ? *it : *it + HalfSize;
3293 }
3294 } else if (preMask == LowLaneTy && postMask == LowLaneTy) {
3295 V1 = DAG.getBitcast(MVT::v4i64, V1);
3296 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3297 DAG.getConstant(0b11101110, DL, GRLenVT));
3298 V1 = DAG.getBitcast(VT, V1);
3299
3300 if (!V2.isUndef()) {
3301 V2 = DAG.getBitcast(MVT::v4i64, V2);
3302 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3303 DAG.getConstant(0b11101110, DL, GRLenVT));
3304 V2 = DAG.getBitcast(VT, V2);
3305 }
3306
3307 for (auto it = Mask.begin(); it < Mask.begin() + HalfSize; it++) {
3308 *it = *it < 0 ? *it : *it - HalfSize;
3309 }
3310 } else if (preMask == HighLaneTy && postMask == HighLaneTy) {
3311 V1 = DAG.getBitcast(MVT::v4i64, V1);
3312 V1 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V1,
3313 DAG.getConstant(0b01000100, DL, GRLenVT));
3314 V1 = DAG.getBitcast(VT, V1);
3315
3316 if (!V2.isUndef()) {
3317 V2 = DAG.getBitcast(MVT::v4i64, V2);
3318 V2 = DAG.getNode(LoongArchISD::XVPERMI, DL, MVT::v4i64, V2,
3319 DAG.getConstant(0b01000100, DL, GRLenVT));
3320 V2 = DAG.getBitcast(VT, V2);
3321 }
3322
3323 for (auto it = Mask.begin() + HalfSize; it < Mask.end(); it++) {
3324 *it = *it < 0 ? *it : *it + HalfSize;
3325 }
3326 } else { // cross-lane
3327 return false;
3328 }
3329
3330 return true;
3331}
3332
3333/// Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
3334/// Only for 256-bit vector.
3335///
3336/// For example:
3337/// %2 = shufflevector <4 x i64> %0, <4 x i64> posion,
3338/// <4 x i64> <i32 0, i32 3, i32 2, i32 0>
3339/// is lowerded to:
3340/// (XVPERMI $xr2, $xr0, 78)
3341/// (XVSHUF $xr1, $xr2, $xr0)
3342/// (XVORI $xr0, $xr1, 0)
3344 ArrayRef<int> Mask,
3345 MVT VT, SDValue V1,
3346 SDValue V2,
3347 SelectionDAG &DAG) {
3348 assert(VT.is256BitVector() && "Only for 256-bit vector shuffles!");
3349 int Size = Mask.size();
3350 int LaneSize = Size / 2;
3351
3352 bool LaneCrossing[2] = {false, false};
3353 for (int i = 0; i < Size; ++i)
3354 if (Mask[i] >= 0 && ((Mask[i] % Size) / LaneSize) != (i / LaneSize))
3355 LaneCrossing[(Mask[i] % Size) / LaneSize] = true;
3356
3357 // Ensure that all lanes ared involved.
3358 if (!LaneCrossing[0] && !LaneCrossing[1])
3359 return SDValue();
3360
3361 SmallVector<int> InLaneMask;
3362 InLaneMask.assign(Mask.begin(), Mask.end());
3363 for (int i = 0; i < Size; ++i) {
3364 int &M = InLaneMask[i];
3365 if (M < 0)
3366 continue;
3367 if (((M % Size) / LaneSize) != (i / LaneSize))
3368 M = (M % LaneSize) + ((i / LaneSize) * LaneSize) + Size;
3369 }
3370
3371 SDValue Flipped = DAG.getBitcast(MVT::v4i64, V1);
3372 Flipped = DAG.getVectorShuffle(MVT::v4i64, DL, Flipped,
3373 DAG.getUNDEF(MVT::v4i64), {2, 3, 0, 1});
3374 Flipped = DAG.getBitcast(VT, Flipped);
3375 return DAG.getVectorShuffle(VT, DL, V1, Flipped, InLaneMask);
3376}
3377
3378/// Dispatching routine to lower various 256-bit LoongArch vector shuffles.
3379///
3380/// This routine breaks down the specific type of 256-bit shuffle and
3381/// dispatches to the lowering routines accordingly.
3383 SDValue V1, SDValue V2, SelectionDAG &DAG,
3384 const LoongArchSubtarget &Subtarget) {
3385 assert((VT.SimpleTy == MVT::v32i8 || VT.SimpleTy == MVT::v16i16 ||
3386 VT.SimpleTy == MVT::v8i32 || VT.SimpleTy == MVT::v4i64 ||
3387 VT.SimpleTy == MVT::v8f32 || VT.SimpleTy == MVT::v4f64) &&
3388 "Vector type is unsupported for lasx!");
3389 assert(V1.getSimpleValueType() == V2.getSimpleValueType() &&
3390 "Two operands have different types!");
3391 assert(VT.getVectorNumElements() == Mask.size() &&
3392 "Unexpected mask size for shuffle!");
3393 assert(Mask.size() % 2 == 0 && "Expected even mask size.");
3394 assert(Mask.size() >= 4 && "Mask size is less than 4.");
3395
3396 APInt KnownUndef, KnownZero;
3397 computeZeroableShuffleElements(Mask, V1, V2, KnownUndef, KnownZero);
3398 APInt Zeroable = KnownUndef | KnownZero;
3399
3400 SDValue Result;
3401 // TODO: Add more comparison patterns.
3402 if (V2.isUndef()) {
3403 if ((Result =
3404 lowerVECTOR_SHUFFLE_XVREPLVEI(DL, Mask, VT, V1, DAG, Subtarget)))
3405 return Result;
3406 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG,
3407 Subtarget)))
3408 return Result;
3409 // Try to widen vectors to gain more optimization opportunities.
3410 if (SDValue NewShuffle = widenShuffleMask(DL, Mask, VT, V1, V2, DAG))
3411 return NewShuffle;
3412 if ((Result =
3413 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3414 return Result;
3415 if ((Result = lowerVECTOR_SHUFFLE_XVPERM(DL, Mask, VT, V1, DAG, Subtarget)))
3416 return Result;
3417 if ((Result =
3418 lowerVECTOR_SHUFFLE_IsReverse(DL, Mask, VT, V1, DAG, Subtarget)))
3419 return Result;
3420
3421 // TODO: This comment may be enabled in the future to better match the
3422 // pattern for instruction selection.
3423 /* V2 = V1; */
3424 }
3425
3426 // It is recommended not to change the pattern comparison order for better
3427 // performance.
3428 if ((Result = lowerVECTOR_SHUFFLE_XVPACKEV(DL, Mask, VT, V1, V2, DAG)))
3429 return Result;
3430 if ((Result = lowerVECTOR_SHUFFLE_XVPACKOD(DL, Mask, VT, V1, V2, DAG)))
3431 return Result;
3432 if ((Result = lowerVECTOR_SHUFFLE_XVILVH(DL, Mask, VT, V1, V2, DAG)))
3433 return Result;
3434 if ((Result = lowerVECTOR_SHUFFLE_XVILVL(DL, Mask, VT, V1, V2, DAG)))
3435 return Result;
3436 if ((Result = lowerVECTOR_SHUFFLE_XVPICKEV(DL, Mask, VT, V1, V2, DAG)))
3437 return Result;
3438 if ((Result = lowerVECTOR_SHUFFLE_XVPICKOD(DL, Mask, VT, V1, V2, DAG)))
3439 return Result;
3440 if ((VT.SimpleTy == MVT::v4i64 || VT.SimpleTy == MVT::v4f64) &&
3441 (Result =
3442 lowerVECTOR_SHUFFLE_XVSHUF4I(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3443 return Result;
3444 if ((Result =
3445 lowerVECTOR_SHUFFLE_XVEXTRINS(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3446 return Result;
3447 if ((Result = lowerVECTOR_SHUFFLEAsShift(DL, Mask, VT, V1, V2, DAG, Subtarget,
3448 Zeroable)))
3449 return Result;
3450 if ((Result =
3451 lowerVECTOR_SHUFFLE_XVPERMI(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3452 return Result;
3453 if ((Result =
3454 lowerVECTOR_SHUFFLE_XVINSVE0(DL, Mask, VT, V1, V2, DAG, Subtarget)))
3455 return Result;
3456 if ((Result = lowerVECTOR_SHUFFLEAsByteRotate(DL, Mask, VT, V1, V2, DAG,
3457 Subtarget)))
3458 return Result;
3459
3460 // canonicalize non cross-lane shuffle vector
3461 SmallVector<int> NewMask(Mask);
3462 if (canonicalizeShuffleVectorByLane(DL, NewMask, VT, V1, V2, DAG, Subtarget))
3463 return lower256BitShuffle(DL, NewMask, VT, V1, V2, DAG, Subtarget);
3464
3465 // FIXME: Handling the remaining cases earlier can degrade performance
3466 // in some situations. Further analysis is required to enable more
3467 // effective optimizations.
3468 if (V2.isUndef()) {
3469 if ((Result = lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(DL, NewMask, VT,
3470 V1, V2, DAG)))
3471 return Result;
3472 }
3473
3474 if (SDValue NewShuffle = widenShuffleMask(DL, NewMask, VT, V1, V2, DAG))
3475 return NewShuffle;
3476 if ((Result = lowerVECTOR_SHUFFLE_XVSHUF(DL, NewMask, VT, V1, V2, DAG)))
3477 return Result;
3478
3479 return SDValue();
3480}
3481
3482SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
3483 SelectionDAG &DAG) const {
3484 ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
3485 ArrayRef<int> OrigMask = SVOp->getMask();
3486 SDValue V1 = Op.getOperand(0);
3487 SDValue V2 = Op.getOperand(1);
3488 MVT VT = Op.getSimpleValueType();
3489 int NumElements = VT.getVectorNumElements();
3490 SDLoc DL(Op);
3491
3492 bool V1IsUndef = V1.isUndef();
3493 bool V2IsUndef = V2.isUndef();
3494 if (V1IsUndef && V2IsUndef)
3495 return DAG.getUNDEF(VT);
3496
3497 // When we create a shuffle node we put the UNDEF node to second operand,
3498 // but in some cases the first operand may be transformed to UNDEF.
3499 // In this case we should just commute the node.
3500 if (V1IsUndef)
3501 return DAG.getCommutedVectorShuffle(*SVOp);
3502
3503 // Check for non-undef masks pointing at an undef vector and make the masks
3504 // undef as well. This makes it easier to match the shuffle based solely on
3505 // the mask.
3506 if (V2IsUndef &&
3507 any_of(OrigMask, [NumElements](int M) { return M >= NumElements; })) {
3508 SmallVector<int, 8> NewMask(OrigMask);
3509 for (int &M : NewMask)
3510 if (M >= NumElements)
3511 M = -1;
3512 return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
3513 }
3514
3515 // Check for illegal shuffle mask element index values.
3516 int MaskUpperLimit = OrigMask.size() * (V2IsUndef ? 1 : 2);
3517 (void)MaskUpperLimit;
3518 assert(llvm::all_of(OrigMask,
3519 [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
3520 "Out of bounds shuffle index");
3521
3522 // For each vector width, delegate to a specialized lowering routine.
3523 if (VT.is128BitVector())
3524 return lower128BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3525
3526 if (VT.is256BitVector())
3527 return lower256BitShuffle(DL, OrigMask, VT, V1, V2, DAG, Subtarget);
3528
3529 return SDValue();
3530}
3531
3532SDValue LoongArchTargetLowering::lowerFP_TO_FP16(SDValue Op,
3533 SelectionDAG &DAG) const {
3534 // Custom lower to ensure the libcall return is passed in an FPR on hard
3535 // float ABIs.
3536 SDLoc DL(Op);
3537 MakeLibCallOptions CallOptions;
3538 SDValue Op0 = Op.getOperand(0);
3539 SDValue Chain = SDValue();
3540 RTLIB::Libcall LC = RTLIB::getFPROUND(Op0.getValueType(), MVT::f16);
3541 SDValue Res;
3542 std::tie(Res, Chain) =
3543 makeLibCall(DAG, LC, MVT::f32, Op0, CallOptions, DL, Chain);
3544 if (Subtarget.is64Bit())
3545 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3546 return DAG.getBitcast(MVT::i32, Res);
3547}
3548
3549SDValue LoongArchTargetLowering::lowerFP16_TO_FP(SDValue Op,
3550 SelectionDAG &DAG) const {
3551 // Custom lower to ensure the libcall argument is passed in an FPR on hard
3552 // float ABIs.
3553 SDLoc DL(Op);
3554 MakeLibCallOptions CallOptions;
3555 SDValue Op0 = Op.getOperand(0);
3556 SDValue Chain = SDValue();
3557 SDValue Arg = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3558 DL, MVT::f32, Op0)
3559 : DAG.getBitcast(MVT::f32, Op0);
3560 SDValue Res;
3561 std::tie(Res, Chain) = makeLibCall(DAG, RTLIB::FPEXT_F16_F32, MVT::f32, Arg,
3562 CallOptions, DL, Chain);
3563 return Res;
3564}
3565
3566SDValue LoongArchTargetLowering::lowerFP_TO_BF16(SDValue Op,
3567 SelectionDAG &DAG) const {
3568 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3569 SDLoc DL(Op);
3570 MakeLibCallOptions CallOptions;
3571 RTLIB::Libcall LC =
3572 RTLIB::getFPROUND(Op.getOperand(0).getValueType(), MVT::bf16);
3573 SDValue Res =
3574 makeLibCall(DAG, LC, MVT::f32, Op.getOperand(0), CallOptions, DL).first;
3575 if (Subtarget.is64Bit())
3576 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Res);
3577 return DAG.getBitcast(MVT::i32, Res);
3578}
3579
3580SDValue LoongArchTargetLowering::lowerBF16_TO_FP(SDValue Op,
3581 SelectionDAG &DAG) const {
3582 assert(Subtarget.hasBasicF() && "Unexpected custom legalization");
3583 MVT VT = Op.getSimpleValueType();
3584 SDLoc DL(Op);
3585 Op = DAG.getNode(
3586 ISD::SHL, DL, Op.getOperand(0).getValueType(), Op.getOperand(0),
3587 DAG.getShiftAmountConstant(16, Op.getOperand(0).getValueType(), DL));
3588 SDValue Res = Subtarget.is64Bit() ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64,
3589 DL, MVT::f32, Op)
3590 : DAG.getBitcast(MVT::f32, Op);
3591 if (VT != MVT::f32)
3592 return DAG.getNode(ISD::FP_EXTEND, DL, VT, Res);
3593 return Res;
3594}
3595
3596// Lower BUILD_VECTOR as broadcast load (if possible).
3597// For example:
3598// %a = load i8, ptr %ptr
3599// %b = build_vector %a, %a, %a, %a
3600// is lowered to :
3601// (VLDREPL_B $a0, 0)
3603 const SDLoc &DL,
3604 SelectionDAG &DAG) {
3605 MVT VT = BVOp->getSimpleValueType(0);
3606 int NumOps = BVOp->getNumOperands();
3607
3608 assert((VT.is128BitVector() || VT.is256BitVector()) &&
3609 "Unsupported vector type for broadcast.");
3610
3611 SDValue IdentitySrc;
3612 bool IsIdeneity = true;
3613
3614 for (int i = 0; i != NumOps; i++) {
3615 SDValue Op = BVOp->getOperand(i);
3616 if (Op.getOpcode() != ISD::LOAD || (IdentitySrc && Op != IdentitySrc)) {
3617 IsIdeneity = false;
3618 break;
3619 }
3620 IdentitySrc = BVOp->getOperand(0);
3621 }
3622
3623 // make sure that this load is valid and only has one user.
3624 if (!IsIdeneity || !IdentitySrc || !BVOp->isOnlyUserOf(IdentitySrc.getNode()))
3625 return SDValue();
3626
3627 auto *LN = cast<LoadSDNode>(IdentitySrc);
3628 auto ExtType = LN->getExtensionType();
3629
3630 if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) &&
3631 VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) {
3632 // Indexed loads and stores are not supported on LoongArch.
3633 assert(LN->isUnindexed() && "Unexpected indexed load.");
3634
3635 SDVTList Tys = DAG.getVTList(VT, MVT::Other);
3636 // The offset operand of unindexed load is always undefined, so there is
3637 // no need to pass it to VLDREPL.
3638 SDValue Ops[] = {LN->getChain(), LN->getBasePtr()};
3639 SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops);
3640 DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1));
3641 return BCast;
3642 }
3643 return SDValue();
3644}
3645
3646// Sequentially insert elements from Ops into Vector, from low to high indices.
3647// Note: Ops can have fewer elements than Vector.
3649 const LoongArchSubtarget &Subtarget, SDValue &Vector,
3650 EVT ResTy) {
3651 assert(Ops.size() <= ResTy.getVectorNumElements());
3652
3653 SDValue Op0 = Ops[0];
3654 if (!Op0.isUndef())
3655 Vector = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, ResTy, Op0);
3656 for (unsigned i = 1; i < Ops.size(); ++i) {
3657 SDValue Opi = Ops[i];
3658 if (Opi.isUndef())
3659 continue;
3660 Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, Opi,
3661 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3662 }
3663}
3664
3665// Build a ResTy subvector from Node, taking NumElts elements starting at index
3666// 'first'.
3668 SelectionDAG &DAG, SDLoc DL,
3669 const LoongArchSubtarget &Subtarget,
3670 EVT ResTy, unsigned first) {
3671 unsigned NumElts = ResTy.getVectorNumElements();
3672
3673 assert(first + NumElts <= Node->getSimpleValueType(0).getVectorNumElements());
3674
3675 SmallVector<SDValue, 16> Ops(Node->op_begin() + first,
3676 Node->op_begin() + first + NumElts);
3677 SDValue Vector = DAG.getUNDEF(ResTy);
3678 fillVector(Ops, DAG, DL, Subtarget, Vector, ResTy);
3679 return Vector;
3680}
3681
3682SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
3683 SelectionDAG &DAG) const {
3684 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
3685 MVT VT = Node->getSimpleValueType(0);
3686 EVT ResTy = Op->getValueType(0);
3687 unsigned NumElts = ResTy.getVectorNumElements();
3688 SDLoc DL(Op);
3689 APInt SplatValue, SplatUndef;
3690 unsigned SplatBitSize;
3691 bool HasAnyUndefs;
3692 bool IsConstant = false;
3693 bool UseSameConstant = true;
3694 SDValue ConstantValue;
3695 bool Is128Vec = ResTy.is128BitVector();
3696 bool Is256Vec = ResTy.is256BitVector();
3697
3698 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
3699 (!Subtarget.hasExtLASX() || !Is256Vec))
3700 return SDValue();
3701
3702 if (SDValue Result = lowerBUILD_VECTORAsBroadCastLoad(Node, DL, DAG))
3703 return Result;
3704
3705 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
3706 /*MinSplatBits=*/8) &&
3707 SplatBitSize <= 64) {
3708 // We can only cope with 8, 16, 32, or 64-bit elements.
3709 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
3710 SplatBitSize != 64)
3711 return SDValue();
3712
3713 if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
3714 // We can only handle 64-bit elements that are within
3715 // the signed 10-bit range or match vldi patterns on 32-bit targets.
3716 // See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
3717 if (!SplatValue.isSignedIntN(10) &&
3718 !isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
3719 return SDValue();
3720 if ((Is128Vec && ResTy == MVT::v4i32) ||
3721 (Is256Vec && ResTy == MVT::v8i32))
3722 return Op;
3723 }
3724
3725 EVT ViaVecTy;
3726
3727 switch (SplatBitSize) {
3728 default:
3729 return SDValue();
3730 case 8:
3731 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
3732 break;
3733 case 16:
3734 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
3735 break;
3736 case 32:
3737 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
3738 break;
3739 case 64:
3740 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
3741 break;
3742 }
3743
3744 // SelectionDAG::getConstant will promote SplatValue appropriately.
3745 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
3746
3747 // Bitcast to the type we originally wanted.
3748 if (ViaVecTy != ResTy)
3749 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
3750
3751 return Result;
3752 }
3753
3754 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
3755 return Op;
3756
3757 for (unsigned i = 0; i < NumElts; ++i) {
3758 SDValue Opi = Node->getOperand(i);
3759 if (isIntOrFPConstant(Opi)) {
3760 IsConstant = true;
3761 if (!ConstantValue.getNode())
3762 ConstantValue = Opi;
3763 else if (ConstantValue != Opi)
3764 UseSameConstant = false;
3765 }
3766 }
3767
3768 // If the type of BUILD_VECTOR is v2f64, custom legalizing it has no benefits.
3769 if (IsConstant && UseSameConstant && ResTy != MVT::v2f64) {
3770 SDValue Result = DAG.getSplatBuildVector(ResTy, DL, ConstantValue);
3771 for (unsigned i = 0; i < NumElts; ++i) {
3772 SDValue Opi = Node->getOperand(i);
3773 if (!isIntOrFPConstant(Opi))
3774 Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Result, Opi,
3775 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
3776 }
3777 return Result;
3778 }
3779
3780 if (!IsConstant) {
3781 // If the BUILD_VECTOR has a repeated pattern, use INSERT_VECTOR_ELT to fill
3782 // the sub-sequence of the vector and then broadcast the sub-sequence.
3783 //
3784 // TODO: If the BUILD_VECTOR contains undef elements, consider falling
3785 // back to use INSERT_VECTOR_ELT to materialize the vector, because it
3786 // generates worse code in some cases. This could be further optimized
3787 // with more consideration.
3789 BitVector UndefElements;
3790 if (Node->getRepeatedSequence(Sequence, &UndefElements) &&
3791 UndefElements.count() == 0) {
3792 // Using LSX instructions to fill the sub-sequence of 256-bits vector,
3793 // because the high part can be simply treated as undef.
3794 SDValue Vector = DAG.getUNDEF(ResTy);
3795 EVT FillTy = Is256Vec
3797 : ResTy;
3798 SDValue FillVec =
3799 Is256Vec ? DAG.getExtractSubvector(DL, FillTy, Vector, 0) : Vector;
3800
3801 fillVector(Sequence, DAG, DL, Subtarget, FillVec, FillTy);
3802
3803 unsigned SeqLen = Sequence.size();
3804 unsigned SplatLen = NumElts / SeqLen;
3805 MVT SplatEltTy = MVT::getIntegerVT(VT.getScalarSizeInBits() * SeqLen);
3806 MVT SplatTy = MVT::getVectorVT(SplatEltTy, SplatLen);
3807
3808 // If size of the sub-sequence is half of a 256-bits vector, bitcast the
3809 // vector to v4i64 type in order to match the pattern of XVREPLVE0Q.
3810 if (SplatEltTy == MVT::i128)
3811 SplatTy = MVT::v4i64;
3812
3813 SDValue SplatVec;
3814 SDValue SrcVec = DAG.getBitcast(
3815 SplatTy,
3816 Is256Vec ? DAG.getInsertSubvector(DL, Vector, FillVec, 0) : FillVec);
3817 if (Is256Vec) {
3818 SplatVec =
3819 DAG.getNode((SplatEltTy == MVT::i128) ? LoongArchISD::XVREPLVE0Q
3820 : LoongArchISD::XVREPLVE0,
3821 DL, SplatTy, SrcVec);
3822 } else {
3823 SplatVec = DAG.getNode(LoongArchISD::VREPLVEI, DL, SplatTy, SrcVec,
3824 DAG.getConstant(0, DL, Subtarget.getGRLenVT()));
3825 }
3826
3827 return DAG.getBitcast(ResTy, SplatVec);
3828 }
3829
3830 // Use INSERT_VECTOR_ELT operations rather than expand to stores, because
3831 // using memory operations is much lower.
3832 //
3833 // For 256-bit vectors, normally split into two halves and concatenate.
3834 // Special case: for v8i32/v8f32/v4i64/v4f64, if the upper half has only
3835 // one non-undef element, skip spliting to avoid a worse result.
3836 if (ResTy == MVT::v8i32 || ResTy == MVT::v8f32 || ResTy == MVT::v4i64 ||
3837 ResTy == MVT::v4f64) {
3838 unsigned NonUndefCount = 0;
3839 for (unsigned i = NumElts / 2; i < NumElts; ++i) {
3840 if (!Node->getOperand(i).isUndef()) {
3841 ++NonUndefCount;
3842 if (NonUndefCount > 1)
3843 break;
3844 }
3845 }
3846 if (NonUndefCount == 1)
3847 return fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, ResTy, 0);
3848 }
3849
3850 EVT VecTy =
3851 Is256Vec ? ResTy.getHalfNumVectorElementsVT(*DAG.getContext()) : ResTy;
3852 SDValue Vector =
3853 fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget, VecTy, 0);
3854
3855 if (Is128Vec)
3856 return Vector;
3857
3858 SDValue VectorHi = fillSubVectorFromBuildVector(Node, DAG, DL, Subtarget,
3859 VecTy, NumElts / 2);
3860
3861 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResTy, Vector, VectorHi);
3862 }
3863
3864 return SDValue();
3865}
3866
3867SDValue LoongArchTargetLowering::lowerCONCAT_VECTORS(SDValue Op,
3868 SelectionDAG &DAG) const {
3869 SDLoc DL(Op);
3870 MVT ResVT = Op.getSimpleValueType();
3871 assert(ResVT.is256BitVector() && Op.getNumOperands() == 2);
3872
3873 if (Op.getOperand(0).getOpcode() == ISD::TRUNCATE &&
3874 Op.getOperand(1).getOpcode() == ISD::TRUNCATE)
3875 return Op;
3876
3877 unsigned NumOperands = Op.getNumOperands();
3878 unsigned NumFreezeUndef = 0;
3879 unsigned NumZero = 0;
3880 unsigned NumNonZero = 0;
3881 unsigned NonZeros = 0;
3882 SmallSet<SDValue, 4> Undefs;
3883 for (unsigned i = 0; i != NumOperands; ++i) {
3884 SDValue SubVec = Op.getOperand(i);
3885 if (SubVec.isUndef())
3886 continue;
3887 if (ISD::isFreezeUndef(SubVec.getNode())) {
3888 // If the freeze(undef) has multiple uses then we must fold to zero.
3889 if (SubVec.hasOneUse()) {
3890 ++NumFreezeUndef;
3891 } else {
3892 ++NumZero;
3893 Undefs.insert(SubVec);
3894 }
3895 } else if (ISD::isBuildVectorAllZeros(SubVec.getNode()))
3896 ++NumZero;
3897 else {
3898 assert(i < sizeof(NonZeros) * CHAR_BIT); // Ensure the shift is in range.
3899 NonZeros |= 1 << i;
3900 ++NumNonZero;
3901 }
3902 }
3903
3904 // If we have more than 2 non-zeros, build each half separately.
3905 if (NumNonZero > 2) {
3906 MVT HalfVT = ResVT.getHalfNumVectorElementsVT();
3907 ArrayRef<SDUse> Ops = Op->ops();
3908 SDValue Lo = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3909 Ops.slice(0, NumOperands / 2));
3910 SDValue Hi = DAG.getNode(ISD::CONCAT_VECTORS, DL, HalfVT,
3911 Ops.slice(NumOperands / 2));
3912 return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
3913 }
3914
3915 // Otherwise, build it up through insert_subvectors.
3916 SDValue Vec = NumZero ? DAG.getConstant(0, DL, ResVT)
3917 : (NumFreezeUndef ? DAG.getFreeze(DAG.getUNDEF(ResVT))
3918 : DAG.getUNDEF(ResVT));
3919
3920 // Replace Undef operands with ZeroVector.
3921 for (SDValue U : Undefs)
3922 DAG.ReplaceAllUsesWith(U, DAG.getConstant(0, DL, U.getSimpleValueType()));
3923
3924 MVT SubVT = Op.getOperand(0).getSimpleValueType();
3925 unsigned NumSubElems = SubVT.getVectorNumElements();
3926 for (unsigned i = 0; i != NumOperands; ++i) {
3927 if ((NonZeros & (1 << i)) == 0)
3928 continue;
3929
3930 Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, ResVT, Vec, Op.getOperand(i),
3931 DAG.getVectorIdxConstant(i * NumSubElems, DL));
3932 }
3933
3934 return Vec;
3935}
3936
3937SDValue
3938LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
3939 SelectionDAG &DAG) const {
3940 MVT EltVT = Op.getSimpleValueType();
3941 SDValue Vec = Op->getOperand(0);
3942 EVT VecTy = Vec->getValueType(0);
3943 SDValue Idx = Op->getOperand(1);
3944 SDLoc DL(Op);
3945 MVT GRLenVT = Subtarget.getGRLenVT();
3946
3947 assert(VecTy.is256BitVector() && "Unexpected EXTRACT_VECTOR_ELT vector type");
3948
3949 if (isa<ConstantSDNode>(Idx))
3950 return Op;
3951
3952 switch (VecTy.getSimpleVT().SimpleTy) {
3953 default:
3954 llvm_unreachable("Unexpected type");
3955 case MVT::v32i8:
3956 case MVT::v16i16:
3957 case MVT::v4i64:
3958 case MVT::v4f64: {
3959 // Extract the high half subvector and place it to the low half of a new
3960 // vector. It doesn't matter what the high half of the new vector is.
3961 EVT HalfTy = VecTy.getHalfNumVectorElementsVT(*DAG.getContext());
3962 SDValue VecHi =
3963 DAG.getExtractSubvector(DL, HalfTy, Vec, HalfTy.getVectorNumElements());
3964 SDValue TmpVec =
3965 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VecTy, DAG.getUNDEF(VecTy),
3966 VecHi, DAG.getConstant(0, DL, GRLenVT));
3967
3968 // Shuffle the origin Vec and the TmpVec using MaskVec, the lowest element
3969 // of MaskVec is Idx, the rest do not matter. ResVec[0] will hold the
3970 // desired element.
3971 SDValue IdxCp =
3972 Subtarget.is64Bit()
3973 ? DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Idx)
3974 : DAG.getBitcast(MVT::f32, Idx);
3975 SDValue IdxVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v8f32, IdxCp);
3976 SDValue MaskVec =
3977 DAG.getBitcast((VecTy == MVT::v4f64) ? MVT::v4i64 : VecTy, IdxVec);
3978 SDValue ResVec =
3979 DAG.getNode(LoongArchISD::VSHUF, DL, VecTy, MaskVec, TmpVec, Vec);
3980
3981 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, ResVec,
3982 DAG.getConstant(0, DL, GRLenVT));
3983 }
3984 case MVT::v8i32:
3985 case MVT::v8f32: {
3986 SDValue SplatIdx = DAG.getSplatBuildVector(MVT::v8i32, DL, Idx);
3987 SDValue SplatValue =
3988 DAG.getNode(LoongArchISD::XVPERM, DL, VecTy, Vec, SplatIdx);
3989
3990 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, SplatValue,
3991 DAG.getConstant(0, DL, GRLenVT));
3992 }
3993 }
3994}
3995
3996SDValue
3997LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
3998 SelectionDAG &DAG) const {
3999 MVT VT = Op.getSimpleValueType();
4000 MVT EltVT = VT.getVectorElementType();
4001 unsigned NumElts = VT.getVectorNumElements();
4002 unsigned EltSizeInBits = EltVT.getScalarSizeInBits();
4003 SDLoc DL(Op);
4004 SDValue Op0 = Op.getOperand(0);
4005 SDValue Op1 = Op.getOperand(1);
4006 SDValue Op2 = Op.getOperand(2);
4007
4008 if (isa<ConstantSDNode>(Op2))
4009 return Op;
4010
4011 MVT IdxTy = MVT::getIntegerVT(EltSizeInBits);
4012 MVT IdxVTy = MVT::getVectorVT(IdxTy, NumElts);
4013
4014 if (!isTypeLegal(VT) || !isTypeLegal(IdxVTy))
4015 return SDValue();
4016
4017 SDValue SplatElt = DAG.getSplatBuildVector(VT, DL, Op1);
4018 SmallVector<SDValue, 32> RawIndices;
4019 SDValue SplatIdx;
4020 SDValue Indices;
4021
4022 if (!Subtarget.is64Bit() && IdxTy == MVT::i64) {
4023 MVT PairVTy = MVT::getVectorVT(MVT::i32, NumElts * 2);
4024 for (unsigned i = 0; i < NumElts; ++i) {
4025 RawIndices.push_back(Op2);
4026 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4027 }
4028 SplatIdx = DAG.getBuildVector(PairVTy, DL, RawIndices);
4029 SplatIdx = DAG.getBitcast(IdxVTy, SplatIdx);
4030
4031 RawIndices.clear();
4032 for (unsigned i = 0; i < NumElts; ++i) {
4033 RawIndices.push_back(DAG.getConstant(i, DL, MVT::i32));
4034 RawIndices.push_back(DAG.getConstant(0, DL, MVT::i32));
4035 }
4036 Indices = DAG.getBuildVector(PairVTy, DL, RawIndices);
4037 Indices = DAG.getBitcast(IdxVTy, Indices);
4038 } else {
4039 SplatIdx = DAG.getSplatBuildVector(IdxVTy, DL, Op2);
4040
4041 for (unsigned i = 0; i < NumElts; ++i)
4042 RawIndices.push_back(DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
4043 Indices = DAG.getBuildVector(IdxVTy, DL, RawIndices);
4044 }
4045
4046 // insert vec, elt, idx
4047 // =>
4048 // select (splatidx == {0,1,2...}) ? splatelt : vec
4049 SDValue SelectCC =
4050 DAG.getSetCC(DL, IdxVTy, SplatIdx, Indices, ISD::CondCode::SETEQ);
4051 return DAG.getNode(ISD::VSELECT, DL, VT, SelectCC, SplatElt, Op0);
4052}
4053
4054SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
4055 SelectionDAG &DAG) const {
4056 SDLoc DL(Op);
4057 SyncScope::ID FenceSSID =
4058 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
4059
4060 // singlethread fences only synchronize with signal handlers on the same
4061 // thread and thus only need to preserve instruction order, not actually
4062 // enforce memory ordering.
4063 if (FenceSSID == SyncScope::SingleThread)
4064 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
4065 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
4066
4067 return Op;
4068}
4069
4071 MVT GRLenVT, SDValue RMValue) {
4072 // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
4073 // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
4074 // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
4075 //
4076 // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
4077 // Since the transformation is self-inverse, it applies in both directions:
4078 // LLVM RM <-> LoongArch FCSR RM
4079 //
4080 // Transformation: RM ^ (~(RM >> 1) & 1)
4081 SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4082 DAG.getConstant(1, DL, GRLenVT));
4083
4084 SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
4085 DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
4086 DAG.getConstant(1, DL, GRLenVT)),
4087 DAG.getConstant(1, DL, GRLenVT));
4088
4089 return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
4090}
4091
4092SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
4093 SelectionDAG &DAG) const {
4094 MVT GRLenVT = Subtarget.getGRLenVT();
4095 SDLoc DL(Op);
4096 SDValue Chain = Op.getOperand(0);
4097 SDValue RMValue = Op.getOperand(1);
4098
4099 if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
4100 uint64_t RM = CVal->getZExtValue();
4101 if (RM > 3) {
4103 LLVMContext &C = MF.getFunction().getContext();
4104 C.diagnose(DiagnosticInfoUnsupported(
4105 MF.getFunction(),
4106 "rounding mode is not supported by LoongArch hardware",
4107 DiagnosticLocation(DL.getDebugLoc()), DS_Error));
4108 return Chain;
4109 }
4110 }
4111
4112 RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
4113 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4114
4115 // The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
4116 // into position before writing via WRFCSR.
4117 RMValue = DAG.getNode(ISD::SHL, DL, GRLenVT, RMValue,
4118 DAG.getConstant(8, DL, GRLenVT));
4119
4120 // FCSR3 is an alias of the RM field; writing it avoids clobbering
4121 // unrelated fields in FCSR0.
4122 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4123 MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
4124 FCSRNo, RMValue, Chain);
4125 return SDValue(RN, 0);
4126}
4127
4128SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
4129 SelectionDAG &DAG) const {
4130 MVT GRLenVT = Subtarget.getGRLenVT();
4131 SDLoc DL(Op);
4132 SDValue Chain = Op->getOperand(0);
4133
4134 // FCSR3 is an alias of the RM field.
4135 SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
4136 MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
4137 MVT::Other, FCSRNo, Chain);
4138 SDValue RMValue = SDValue(FCSR, 0);
4139 Chain = SDValue(FCSR, 1);
4140
4141 // The RM field in FCSR is at bits [9:8].
4142 RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
4143 DAG.getConstant(8, DL, GRLenVT));
4144 RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
4145
4146 SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
4147 return DAG.getMergeValues({RetVal, Chain}, DL);
4148}
4149
4150SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
4151 SelectionDAG &DAG) const {
4152
4153 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
4154 DAG.getContext()->emitError(
4155 "On LA64, only 64-bit registers can be written.");
4156 return Op.getOperand(0);
4157 }
4158
4159 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
4160 DAG.getContext()->emitError(
4161 "On LA32, only 32-bit registers can be written.");
4162 return Op.getOperand(0);
4163 }
4164
4165 return Op;
4166}
4167
4168SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
4169 SelectionDAG &DAG) const {
4170 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
4171 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
4172 "be a constant integer");
4173 return SDValue();
4174 }
4175
4178 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
4179 EVT VT = Op.getValueType();
4180 SDLoc DL(Op);
4181 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
4182 unsigned Depth = Op.getConstantOperandVal(0);
4183 int GRLenInBytes = Subtarget.getGRLen() / 8;
4184
4185 while (Depth--) {
4186 int Offset = -(GRLenInBytes * 2);
4187 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
4188 DAG.getSignedConstant(Offset, DL, VT));
4189 FrameAddr =
4190 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
4191 }
4192 return FrameAddr;
4193}
4194
4195SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
4196 SelectionDAG &DAG) const {
4197 // Currently only support lowering return address for current frame.
4198 if (Op.getConstantOperandVal(0) != 0) {
4199 DAG.getContext()->emitError(
4200 "return address can only be determined for the current frame");
4201 return SDValue();
4202 }
4203
4206 MVT GRLenVT = Subtarget.getGRLenVT();
4207
4208 // Return the value of the return address register, marking it an implicit
4209 // live-in.
4210 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
4211 getRegClassFor(GRLenVT));
4212 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
4213}
4214
4215SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
4216 SelectionDAG &DAG) const {
4218 auto Size = Subtarget.getGRLen() / 8;
4219 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
4220 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4221}
4222
4223SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
4224 SelectionDAG &DAG) const {
4226 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
4227
4228 SDLoc DL(Op);
4229 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
4231
4232 // vastart just stores the address of the VarArgsFrameIndex slot into the
4233 // memory location argument.
4234 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
4235 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
4236 MachinePointerInfo(SV));
4237}
4238
4239SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
4240 SelectionDAG &DAG) const {
4241 SDLoc DL(Op);
4242 SDValue Op0 = Op.getOperand(0);
4243 EVT VT = Op.getValueType();
4244 EVT Op0VT = Op0.getValueType();
4245
4246 if (VT.isVector()) {
4247 if (VT.getScalarSizeInBits() != Op0VT.getScalarSizeInBits())
4248 return SDValue();
4249 return Op;
4250 }
4251
4252 if ((DAG.SignBitIsZero(Op0) || Op->getFlags().hasNonNeg()) &&
4255 return DAG.getNode(ISD::SINT_TO_FP, DL, VT, Op0);
4256
4257 // We can't do uint64 -> double -> float because of double-rounding issue.
4258 if (Subtarget.hasExtLSX() && Op0VT == MVT::i64 && VT == MVT::f64) {
4259 Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2i64, Op0);
4260 SDValue Conv = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::v2f64, Op0);
4261 Conv = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f64, Conv,
4262 DAG.getIntPtrConstant(0, DL));
4263 return Conv;
4264 }
4265
4266 if (!Subtarget.is64Bit() || !Subtarget.hasBasicF() || Subtarget.hasBasicD())
4267 return SDValue();
4268
4269 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4270 !Subtarget.hasBasicD() && "unexpected target features");
4271
4272 if (Op0->getOpcode() == ISD::AND) {
4273 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
4274 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
4275 return Op;
4276 }
4277
4278 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
4279 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
4280 Op0.getConstantOperandVal(2) == UINT64_C(0))
4281 return Op;
4282
4283 if (Op0.getOpcode() == ISD::AssertZext &&
4284 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
4285 return Op;
4286
4287 EVT OpVT = Op0.getValueType();
4288 EVT RetVT = Op.getValueType();
4289 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
4290 MakeLibCallOptions CallOptions;
4291 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4292 SDValue Chain = SDValue();
4293 SDValue Result;
4294 std::tie(Result, Chain) =
4295 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4296 return Result;
4297}
4298
4299SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
4300 SelectionDAG &DAG) const {
4301 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
4302 !Subtarget.hasBasicD() && "unexpected target features");
4303
4304 SDLoc DL(Op);
4305 SDValue Op0 = Op.getOperand(0);
4306
4307 if ((Op0.getOpcode() == ISD::AssertSext ||
4309 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
4310 return Op;
4311
4312 EVT OpVT = Op0.getValueType();
4313 EVT RetVT = Op.getValueType();
4314 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
4315 MakeLibCallOptions CallOptions;
4316 CallOptions.setTypeListBeforeSoften(OpVT, RetVT);
4317 SDValue Chain = SDValue();
4318 SDValue Result;
4319 std::tie(Result, Chain) =
4320 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
4321 return Result;
4322}
4323
4324SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
4325 SelectionDAG &DAG) const {
4326
4327 SDLoc DL(Op);
4328 EVT VT = Op.getValueType();
4329 SDValue Op0 = Op.getOperand(0);
4330 EVT Op0VT = Op0.getValueType();
4331
4332 if (Op.getValueType() == MVT::f32 && Op0VT == MVT::i32 &&
4333 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
4334 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
4335 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
4336 }
4337 if (VT == MVT::f64 && Op0VT == MVT::i64 && !Subtarget.is64Bit()) {
4338 SDValue Lo, Hi;
4339 std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
4340 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
4341 }
4342 return Op;
4343}
4344
4345SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
4346 SelectionDAG &DAG) const {
4347
4348 SDLoc DL(Op);
4349 SDValue Op0 = Op.getOperand(0);
4350
4351 if (Op0.getValueType() == MVT::f16)
4352 Op0 = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Op0);
4353
4354 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
4355 !Subtarget.hasBasicD()) {
4356 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op0);
4357 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
4358 }
4359
4360 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
4361 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op0);
4362 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
4363}
4364
4365SDValue LoongArchTargetLowering::lowerFP_TO_UINT(SDValue Op,
4366 SelectionDAG &DAG) const {
4367 if (!Subtarget.hasExtLSX())
4368 return SDValue();
4369
4370 SDLoc DL(Op);
4371 SDValue Src = Op.getOperand(0);
4372 EVT VT = Op.getValueType();
4373 EVT SrcVT = Src.getValueType();
4374
4375 if (VT != MVT::i64)
4376 return SDValue();
4377
4378 if (SrcVT != MVT::f32 && SrcVT != MVT::f64)
4379 return SDValue();
4380
4381 if (SrcVT == MVT::f32)
4382 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, Src);
4383 Src = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, MVT::v2f64, Src);
4384 SDValue Conv = DAG.getNode(ISD::FP_TO_UINT, DL, MVT::v2i64, Src);
4385 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Conv,
4386 DAG.getIntPtrConstant(0, DL));
4387}
4388
4390 SelectionDAG &DAG, unsigned Flags) {
4391 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
4392}
4393
4395 SelectionDAG &DAG, unsigned Flags) {
4396 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
4397 Flags);
4398}
4399
4401 SelectionDAG &DAG, unsigned Flags) {
4402 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
4403 N->getOffset(), Flags);
4404}
4405
4407 SelectionDAG &DAG, unsigned Flags) {
4408 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
4409}
4410
4411template <class NodeTy>
4412SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
4414 bool IsLocal) const {
4415 SDLoc DL(N);
4416 EVT Ty = getPointerTy(DAG.getDataLayout());
4417 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
4418 SDValue Load;
4419
4420 switch (M) {
4421 default:
4422 report_fatal_error("Unsupported code model");
4423
4424 case CodeModel::Large: {
4425 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4426
4427 // This is not actually used, but is necessary for successfully matching
4428 // the PseudoLA_*_LARGE nodes.
4429 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4430 if (IsLocal) {
4431 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
4432 // eventually becomes the desired 5-insn code sequence.
4433 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
4434 Tmp, Addr),
4435 0);
4436 } else {
4437 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
4438 // eventually becomes the desired 5-insn code sequence.
4439 Load = SDValue(
4440 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
4441 0);
4442 }
4443 break;
4444 }
4445
4446 case CodeModel::Small:
4447 case CodeModel::Medium:
4448 if (IsLocal) {
4449 // This generates the pattern (PseudoLA_PCREL sym), which
4450 //
4451 // for la32r expands to:
4452 // (addi.w (pcaddu12i %pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4453 //
4454 // for la32s and la64 expands to:
4455 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
4456 Load = SDValue(
4457 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
4458 } else {
4459 // This generates the pattern (PseudoLA_GOT sym), which
4460 //
4461 // for la32r expands to:
4462 // (ld.w (pcaddu12i %got_pcadd_hi20(sym)) %pcadd_lo12(.Lpcadd_hi)).
4463 //
4464 // for la32s and la64 expands to:
4465 // (ld.w/d (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
4466 Load =
4467 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
4468 }
4469 }
4470
4471 if (!IsLocal) {
4472 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4474 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4478 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4479 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
4480 }
4481
4482 return Load;
4483}
4484
4485SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
4486 SelectionDAG &DAG) const {
4487 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
4488 DAG.getTarget().getCodeModel());
4489}
4490
4491SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
4492 SelectionDAG &DAG) const {
4493 return getAddr(cast<JumpTableSDNode>(Op), DAG,
4494 DAG.getTarget().getCodeModel());
4495}
4496
4497SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
4498 SelectionDAG &DAG) const {
4499 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
4500 DAG.getTarget().getCodeModel());
4501}
4502
4503SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
4504 SelectionDAG &DAG) const {
4505 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4506 assert(N->getOffset() == 0 && "unexpected offset in global node");
4507 auto CM = DAG.getTarget().getCodeModel();
4508 const GlobalValue *GV = N->getGlobal();
4509
4510 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
4511 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
4512 CM = *GCM;
4513 }
4514
4515 return getAddr(N, DAG, CM, GV->isDSOLocal());
4516}
4517
4518SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
4519 SelectionDAG &DAG,
4520 unsigned Opc, bool UseGOT,
4521 bool Large) const {
4522 SDLoc DL(N);
4523 EVT Ty = getPointerTy(DAG.getDataLayout());
4524 MVT GRLenVT = Subtarget.getGRLenVT();
4525
4526 // This is not actually used, but is necessary for successfully matching the
4527 // PseudoLA_*_LARGE nodes.
4528 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4529 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4530
4531 // Only IE needs an extra argument for large code model.
4532 SDValue Offset = Opc == LoongArch::PseudoLA_TLS_IE_LARGE
4533 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4534 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4535
4536 // If it is LE for normal/medium code model, the add tp operation will occur
4537 // during the pseudo-instruction expansion.
4538 if (Opc == LoongArch::PseudoLA_TLS_LE && !Large)
4539 return Offset;
4540
4541 if (UseGOT) {
4542 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
4544 MachineMemOperand *MemOp = MF.getMachineMemOperand(
4548 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
4549 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
4550 }
4551
4552 // Add the thread pointer.
4553 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
4554 DAG.getRegister(LoongArch::R2, GRLenVT));
4555}
4556
4557SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
4558 SelectionDAG &DAG,
4559 unsigned Opc,
4560 bool Large) const {
4561 SDLoc DL(N);
4562 EVT Ty = getPointerTy(DAG.getDataLayout());
4563 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
4564
4565 // This is not actually used, but is necessary for successfully matching the
4566 // PseudoLA_*_LARGE nodes.
4567 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4568
4569 // Use a PC-relative addressing mode to access the dynamic GOT address.
4570 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
4571 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4572 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4573
4574 // Prepare argument list to generate call.
4576 Args.emplace_back(Load, CallTy);
4577
4578 // Setup call to __tls_get_addr.
4579 TargetLowering::CallLoweringInfo CLI(DAG);
4580 CLI.setDebugLoc(DL)
4581 .setChain(DAG.getEntryNode())
4582 .setLibCallee(CallingConv::C, CallTy,
4583 DAG.getExternalSymbol("__tls_get_addr", Ty),
4584 std::move(Args));
4585
4586 return LowerCallTo(CLI).first;
4587}
4588
4589SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
4590 SelectionDAG &DAG, unsigned Opc,
4591 bool Large) const {
4592 SDLoc DL(N);
4593 EVT Ty = getPointerTy(DAG.getDataLayout());
4594 const GlobalValue *GV = N->getGlobal();
4595
4596 // This is not actually used, but is necessary for successfully matching the
4597 // PseudoLA_*_LARGE nodes.
4598 SDValue Tmp = DAG.getConstant(0, DL, Ty);
4599
4600 // Use a PC-relative addressing mode to access the global dynamic GOT address.
4601 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
4602 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
4603 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
4604 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
4605}
4606
4607SDValue
4608LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
4609 SelectionDAG &DAG) const {
4612 report_fatal_error("In GHC calling convention TLS is not supported");
4613
4614 bool Large = DAG.getTarget().getCodeModel() == CodeModel::Large;
4615 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
4616
4617 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
4618 assert(N->getOffset() == 0 && "unexpected offset in global node");
4619
4620 if (DAG.getTarget().useEmulatedTLS())
4621 reportFatalUsageError("the emulated TLS is prohibited");
4622
4623 bool IsDesc = DAG.getTarget().useTLSDESC();
4624
4625 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
4627 // In this model, application code calls the dynamic linker function
4628 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
4629 // runtime.
4630 if (!IsDesc)
4631 return getDynamicTLSAddr(N, DAG,
4632 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
4633 : LoongArch::PseudoLA_TLS_GD,
4634 Large);
4635 break;
4637 // Same as GeneralDynamic, except for assembly modifiers and relocation
4638 // records.
4639 if (!IsDesc)
4640 return getDynamicTLSAddr(N, DAG,
4641 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
4642 : LoongArch::PseudoLA_TLS_LD,
4643 Large);
4644 break;
4646 // This model uses the GOT to resolve TLS offsets.
4647 return getStaticTLSAddr(N, DAG,
4648 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
4649 : LoongArch::PseudoLA_TLS_IE,
4650 /*UseGOT=*/true, Large);
4652 // This model is used when static linking as the TLS offsets are resolved
4653 // during program linking.
4654 //
4655 // This node doesn't need an extra argument for the large code model.
4656 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
4657 /*UseGOT=*/false, Large);
4658 }
4659
4660 return getTLSDescAddr(N, DAG,
4661 Large ? LoongArch::PseudoLA_TLS_DESC_LARGE
4662 : LoongArch::PseudoLA_TLS_DESC,
4663 Large);
4664}
4665
4666template <unsigned N>
4668 SelectionDAG &DAG, bool IsSigned = false) {
4669 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
4670 // Check the ImmArg.
4671 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
4672 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
4673 DAG.getContext()->emitError(Op->getOperationName(0) +
4674 ": argument out of range.");
4675 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
4676 }
4677 return SDValue();
4678}
4679
4680SDValue
4681LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
4682 SelectionDAG &DAG) const {
4683 switch (Op.getConstantOperandVal(0)) {
4684 default:
4685 return SDValue(); // Don't custom lower most intrinsics.
4686 case Intrinsic::thread_pointer: {
4687 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4688 return DAG.getRegister(LoongArch::R2, PtrVT);
4689 }
4690 case Intrinsic::loongarch_lsx_vpickve2gr_d:
4691 case Intrinsic::loongarch_lsx_vpickve2gr_du:
4692 case Intrinsic::loongarch_lsx_vreplvei_d:
4693 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
4694 return checkIntrinsicImmArg<1>(Op, 2, DAG);
4695 case Intrinsic::loongarch_lsx_vreplvei_w:
4696 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
4697 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
4698 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
4699 case Intrinsic::loongarch_lasx_xvpickve_d:
4700 case Intrinsic::loongarch_lasx_xvpickve_d_f:
4701 return checkIntrinsicImmArg<2>(Op, 2, DAG);
4702 case Intrinsic::loongarch_lasx_xvinsve0_d:
4703 return checkIntrinsicImmArg<2>(Op, 3, DAG);
4704 case Intrinsic::loongarch_lsx_vsat_b:
4705 case Intrinsic::loongarch_lsx_vsat_bu:
4706 case Intrinsic::loongarch_lsx_vrotri_b:
4707 case Intrinsic::loongarch_lsx_vsllwil_h_b:
4708 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
4709 case Intrinsic::loongarch_lsx_vsrlri_b:
4710 case Intrinsic::loongarch_lsx_vsrari_b:
4711 case Intrinsic::loongarch_lsx_vreplvei_h:
4712 case Intrinsic::loongarch_lasx_xvsat_b:
4713 case Intrinsic::loongarch_lasx_xvsat_bu:
4714 case Intrinsic::loongarch_lasx_xvrotri_b:
4715 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
4716 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
4717 case Intrinsic::loongarch_lasx_xvsrlri_b:
4718 case Intrinsic::loongarch_lasx_xvsrari_b:
4719 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
4720 case Intrinsic::loongarch_lasx_xvpickve_w:
4721 case Intrinsic::loongarch_lasx_xvpickve_w_f:
4722 return checkIntrinsicImmArg<3>(Op, 2, DAG);
4723 case Intrinsic::loongarch_lasx_xvinsve0_w:
4724 return checkIntrinsicImmArg<3>(Op, 3, DAG);
4725 case Intrinsic::loongarch_lsx_vsat_h:
4726 case Intrinsic::loongarch_lsx_vsat_hu:
4727 case Intrinsic::loongarch_lsx_vrotri_h:
4728 case Intrinsic::loongarch_lsx_vsllwil_w_h:
4729 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
4730 case Intrinsic::loongarch_lsx_vsrlri_h:
4731 case Intrinsic::loongarch_lsx_vsrari_h:
4732 case Intrinsic::loongarch_lsx_vreplvei_b:
4733 case Intrinsic::loongarch_lasx_xvsat_h:
4734 case Intrinsic::loongarch_lasx_xvsat_hu:
4735 case Intrinsic::loongarch_lasx_xvrotri_h:
4736 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
4737 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
4738 case Intrinsic::loongarch_lasx_xvsrlri_h:
4739 case Intrinsic::loongarch_lasx_xvsrari_h:
4740 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
4741 return checkIntrinsicImmArg<4>(Op, 2, DAG);
4742 case Intrinsic::loongarch_lsx_vsrlni_b_h:
4743 case Intrinsic::loongarch_lsx_vsrani_b_h:
4744 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
4745 case Intrinsic::loongarch_lsx_vsrarni_b_h:
4746 case Intrinsic::loongarch_lsx_vssrlni_b_h:
4747 case Intrinsic::loongarch_lsx_vssrani_b_h:
4748 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
4749 case Intrinsic::loongarch_lsx_vssrani_bu_h:
4750 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
4751 case Intrinsic::loongarch_lsx_vssrarni_b_h:
4752 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
4753 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
4754 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
4755 case Intrinsic::loongarch_lasx_xvsrani_b_h:
4756 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
4757 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
4758 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
4759 case Intrinsic::loongarch_lasx_xvssrani_b_h:
4760 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
4761 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
4762 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
4763 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
4764 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
4765 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
4766 return checkIntrinsicImmArg<4>(Op, 3, DAG);
4767 case Intrinsic::loongarch_lsx_vsat_w:
4768 case Intrinsic::loongarch_lsx_vsat_wu:
4769 case Intrinsic::loongarch_lsx_vrotri_w:
4770 case Intrinsic::loongarch_lsx_vsllwil_d_w:
4771 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
4772 case Intrinsic::loongarch_lsx_vsrlri_w:
4773 case Intrinsic::loongarch_lsx_vsrari_w:
4774 case Intrinsic::loongarch_lsx_vslei_bu:
4775 case Intrinsic::loongarch_lsx_vslei_hu:
4776 case Intrinsic::loongarch_lsx_vslei_wu:
4777 case Intrinsic::loongarch_lsx_vslei_du:
4778 case Intrinsic::loongarch_lsx_vslti_bu:
4779 case Intrinsic::loongarch_lsx_vslti_hu:
4780 case Intrinsic::loongarch_lsx_vslti_wu:
4781 case Intrinsic::loongarch_lsx_vslti_du:
4782 case Intrinsic::loongarch_lsx_vbsll_v:
4783 case Intrinsic::loongarch_lsx_vbsrl_v:
4784 case Intrinsic::loongarch_lasx_xvsat_w:
4785 case Intrinsic::loongarch_lasx_xvsat_wu:
4786 case Intrinsic::loongarch_lasx_xvrotri_w:
4787 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
4788 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
4789 case Intrinsic::loongarch_lasx_xvsrlri_w:
4790 case Intrinsic::loongarch_lasx_xvsrari_w:
4791 case Intrinsic::loongarch_lasx_xvslei_bu:
4792 case Intrinsic::loongarch_lasx_xvslei_hu:
4793 case Intrinsic::loongarch_lasx_xvslei_wu:
4794 case Intrinsic::loongarch_lasx_xvslei_du:
4795 case Intrinsic::loongarch_lasx_xvslti_bu:
4796 case Intrinsic::loongarch_lasx_xvslti_hu:
4797 case Intrinsic::loongarch_lasx_xvslti_wu:
4798 case Intrinsic::loongarch_lasx_xvslti_du:
4799 case Intrinsic::loongarch_lasx_xvbsll_v:
4800 case Intrinsic::loongarch_lasx_xvbsrl_v:
4801 return checkIntrinsicImmArg<5>(Op, 2, DAG);
4802 case Intrinsic::loongarch_lsx_vseqi_b:
4803 case Intrinsic::loongarch_lsx_vseqi_h:
4804 case Intrinsic::loongarch_lsx_vseqi_w:
4805 case Intrinsic::loongarch_lsx_vseqi_d:
4806 case Intrinsic::loongarch_lsx_vslei_b:
4807 case Intrinsic::loongarch_lsx_vslei_h:
4808 case Intrinsic::loongarch_lsx_vslei_w:
4809 case Intrinsic::loongarch_lsx_vslei_d:
4810 case Intrinsic::loongarch_lsx_vslti_b:
4811 case Intrinsic::loongarch_lsx_vslti_h:
4812 case Intrinsic::loongarch_lsx_vslti_w:
4813 case Intrinsic::loongarch_lsx_vslti_d:
4814 case Intrinsic::loongarch_lasx_xvseqi_b:
4815 case Intrinsic::loongarch_lasx_xvseqi_h:
4816 case Intrinsic::loongarch_lasx_xvseqi_w:
4817 case Intrinsic::loongarch_lasx_xvseqi_d:
4818 case Intrinsic::loongarch_lasx_xvslei_b:
4819 case Intrinsic::loongarch_lasx_xvslei_h:
4820 case Intrinsic::loongarch_lasx_xvslei_w:
4821 case Intrinsic::loongarch_lasx_xvslei_d:
4822 case Intrinsic::loongarch_lasx_xvslti_b:
4823 case Intrinsic::loongarch_lasx_xvslti_h:
4824 case Intrinsic::loongarch_lasx_xvslti_w:
4825 case Intrinsic::loongarch_lasx_xvslti_d:
4826 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
4827 case Intrinsic::loongarch_lsx_vsrlni_h_w:
4828 case Intrinsic::loongarch_lsx_vsrani_h_w:
4829 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
4830 case Intrinsic::loongarch_lsx_vsrarni_h_w:
4831 case Intrinsic::loongarch_lsx_vssrlni_h_w:
4832 case Intrinsic::loongarch_lsx_vssrani_h_w:
4833 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
4834 case Intrinsic::loongarch_lsx_vssrani_hu_w:
4835 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
4836 case Intrinsic::loongarch_lsx_vssrarni_h_w:
4837 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
4838 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
4839 case Intrinsic::loongarch_lsx_vfrstpi_b:
4840 case Intrinsic::loongarch_lsx_vfrstpi_h:
4841 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
4842 case Intrinsic::loongarch_lasx_xvsrani_h_w:
4843 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
4844 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
4845 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
4846 case Intrinsic::loongarch_lasx_xvssrani_h_w:
4847 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
4848 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
4849 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
4850 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
4851 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
4852 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
4853 case Intrinsic::loongarch_lasx_xvfrstpi_b:
4854 case Intrinsic::loongarch_lasx_xvfrstpi_h:
4855 return checkIntrinsicImmArg<5>(Op, 3, DAG);
4856 case Intrinsic::loongarch_lsx_vsat_d:
4857 case Intrinsic::loongarch_lsx_vsat_du:
4858 case Intrinsic::loongarch_lsx_vrotri_d:
4859 case Intrinsic::loongarch_lsx_vsrlri_d:
4860 case Intrinsic::loongarch_lsx_vsrari_d:
4861 case Intrinsic::loongarch_lasx_xvsat_d:
4862 case Intrinsic::loongarch_lasx_xvsat_du:
4863 case Intrinsic::loongarch_lasx_xvrotri_d:
4864 case Intrinsic::loongarch_lasx_xvsrlri_d:
4865 case Intrinsic::loongarch_lasx_xvsrari_d:
4866 return checkIntrinsicImmArg<6>(Op, 2, DAG);
4867 case Intrinsic::loongarch_lsx_vsrlni_w_d:
4868 case Intrinsic::loongarch_lsx_vsrani_w_d:
4869 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
4870 case Intrinsic::loongarch_lsx_vsrarni_w_d:
4871 case Intrinsic::loongarch_lsx_vssrlni_w_d:
4872 case Intrinsic::loongarch_lsx_vssrani_w_d:
4873 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
4874 case Intrinsic::loongarch_lsx_vssrani_wu_d:
4875 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
4876 case Intrinsic::loongarch_lsx_vssrarni_w_d:
4877 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
4878 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
4879 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
4880 case Intrinsic::loongarch_lasx_xvsrani_w_d:
4881 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
4882 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
4883 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
4884 case Intrinsic::loongarch_lasx_xvssrani_w_d:
4885 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
4886 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
4887 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
4888 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
4889 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
4890 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
4891 return checkIntrinsicImmArg<6>(Op, 3, DAG);
4892 case Intrinsic::loongarch_lsx_vsrlni_d_q:
4893 case Intrinsic::loongarch_lsx_vsrani_d_q:
4894 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
4895 case Intrinsic::loongarch_lsx_vsrarni_d_q:
4896 case Intrinsic::loongarch_lsx_vssrlni_d_q:
4897 case Intrinsic::loongarch_lsx_vssrani_d_q:
4898 case Intrinsic::loongarch_lsx_vssrlni_du_q:
4899 case Intrinsic::loongarch_lsx_vssrani_du_q:
4900 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
4901 case Intrinsic::loongarch_lsx_vssrarni_d_q:
4902 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
4903 case Intrinsic::loongarch_lsx_vssrarni_du_q:
4904 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
4905 case Intrinsic::loongarch_lasx_xvsrani_d_q:
4906 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
4907 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
4908 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
4909 case Intrinsic::loongarch_lasx_xvssrani_d_q:
4910 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
4911 case Intrinsic::loongarch_lasx_xvssrani_du_q:
4912 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
4913 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
4914 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
4915 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
4916 return checkIntrinsicImmArg<7>(Op, 3, DAG);
4917 case Intrinsic::loongarch_lsx_vnori_b:
4918 case Intrinsic::loongarch_lsx_vshuf4i_b:
4919 case Intrinsic::loongarch_lsx_vshuf4i_h:
4920 case Intrinsic::loongarch_lsx_vshuf4i_w:
4921 case Intrinsic::loongarch_lasx_xvnori_b:
4922 case Intrinsic::loongarch_lasx_xvshuf4i_b:
4923 case Intrinsic::loongarch_lasx_xvshuf4i_h:
4924 case Intrinsic::loongarch_lasx_xvshuf4i_w:
4925 case Intrinsic::loongarch_lasx_xvpermi_d:
4926 return checkIntrinsicImmArg<8>(Op, 2, DAG);
4927 case Intrinsic::loongarch_lsx_vshuf4i_d:
4928 case Intrinsic::loongarch_lsx_vpermi_w:
4929 case Intrinsic::loongarch_lsx_vbitseli_b:
4930 case Intrinsic::loongarch_lsx_vextrins_b:
4931 case Intrinsic::loongarch_lsx_vextrins_h:
4932 case Intrinsic::loongarch_lsx_vextrins_w:
4933 case Intrinsic::loongarch_lsx_vextrins_d:
4934 case Intrinsic::loongarch_lasx_xvshuf4i_d:
4935 case Intrinsic::loongarch_lasx_xvpermi_w:
4936 case Intrinsic::loongarch_lasx_xvpermi_q:
4937 case Intrinsic::loongarch_lasx_xvbitseli_b:
4938 case Intrinsic::loongarch_lasx_xvextrins_b:
4939 case Intrinsic::loongarch_lasx_xvextrins_h:
4940 case Intrinsic::loongarch_lasx_xvextrins_w:
4941 case Intrinsic::loongarch_lasx_xvextrins_d:
4942 return checkIntrinsicImmArg<8>(Op, 3, DAG);
4943 case Intrinsic::loongarch_lsx_vrepli_b:
4944 case Intrinsic::loongarch_lsx_vrepli_h:
4945 case Intrinsic::loongarch_lsx_vrepli_w:
4946 case Intrinsic::loongarch_lsx_vrepli_d:
4947 case Intrinsic::loongarch_lasx_xvrepli_b:
4948 case Intrinsic::loongarch_lasx_xvrepli_h:
4949 case Intrinsic::loongarch_lasx_xvrepli_w:
4950 case Intrinsic::loongarch_lasx_xvrepli_d:
4951 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
4952 case Intrinsic::loongarch_lsx_vldi:
4953 case Intrinsic::loongarch_lasx_xvldi:
4954 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
4955 }
4956}
4957
4958// Helper function that emits error message for intrinsics with chain and return
4959// merge values of a UNDEF and the chain.
4961 StringRef ErrorMsg,
4962 SelectionDAG &DAG) {
4963 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
4964 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
4965 SDLoc(Op));
4966}
4967
4968SDValue
4969LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
4970 SelectionDAG &DAG) const {
4971 SDLoc DL(Op);
4972 MVT GRLenVT = Subtarget.getGRLenVT();
4973 EVT VT = Op.getValueType();
4974 SDValue Chain = Op.getOperand(0);
4975 const StringRef ErrorMsgOOR = "argument out of range";
4976 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
4977 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
4978
4979 switch (Op.getConstantOperandVal(1)) {
4980 default:
4981 return Op;
4982 case Intrinsic::loongarch_crc_w_b_w:
4983 case Intrinsic::loongarch_crc_w_h_w:
4984 case Intrinsic::loongarch_crc_w_w_w:
4985 case Intrinsic::loongarch_crc_w_d_w:
4986 case Intrinsic::loongarch_crcc_w_b_w:
4987 case Intrinsic::loongarch_crcc_w_h_w:
4988 case Intrinsic::loongarch_crcc_w_w_w:
4989 case Intrinsic::loongarch_crcc_w_d_w:
4990 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
4991 case Intrinsic::loongarch_csrrd_w:
4992 case Intrinsic::loongarch_csrrd_d: {
4993 unsigned Imm = Op.getConstantOperandVal(2);
4994 return !isUInt<14>(Imm)
4995 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
4996 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
4997 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
4998 }
4999 case Intrinsic::loongarch_csrwr_w:
5000 case Intrinsic::loongarch_csrwr_d: {
5001 unsigned Imm = Op.getConstantOperandVal(3);
5002 return !isUInt<14>(Imm)
5003 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5004 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5005 {Chain, Op.getOperand(2),
5006 DAG.getConstant(Imm, DL, GRLenVT)});
5007 }
5008 case Intrinsic::loongarch_csrxchg_w:
5009 case Intrinsic::loongarch_csrxchg_d: {
5010 unsigned Imm = Op.getConstantOperandVal(4);
5011 return !isUInt<14>(Imm)
5012 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5013 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5014 {Chain, Op.getOperand(2), Op.getOperand(3),
5015 DAG.getConstant(Imm, DL, GRLenVT)});
5016 }
5017 case Intrinsic::loongarch_iocsrrd_d: {
5018 return DAG.getNode(
5019 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
5020 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
5021 }
5022#define IOCSRRD_CASE(NAME, NODE) \
5023 case Intrinsic::loongarch_##NAME: { \
5024 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
5025 {Chain, Op.getOperand(2)}); \
5026 }
5027 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5028 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5029 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5030#undef IOCSRRD_CASE
5031 case Intrinsic::loongarch_cpucfg: {
5032 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5033 {Chain, Op.getOperand(2)});
5034 }
5035 case Intrinsic::loongarch_lddir_d: {
5036 unsigned Imm = Op.getConstantOperandVal(3);
5037 return !isUInt<8>(Imm)
5038 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5039 : Op;
5040 }
5041 case Intrinsic::loongarch_movfcsr2gr: {
5042 if (!Subtarget.hasBasicF())
5043 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
5044 unsigned Imm = Op.getConstantOperandVal(2);
5045 return !isUInt<2>(Imm)
5046 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5047 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
5048 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5049 }
5050 case Intrinsic::loongarch_lsx_vld:
5051 case Intrinsic::loongarch_lsx_vldrepl_b:
5052 case Intrinsic::loongarch_lasx_xvld:
5053 case Intrinsic::loongarch_lasx_xvldrepl_b:
5054 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5055 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
5056 : SDValue();
5057 case Intrinsic::loongarch_lsx_vldrepl_h:
5058 case Intrinsic::loongarch_lasx_xvldrepl_h:
5059 return !isShiftedInt<11, 1>(
5060 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5062 Op, "argument out of range or not a multiple of 2", DAG)
5063 : SDValue();
5064 case Intrinsic::loongarch_lsx_vldrepl_w:
5065 case Intrinsic::loongarch_lasx_xvldrepl_w:
5066 return !isShiftedInt<10, 2>(
5067 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5069 Op, "argument out of range or not a multiple of 4", DAG)
5070 : SDValue();
5071 case Intrinsic::loongarch_lsx_vldrepl_d:
5072 case Intrinsic::loongarch_lasx_xvldrepl_d:
5073 return !isShiftedInt<9, 3>(
5074 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
5076 Op, "argument out of range or not a multiple of 8", DAG)
5077 : SDValue();
5078 }
5079}
5080
5081// Helper function that emits error message for intrinsics with void return
5082// value and return the chain.
5084 SelectionDAG &DAG) {
5085
5086 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
5087 return Op.getOperand(0);
5088}
5089
5090SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
5091 SelectionDAG &DAG) const {
5092 SDLoc DL(Op);
5093 MVT GRLenVT = Subtarget.getGRLenVT();
5094 SDValue Chain = Op.getOperand(0);
5095 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
5096 SDValue Op2 = Op.getOperand(2);
5097 const StringRef ErrorMsgOOR = "argument out of range";
5098 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5099 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
5100 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5101
5102 switch (IntrinsicEnum) {
5103 default:
5104 // TODO: Add more Intrinsics.
5105 return SDValue();
5106 case Intrinsic::loongarch_cacop_d:
5107 case Intrinsic::loongarch_cacop_w: {
5108 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
5109 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
5110 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
5111 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
5112 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
5113 unsigned Imm1 = Op2->getAsZExtVal();
5114 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
5115 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
5116 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
5117 return Op;
5118 }
5119 case Intrinsic::loongarch_dbar: {
5120 unsigned Imm = Op2->getAsZExtVal();
5121 return !isUInt<15>(Imm)
5122 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5123 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
5124 DAG.getConstant(Imm, DL, GRLenVT));
5125 }
5126 case Intrinsic::loongarch_ibar: {
5127 unsigned Imm = Op2->getAsZExtVal();
5128 return !isUInt<15>(Imm)
5129 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5130 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
5131 DAG.getConstant(Imm, DL, GRLenVT));
5132 }
5133 case Intrinsic::loongarch_break: {
5134 unsigned Imm = Op2->getAsZExtVal();
5135 return !isUInt<15>(Imm)
5136 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5137 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
5138 DAG.getConstant(Imm, DL, GRLenVT));
5139 }
5140 case Intrinsic::loongarch_movgr2fcsr: {
5141 if (!Subtarget.hasBasicF())
5142 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
5143 unsigned Imm = Op2->getAsZExtVal();
5144 return !isUInt<2>(Imm)
5145 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5146 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
5147 DAG.getConstant(Imm, DL, GRLenVT),
5148 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
5149 Op.getOperand(3)));
5150 }
5151 case Intrinsic::loongarch_syscall: {
5152 unsigned Imm = Op2->getAsZExtVal();
5153 return !isUInt<15>(Imm)
5154 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5155 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
5156 DAG.getConstant(Imm, DL, GRLenVT));
5157 }
5158#define IOCSRWR_CASE(NAME, NODE) \
5159 case Intrinsic::loongarch_##NAME: { \
5160 SDValue Op3 = Op.getOperand(3); \
5161 return Subtarget.is64Bit() \
5162 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
5163 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5164 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
5165 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
5166 Op3); \
5167 }
5168 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
5169 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
5170 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
5171#undef IOCSRWR_CASE
5172 case Intrinsic::loongarch_iocsrwr_d: {
5173 return !Subtarget.is64Bit()
5174 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5175 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
5176 Op2,
5177 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
5178 Op.getOperand(3)));
5179 }
5180#define ASRT_LE_GT_CASE(NAME) \
5181 case Intrinsic::loongarch_##NAME: { \
5182 return !Subtarget.is64Bit() \
5183 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
5184 : Op; \
5185 }
5186 ASRT_LE_GT_CASE(asrtle_d)
5187 ASRT_LE_GT_CASE(asrtgt_d)
5188#undef ASRT_LE_GT_CASE
5189 case Intrinsic::loongarch_ldpte_d: {
5190 unsigned Imm = Op.getConstantOperandVal(3);
5191 return !Subtarget.is64Bit()
5192 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
5193 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5194 : Op;
5195 }
5196 case Intrinsic::loongarch_lsx_vst:
5197 case Intrinsic::loongarch_lasx_xvst:
5198 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
5199 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5200 : SDValue();
5201 case Intrinsic::loongarch_lasx_xvstelm_b:
5202 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5203 !isUInt<5>(Op.getConstantOperandVal(5)))
5204 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5205 : SDValue();
5206 case Intrinsic::loongarch_lsx_vstelm_b:
5207 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5208 !isUInt<4>(Op.getConstantOperandVal(5)))
5209 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
5210 : SDValue();
5211 case Intrinsic::loongarch_lasx_xvstelm_h:
5212 return (!isShiftedInt<8, 1>(
5213 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5214 !isUInt<4>(Op.getConstantOperandVal(5)))
5216 Op, "argument out of range or not a multiple of 2", DAG)
5217 : SDValue();
5218 case Intrinsic::loongarch_lsx_vstelm_h:
5219 return (!isShiftedInt<8, 1>(
5220 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5221 !isUInt<3>(Op.getConstantOperandVal(5)))
5223 Op, "argument out of range or not a multiple of 2", DAG)
5224 : SDValue();
5225 case Intrinsic::loongarch_lasx_xvstelm_w:
5226 return (!isShiftedInt<8, 2>(
5227 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5228 !isUInt<3>(Op.getConstantOperandVal(5)))
5230 Op, "argument out of range or not a multiple of 4", DAG)
5231 : SDValue();
5232 case Intrinsic::loongarch_lsx_vstelm_w:
5233 return (!isShiftedInt<8, 2>(
5234 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5235 !isUInt<2>(Op.getConstantOperandVal(5)))
5237 Op, "argument out of range or not a multiple of 4", DAG)
5238 : SDValue();
5239 case Intrinsic::loongarch_lasx_xvstelm_d:
5240 return (!isShiftedInt<8, 3>(
5241 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5242 !isUInt<2>(Op.getConstantOperandVal(5)))
5244 Op, "argument out of range or not a multiple of 8", DAG)
5245 : SDValue();
5246 case Intrinsic::loongarch_lsx_vstelm_d:
5247 return (!isShiftedInt<8, 3>(
5248 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
5249 !isUInt<1>(Op.getConstantOperandVal(5)))
5251 Op, "argument out of range or not a multiple of 8", DAG)
5252 : SDValue();
5253 }
5254}
5255
5256SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
5257 SelectionDAG &DAG) const {
5258 SDLoc DL(Op);
5259 SDValue Lo = Op.getOperand(0);
5260 SDValue Hi = Op.getOperand(1);
5261 SDValue Shamt = Op.getOperand(2);
5262 EVT VT = Lo.getValueType();
5263
5264 // if Shamt-GRLen < 0: // Shamt < GRLen
5265 // Lo = Lo << Shamt
5266 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
5267 // else:
5268 // Lo = 0
5269 // Hi = Lo << (Shamt-GRLen)
5270
5271 SDValue Zero = DAG.getConstant(0, DL, VT);
5272 SDValue One = DAG.getConstant(1, DL, VT);
5273 SDValue MinusGRLen =
5274 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5275 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5276 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5277 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5278
5279 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
5280 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
5281 SDValue ShiftRightLo =
5282 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
5283 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
5284 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
5285 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
5286
5287 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5288
5289 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
5290 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5291
5292 SDValue Parts[2] = {Lo, Hi};
5293 return DAG.getMergeValues(Parts, DL);
5294}
5295
5296SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
5297 SelectionDAG &DAG,
5298 bool IsSRA) const {
5299 SDLoc DL(Op);
5300 SDValue Lo = Op.getOperand(0);
5301 SDValue Hi = Op.getOperand(1);
5302 SDValue Shamt = Op.getOperand(2);
5303 EVT VT = Lo.getValueType();
5304
5305 // SRA expansion:
5306 // if Shamt-GRLen < 0: // Shamt < GRLen
5307 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5308 // Hi = Hi >>s Shamt
5309 // else:
5310 // Lo = Hi >>s (Shamt-GRLen);
5311 // Hi = Hi >>s (GRLen-1)
5312 //
5313 // SRL expansion:
5314 // if Shamt-GRLen < 0: // Shamt < GRLen
5315 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
5316 // Hi = Hi >>u Shamt
5317 // else:
5318 // Lo = Hi >>u (Shamt-GRLen);
5319 // Hi = 0;
5320
5321 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
5322
5323 SDValue Zero = DAG.getConstant(0, DL, VT);
5324 SDValue One = DAG.getConstant(1, DL, VT);
5325 SDValue MinusGRLen =
5326 DAG.getSignedConstant(-(int)Subtarget.getGRLen(), DL, VT);
5327 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
5328 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
5329 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
5330
5331 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
5332 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
5333 SDValue ShiftLeftHi =
5334 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
5335 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
5336 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
5337 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
5338 SDValue HiFalse =
5339 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
5340
5341 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
5342
5343 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
5344 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
5345
5346 SDValue Parts[2] = {Lo, Hi};
5347 return DAG.getMergeValues(Parts, DL);
5348}
5349
5350// Returns the opcode of the target-specific SDNode that implements the 32-bit
5351// form of the given Opcode.
5352static unsigned getLoongArchWOpcode(unsigned Opcode) {
5353 switch (Opcode) {
5354 default:
5355 llvm_unreachable("Unexpected opcode");
5356 case ISD::SDIV:
5357 return LoongArchISD::DIV_W;
5358 case ISD::UDIV:
5359 return LoongArchISD::DIV_WU;
5360 case ISD::SREM:
5361 return LoongArchISD::MOD_W;
5362 case ISD::UREM:
5363 return LoongArchISD::MOD_WU;
5364 case ISD::SHL:
5365 return LoongArchISD::SLL_W;
5366 case ISD::SRA:
5367 return LoongArchISD::SRA_W;
5368 case ISD::SRL:
5369 return LoongArchISD::SRL_W;
5370 case ISD::ROTL:
5371 case ISD::ROTR:
5372 return LoongArchISD::ROTR_W;
5373 case ISD::CTTZ:
5374 return LoongArchISD::CTZ_W;
5375 case ISD::CTLZ:
5376 return LoongArchISD::CLZ_W;
5377 }
5378}
5379
5380// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
5381// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
5382// otherwise be promoted to i64, making it difficult to select the
5383// SLL_W/.../*W later one because the fact the operation was originally of
5384// type i8/i16/i32 is lost.
5386 unsigned ExtOpc = ISD::ANY_EXTEND) {
5387 SDLoc DL(N);
5388 unsigned WOpcode = getLoongArchWOpcode(N->getOpcode());
5389 SDValue NewOp0, NewRes;
5390
5391 switch (NumOp) {
5392 default:
5393 llvm_unreachable("Unexpected NumOp");
5394 case 1: {
5395 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5396 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
5397 break;
5398 }
5399 case 2: {
5400 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
5401 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
5402 if (N->getOpcode() == ISD::ROTL) {
5403 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
5404 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
5405 }
5406 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
5407 break;
5408 }
5409 // TODO:Handle more NumOp.
5410 }
5411
5412 // ReplaceNodeResults requires we maintain the same type for the return
5413 // value.
5414 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
5415}
5416
5417// Converts the given 32-bit operation to a i64 operation with signed extension
5418// semantic to reduce the signed extension instructions.
5420 SDLoc DL(N);
5421 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
5422 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
5423 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
5424 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
5425 DAG.getValueType(MVT::i32));
5426 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
5427}
5428
5429// Helper function that emits error message for intrinsics with/without chain
5430// and return a UNDEF or and the chain as the results.
5433 StringRef ErrorMsg, bool WithChain = true) {
5434 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
5435 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
5436 if (!WithChain)
5437 return;
5438 Results.push_back(N->getOperand(0));
5439}
5440
5441template <unsigned N>
5442static void
5444 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
5445 unsigned ResOp) {
5446 const StringRef ErrorMsgOOR = "argument out of range";
5447 unsigned Imm = Node->getConstantOperandVal(2);
5448 if (!isUInt<N>(Imm)) {
5450 /*WithChain=*/false);
5451 return;
5452 }
5453 SDLoc DL(Node);
5454 SDValue Vec = Node->getOperand(1);
5455
5456 SDValue PickElt =
5457 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
5458 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
5460 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
5461 PickElt.getValue(0)));
5462}
5463
5466 SelectionDAG &DAG,
5467 const LoongArchSubtarget &Subtarget,
5468 unsigned ResOp) {
5469 SDLoc DL(N);
5470 SDValue Vec = N->getOperand(1);
5471
5472 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
5473 Results.push_back(
5474 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
5475}
5476
5477static void
5479 SelectionDAG &DAG,
5480 const LoongArchSubtarget &Subtarget) {
5481 switch (N->getConstantOperandVal(0)) {
5482 default:
5483 llvm_unreachable("Unexpected Intrinsic.");
5484 case Intrinsic::loongarch_lsx_vpickve2gr_b:
5485 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5486 LoongArchISD::VPICK_SEXT_ELT);
5487 break;
5488 case Intrinsic::loongarch_lsx_vpickve2gr_h:
5489 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
5490 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5491 LoongArchISD::VPICK_SEXT_ELT);
5492 break;
5493 case Intrinsic::loongarch_lsx_vpickve2gr_w:
5494 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5495 LoongArchISD::VPICK_SEXT_ELT);
5496 break;
5497 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
5498 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
5499 LoongArchISD::VPICK_ZEXT_ELT);
5500 break;
5501 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
5502 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
5503 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
5504 LoongArchISD::VPICK_ZEXT_ELT);
5505 break;
5506 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
5507 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
5508 LoongArchISD::VPICK_ZEXT_ELT);
5509 break;
5510 case Intrinsic::loongarch_lsx_bz_b:
5511 case Intrinsic::loongarch_lsx_bz_h:
5512 case Intrinsic::loongarch_lsx_bz_w:
5513 case Intrinsic::loongarch_lsx_bz_d:
5514 case Intrinsic::loongarch_lasx_xbz_b:
5515 case Intrinsic::loongarch_lasx_xbz_h:
5516 case Intrinsic::loongarch_lasx_xbz_w:
5517 case Intrinsic::loongarch_lasx_xbz_d:
5518 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5519 LoongArchISD::VALL_ZERO);
5520 break;
5521 case Intrinsic::loongarch_lsx_bz_v:
5522 case Intrinsic::loongarch_lasx_xbz_v:
5523 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5524 LoongArchISD::VANY_ZERO);
5525 break;
5526 case Intrinsic::loongarch_lsx_bnz_b:
5527 case Intrinsic::loongarch_lsx_bnz_h:
5528 case Intrinsic::loongarch_lsx_bnz_w:
5529 case Intrinsic::loongarch_lsx_bnz_d:
5530 case Intrinsic::loongarch_lasx_xbnz_b:
5531 case Intrinsic::loongarch_lasx_xbnz_h:
5532 case Intrinsic::loongarch_lasx_xbnz_w:
5533 case Intrinsic::loongarch_lasx_xbnz_d:
5534 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5535 LoongArchISD::VALL_NONZERO);
5536 break;
5537 case Intrinsic::loongarch_lsx_bnz_v:
5538 case Intrinsic::loongarch_lasx_xbnz_v:
5539 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
5540 LoongArchISD::VANY_NONZERO);
5541 break;
5542 }
5543}
5544
5547 SelectionDAG &DAG) {
5548 assert(N->getValueType(0) == MVT::i128 &&
5549 "AtomicCmpSwap on types less than 128 should be legal");
5550 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
5551
5552 unsigned Opcode;
5553 switch (MemOp->getMergedOrdering()) {
5557 Opcode = LoongArch::PseudoCmpXchg128Acquire;
5558 break;
5561 Opcode = LoongArch::PseudoCmpXchg128;
5562 break;
5563 default:
5564 llvm_unreachable("Unexpected ordering!");
5565 }
5566
5567 SDLoc DL(N);
5568 auto CmpVal = DAG.SplitScalar(N->getOperand(2), DL, MVT::i64, MVT::i64);
5569 auto NewVal = DAG.SplitScalar(N->getOperand(3), DL, MVT::i64, MVT::i64);
5570 SDValue Ops[] = {N->getOperand(1), CmpVal.first, CmpVal.second,
5571 NewVal.first, NewVal.second, N->getOperand(0)};
5572
5573 SDNode *CmpSwap = DAG.getMachineNode(
5574 Opcode, SDLoc(N), DAG.getVTList(MVT::i64, MVT::i64, MVT::i64, MVT::Other),
5575 Ops);
5576 DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
5577 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
5578 SDValue(CmpSwap, 0), SDValue(CmpSwap, 1)));
5579 Results.push_back(SDValue(CmpSwap, 3));
5580}
5581
5584 SDLoc DL(N);
5585 EVT VT = N->getValueType(0);
5586 switch (N->getOpcode()) {
5587 default:
5588 llvm_unreachable("Don't know how to legalize this operation");
5589 case ISD::ADD:
5590 case ISD::SUB:
5591 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
5592 "Unexpected custom legalisation");
5593 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
5594 break;
5595 case ISD::SDIV:
5596 case ISD::UDIV:
5597 case ISD::SREM:
5598 case ISD::UREM:
5599 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5600 "Unexpected custom legalisation");
5601 Results.push_back(customLegalizeToWOp(N, DAG, 2,
5602 Subtarget.hasDiv32() && VT == MVT::i32
5604 : ISD::SIGN_EXTEND));
5605 break;
5606 case ISD::SHL:
5607 case ISD::SRA:
5608 case ISD::SRL:
5609 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5610 "Unexpected custom legalisation");
5611 if (N->getOperand(1).getOpcode() != ISD::Constant) {
5612 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5613 break;
5614 }
5615 break;
5616 case ISD::ROTL:
5617 case ISD::ROTR:
5618 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5619 "Unexpected custom legalisation");
5620 Results.push_back(customLegalizeToWOp(N, DAG, 2));
5621 break;
5622 case ISD::LOAD: {
5623 // Use an f64 load and a scalar_to_vector for v2f32 loads. This avoids
5624 // scalarizing in 32-bit mode. In 64-bit mode this avoids a int->fp
5625 // cast since type legalization will try to use an i64 load.
5626 MVT VT = N->getSimpleValueType(0);
5627 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5628 "Unexpected custom legalisation");
5630 "Unexpected type action!");
5631 if (!ISD::isNON_EXTLoad(N))
5632 return;
5633 auto *Ld = cast<LoadSDNode>(N);
5634 SDValue Res = DAG.getLoad(MVT::f64, DL, Ld->getChain(), Ld->getBasePtr(),
5635 Ld->getPointerInfo(), Ld->getBaseAlign(),
5636 Ld->getMemOperand()->getFlags());
5637 SDValue Chain = Res.getValue(1);
5638 MVT VecVT = MVT::getVectorVT(MVT::f64, 2);
5639 Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, Res);
5640 EVT WideVT = getTypeToTransformTo(*DAG.getContext(), VT);
5641 Res = DAG.getBitcast(WideVT, Res);
5642 Results.push_back(Res);
5643 Results.push_back(Chain);
5644 break;
5645 }
5646 case ISD::FP_TO_SINT: {
5647 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5648 "Unexpected custom legalisation");
5649 SDValue Src = N->getOperand(0);
5650 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
5651 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
5653 if (!isTypeLegal(Src.getValueType()))
5654 return;
5655 if (Src.getValueType() == MVT::f16)
5656 Src = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
5657 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
5658 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
5659 return;
5660 }
5661 // If the FP type needs to be softened, emit a library call using the 'si'
5662 // version. If we left it to default legalization we'd end up with 'di'.
5663 RTLIB::Libcall LC;
5664 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
5665 MakeLibCallOptions CallOptions;
5666 EVT OpVT = Src.getValueType();
5667 CallOptions.setTypeListBeforeSoften(OpVT, VT);
5668 SDValue Chain = SDValue();
5669 SDValue Result;
5670 std::tie(Result, Chain) =
5671 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
5672 Results.push_back(Result);
5673 break;
5674 }
5675 case ISD::BITCAST: {
5676 SDValue Src = N->getOperand(0);
5677 EVT SrcVT = Src.getValueType();
5678 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
5679 Subtarget.hasBasicF()) {
5680 SDValue Dst =
5681 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
5682 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
5683 } else if (VT == MVT::i64 && SrcVT == MVT::f64 && !Subtarget.is64Bit()) {
5684 SDValue NewReg = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
5685 DAG.getVTList(MVT::i32, MVT::i32), Src);
5686 SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
5687 NewReg.getValue(0), NewReg.getValue(1));
5688 Results.push_back(RetReg);
5689 }
5690 break;
5691 }
5692 case ISD::FP_TO_UINT: {
5693 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5694 "Unexpected custom legalisation");
5695 auto &TLI = DAG.getTargetLoweringInfo();
5696 SDValue Tmp1, Tmp2;
5697 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
5698 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
5699 break;
5700 }
5701 case ISD::FP_ROUND: {
5702 assert(VT == MVT::v2f32 && Subtarget.hasExtLSX() &&
5703 "Unexpected custom legalisation");
5704 // On LSX platforms, rounding from v2f64 to v4f32 (after legalization from
5705 // v2f32) is scalarized. Add a customized v2f32 widening to convert it into
5706 // a target-specific LoongArchISD::VFCVT to optimize it.
5707 SDValue Op0 = N->getOperand(0);
5708 EVT OpVT = Op0.getValueType();
5709 if (OpVT == MVT::v2f64) {
5710 SDValue Undef = DAG.getUNDEF(OpVT);
5711 SDValue Dst =
5712 DAG.getNode(LoongArchISD::VFCVT, DL, MVT::v4f32, Undef, Op0);
5713 Results.push_back(Dst);
5714 }
5715 break;
5716 }
5717 case ISD::BSWAP: {
5718 SDValue Src = N->getOperand(0);
5719 assert((VT == MVT::i16 || VT == MVT::i32) &&
5720 "Unexpected custom legalization");
5721 MVT GRLenVT = Subtarget.getGRLenVT();
5722 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5723 SDValue Tmp;
5724 switch (VT.getSizeInBits()) {
5725 default:
5726 llvm_unreachable("Unexpected operand width");
5727 case 16:
5728 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
5729 break;
5730 case 32:
5731 // Only LA64 will get to here due to the size mismatch between VT and
5732 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
5733 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
5734 break;
5735 }
5736 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5737 break;
5738 }
5739 case ISD::BITREVERSE: {
5740 SDValue Src = N->getOperand(0);
5741 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
5742 "Unexpected custom legalization");
5743 MVT GRLenVT = Subtarget.getGRLenVT();
5744 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
5745 SDValue Tmp;
5746 switch (VT.getSizeInBits()) {
5747 default:
5748 llvm_unreachable("Unexpected operand width");
5749 case 8:
5750 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
5751 break;
5752 case 32:
5753 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
5754 break;
5755 }
5756 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
5757 break;
5758 }
5759 case ISD::CTLZ:
5760 case ISD::CTTZ: {
5761 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
5762 "Unexpected custom legalisation");
5763 Results.push_back(customLegalizeToWOp(N, DAG, 1));
5764 break;
5765 }
5767 SDValue Chain = N->getOperand(0);
5768 SDValue Op2 = N->getOperand(2);
5769 MVT GRLenVT = Subtarget.getGRLenVT();
5770 const StringRef ErrorMsgOOR = "argument out of range";
5771 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
5772 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
5773
5774 switch (N->getConstantOperandVal(1)) {
5775 default:
5776 llvm_unreachable("Unexpected Intrinsic.");
5777 case Intrinsic::loongarch_movfcsr2gr: {
5778 if (!Subtarget.hasBasicF()) {
5779 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
5780 return;
5781 }
5782 unsigned Imm = Op2->getAsZExtVal();
5783 if (!isUInt<2>(Imm)) {
5784 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5785 return;
5786 }
5787 SDValue MOVFCSR2GRResults = DAG.getNode(
5788 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
5789 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5790 Results.push_back(
5791 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
5792 Results.push_back(MOVFCSR2GRResults.getValue(1));
5793 break;
5794 }
5795#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
5796 case Intrinsic::loongarch_##NAME: { \
5797 SDValue NODE = DAG.getNode( \
5798 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5799 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
5800 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5801 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5802 Results.push_back(NODE.getValue(1)); \
5803 break; \
5804 }
5805 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
5806 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
5807 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
5808 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
5809 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
5810 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
5811#undef CRC_CASE_EXT_BINARYOP
5812
5813#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
5814 case Intrinsic::loongarch_##NAME: { \
5815 SDValue NODE = DAG.getNode( \
5816 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5817 {Chain, Op2, \
5818 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
5819 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
5820 Results.push_back(NODE.getValue(1)); \
5821 break; \
5822 }
5823 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
5824 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
5825#undef CRC_CASE_EXT_UNARYOP
5826#define CSR_CASE(ID) \
5827 case Intrinsic::loongarch_##ID: { \
5828 if (!Subtarget.is64Bit()) \
5829 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
5830 break; \
5831 }
5832 CSR_CASE(csrrd_d);
5833 CSR_CASE(csrwr_d);
5834 CSR_CASE(csrxchg_d);
5835 CSR_CASE(iocsrrd_d);
5836#undef CSR_CASE
5837 case Intrinsic::loongarch_csrrd_w: {
5838 unsigned Imm = Op2->getAsZExtVal();
5839 if (!isUInt<14>(Imm)) {
5840 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5841 return;
5842 }
5843 SDValue CSRRDResults =
5844 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
5845 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
5846 Results.push_back(
5847 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
5848 Results.push_back(CSRRDResults.getValue(1));
5849 break;
5850 }
5851 case Intrinsic::loongarch_csrwr_w: {
5852 unsigned Imm = N->getConstantOperandVal(3);
5853 if (!isUInt<14>(Imm)) {
5854 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5855 return;
5856 }
5857 SDValue CSRWRResults =
5858 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
5859 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5860 DAG.getConstant(Imm, DL, GRLenVT)});
5861 Results.push_back(
5862 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
5863 Results.push_back(CSRWRResults.getValue(1));
5864 break;
5865 }
5866 case Intrinsic::loongarch_csrxchg_w: {
5867 unsigned Imm = N->getConstantOperandVal(4);
5868 if (!isUInt<14>(Imm)) {
5869 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
5870 return;
5871 }
5872 SDValue CSRXCHGResults = DAG.getNode(
5873 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
5874 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
5875 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
5876 DAG.getConstant(Imm, DL, GRLenVT)});
5877 Results.push_back(
5878 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
5879 Results.push_back(CSRXCHGResults.getValue(1));
5880 break;
5881 }
5882#define IOCSRRD_CASE(NAME, NODE) \
5883 case Intrinsic::loongarch_##NAME: { \
5884 SDValue IOCSRRDResults = \
5885 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
5886 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
5887 Results.push_back( \
5888 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
5889 Results.push_back(IOCSRRDResults.getValue(1)); \
5890 break; \
5891 }
5892 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
5893 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
5894 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
5895#undef IOCSRRD_CASE
5896 case Intrinsic::loongarch_cpucfg: {
5897 SDValue CPUCFGResults =
5898 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
5899 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
5900 Results.push_back(
5901 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
5902 Results.push_back(CPUCFGResults.getValue(1));
5903 break;
5904 }
5905 case Intrinsic::loongarch_lddir_d: {
5906 if (!Subtarget.is64Bit()) {
5907 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
5908 return;
5909 }
5910 break;
5911 }
5912 }
5913 break;
5914 }
5915 case ISD::READ_REGISTER: {
5916 if (Subtarget.is64Bit())
5917 DAG.getContext()->emitError(
5918 "On LA64, only 64-bit registers can be read.");
5919 else
5920 DAG.getContext()->emitError(
5921 "On LA32, only 32-bit registers can be read.");
5922 Results.push_back(DAG.getUNDEF(VT));
5923 Results.push_back(N->getOperand(0));
5924 break;
5925 }
5927 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
5928 break;
5929 }
5930 case ISD::LROUND: {
5931 SDValue Op0 = N->getOperand(0);
5932 EVT OpVT = Op0.getValueType();
5933 RTLIB::Libcall LC =
5934 OpVT == MVT::f64 ? RTLIB::LROUND_F64 : RTLIB::LROUND_F32;
5935 MakeLibCallOptions CallOptions;
5936 CallOptions.setTypeListBeforeSoften(OpVT, MVT::i64);
5937 SDValue Result = makeLibCall(DAG, LC, MVT::i64, Op0, CallOptions, DL).first;
5938 Result = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Result);
5939 Results.push_back(Result);
5940 break;
5941 }
5942 case ISD::ATOMIC_CMP_SWAP: {
5944 break;
5945 }
5946 case ISD::TRUNCATE: {
5947 MVT VT = N->getSimpleValueType(0);
5948 if (getTypeAction(*DAG.getContext(), VT) != TypeWidenVector)
5949 return;
5950
5951 MVT WidenVT = getTypeToTransformTo(*DAG.getContext(), VT).getSimpleVT();
5952 SDValue In = N->getOperand(0);
5953 EVT InVT = In.getValueType();
5954 EVT InEltVT = InVT.getVectorElementType();
5955 EVT EltVT = VT.getVectorElementType();
5956 unsigned MinElts = VT.getVectorNumElements();
5957 unsigned WidenNumElts = WidenVT.getVectorNumElements();
5958 unsigned InBits = InVT.getSizeInBits();
5959
5960 // v8i64 -> (v8i32) -> v8i8
5961 if (InVT == MVT::v8i64 && WidenVT.is128BitVector()) {
5962 InVT = MVT::getVectorVT(MVT::getIntegerVT(256 / MinElts), MinElts);
5963 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
5964 InBits = 256;
5965 }
5966
5967 // v8i32 -> v8i8 / v4i64 -> v4i16 / v4i64 -> v4i8
5968 if ((InVT == MVT::v8i32 || InVT == MVT::v4i64) &&
5969 WidenVT.is128BitVector()) {
5970 InVT = MVT::getVectorVT(MVT::getIntegerVT(128 / MinElts), MinElts);
5971 In = DAG.getNode(N->getOpcode(), DL, InVT, In);
5972 InBits = 128;
5973 InEltVT = InVT.getVectorElementType();
5974 }
5975
5976 if ((128 % InBits) == 0 && WidenVT.is128BitVector()) {
5977 if ((InEltVT.getSizeInBits() % EltVT.getSizeInBits()) == 0) {
5978 int Scale = InEltVT.getSizeInBits() / EltVT.getSizeInBits();
5979 SmallVector<int, 16> TruncMask(WidenNumElts, -1);
5980 for (unsigned I = 0; I < MinElts; ++I)
5981 TruncMask[I] = Scale * I;
5982
5983 unsigned WidenNumElts = 128 / In.getScalarValueSizeInBits();
5984 MVT SVT = In.getSimpleValueType().getScalarType();
5985 MVT VT = MVT::getVectorVT(SVT, WidenNumElts);
5986 SDValue WidenIn =
5987 DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, DAG.getUNDEF(VT), In,
5988 DAG.getVectorIdxConstant(0, DL));
5989 assert(isTypeLegal(WidenVT) && isTypeLegal(WidenIn.getValueType()) &&
5990 "Illegal vector type in truncation");
5991 WidenIn = DAG.getBitcast(WidenVT, WidenIn);
5992 Results.push_back(
5993 DAG.getVectorShuffle(WidenVT, DL, WidenIn, WidenIn, TruncMask));
5994 return;
5995 }
5996 }
5997
5998 break;
5999 }
6000 case ISD::SIGN_EXTEND: {
6001 // LASX has native VEXT2XV_* for sign extension.
6002 if (!Subtarget.hasExtLSX() || Subtarget.hasExtLASX())
6003 return;
6004
6005 EVT DstVT = N->getValueType(0);
6006 SDValue Src = N->getOperand(0);
6007 MVT SrcVT = Src.getSimpleValueType();
6008
6009 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
6010 unsigned DstEltBits = DstVT.getScalarSizeInBits();
6011 unsigned NumElts = DstVT.getVectorNumElements();
6012
6013 if (SrcVT.getSizeInBits() > 128)
6014 return;
6015
6016 if (!DstVT.isVector() || DstVT.getSizeInBits() <= 128)
6017 return;
6018
6019 // Legalize and extend the src to 128-bit first.
6020 if (SrcVT.getSizeInBits() < 128) {
6021 unsigned WidenSrcElts = 128 / SrcEltBits;
6022 MVT WidenSrcVT = MVT::getVectorVT(SrcVT.getScalarType(), WidenSrcElts);
6023 Src = DAG.getNode(ISD::INSERT_SUBVECTOR, DL, WidenSrcVT,
6024 DAG.getUNDEF(WidenSrcVT), Src,
6025 DAG.getVectorIdxConstant(0, DL));
6026 SrcVT = WidenSrcVT;
6027
6028 unsigned FirstStageEltBits = 128 / NumElts;
6029 MVT FirstStageEltVT = MVT::getIntegerVT(FirstStageEltBits);
6030 MVT FirstStageVT = MVT::getVectorVT(FirstStageEltVT, NumElts);
6031 Src = DAG.getNode(ISD::SIGN_EXTEND_VECTOR_INREG, DL, FirstStageVT, Src);
6032 SrcVT = FirstStageVT;
6033 SrcEltBits = FirstStageEltBits;
6034 }
6035
6037 Blocks.push_back(Src);
6038
6039 // Sign-extend the src by using SLTI + VILVL + VILVH recursively.
6040 while (SrcEltBits < DstEltBits) {
6041 unsigned NextEltBits = SrcEltBits * 2;
6042 MVT NextEltVT = MVT::getIntegerVT(NextEltBits);
6043 unsigned CurEltsPerBlock = SrcVT.getVectorNumElements();
6044 unsigned NextEltsPerBlock = CurEltsPerBlock / 2;
6045 MVT NextBlockVT = MVT::getVectorVT(NextEltVT, NextEltsPerBlock);
6046
6047 SmallVector<SDValue, 8> NextBlocks;
6048 NextBlocks.reserve(Blocks.size() * 2);
6049 for (SDValue Block : Blocks) {
6050 SDValue Zero = DAG.getConstant(0, DL, SrcVT);
6051 SDValue Mask = DAG.getNode(ISD::SETCC, DL, SrcVT, Block, Zero,
6052 DAG.getCondCode(ISD::SETLT));
6053 SDValue LoInterleaved =
6054 DAG.getNode(LoongArchISD::VILVL, DL, SrcVT, Mask, Block);
6055 SDValue HiInterleaved =
6056 DAG.getNode(LoongArchISD::VILVH, DL, SrcVT, Mask, Block);
6057
6058 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, LoInterleaved));
6059 NextBlocks.push_back(DAG.getBitcast(NextBlockVT, HiInterleaved));
6060 }
6061
6062 Blocks = std::move(NextBlocks);
6063 SrcVT = NextBlockVT;
6064 SrcEltBits = NextEltBits;
6065 }
6066
6067 Results.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Blocks));
6068 break;
6069 }
6070 case ISD::FP_EXTEND:
6071 // FP_EXTEND may reach here due to the Custom action for v2f32 results, but
6072 // no target-specific lowering is required. Leave it unchanged and rely on
6073 // the default type legalization.
6074 break;
6075 }
6076}
6077
6078/// Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
6080 SelectionDAG &DAG) {
6081 assert(N->getOpcode() == ISD::AND && "Unexpected opcode combine into ANDN");
6082
6083 MVT VT = N->getSimpleValueType(0);
6084 if (!VT.is128BitVector() && !VT.is256BitVector())
6085 return SDValue();
6086
6087 SDValue X, Y;
6088 SDValue N0 = N->getOperand(0);
6089 SDValue N1 = N->getOperand(1);
6090
6091 if (SDValue Not = isNOT(N0, DAG)) {
6092 X = Not;
6093 Y = N1;
6094 } else if (SDValue Not = isNOT(N1, DAG)) {
6095 X = Not;
6096 Y = N0;
6097 } else
6098 return SDValue();
6099
6100 X = DAG.getBitcast(VT, X);
6101 Y = DAG.getBitcast(VT, Y);
6102 return DAG.getNode(LoongArchISD::VANDN, DL, VT, X, Y);
6103}
6104
6105static bool isConstantSplatVector(SDValue N, APInt &SplatValue,
6106 unsigned MinSizeInBits) {
6109
6110 if (!Node)
6111 return false;
6112
6113 APInt SplatUndef;
6114 unsigned SplatBitSize;
6115 bool HasAnyUndefs;
6116
6117 return Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
6118 HasAnyUndefs, MinSizeInBits,
6119 /*IsBigEndian=*/false);
6120}
6121
6122static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex) {
6123 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6124 if (!BV)
6125 return SDValue();
6126
6127 SDValue Src;
6128 int Start = -1;
6129
6130 for (unsigned i = 0, NumElts = BV->getNumOperands(); i < NumElts; ++i) {
6131 SDValue Op = BV->getOperand(i);
6132 if (Op.isUndef())
6133 continue;
6134 if (Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
6135 return SDValue();
6136
6137 auto *IdxC = dyn_cast<ConstantSDNode>(Op.getOperand(1));
6138 if (!IdxC)
6139 return SDValue();
6140
6141 unsigned EltIdx = IdxC->getZExtValue();
6142 if (Start < 0)
6143 Start = (int)EltIdx - (int)(i * 2);
6144 if (Start < 0 || Start > 1 || EltIdx != (unsigned)(Start + (int)(i * 2)))
6145 return SDValue();
6146
6147 SDValue CurSrc = Op.getOperand(0);
6148 if (!Src)
6149 Src = CurSrc;
6150 else if (Src != CurSrc)
6151 return SDValue();
6152 }
6153
6154 if (!Src || Start < 0)
6155 return SDValue();
6156
6157 StartIndex = (unsigned)Start;
6158 return Src;
6159}
6160
6161static SDValue
6163 const LoongArchSubtarget &Subtarget) {
6164 if (!Subtarget.hasExtLSX())
6165 return SDValue();
6166
6167 unsigned Opc = N->getOpcode();
6168 assert((Opc == ISD::ADD || Opc == ISD::SUB) && "Unexpected opcode");
6169
6170 EVT VT = N->getValueType(0);
6171 SDLoc DL(N);
6172
6173 SDValue LHS = N->getOperand(0);
6174 SDValue RHS = N->getOperand(1);
6175
6176 bool isSigned;
6177 unsigned ExtOpc = LHS.getOpcode();
6178 if (ExtOpc == ISD::SIGN_EXTEND)
6179 isSigned = true;
6180 else if (ExtOpc == ISD::ZERO_EXTEND)
6181 isSigned = false;
6182 else
6183 return SDValue();
6184
6185 if (ExtOpc != RHS.getOpcode())
6186 return SDValue();
6187
6188 if (!LHS.hasOneUse() || !RHS.hasOneUse())
6189 return SDValue();
6190
6191 unsigned OddIdx, EvenIdx;
6192 SDValue LHSVec = matchDeinterleaveBuildVector(LHS.getOperand(0), OddIdx);
6193 SDValue RHSVec = matchDeinterleaveBuildVector(RHS.getOperand(0), EvenIdx);
6194
6195 if (!LHSVec || !RHSVec)
6196 return SDValue();
6197 if (OddIdx != 1 || EvenIdx != 0)
6198 return SDValue();
6199 if (LHSVec.getValueType() != RHSVec.getValueType())
6200 return SDValue();
6201
6202 EVT SrcVT = LHSVec.getValueType();
6203 EVT SrcEltVT = SrcVT.getVectorElementType();
6204 EVT DstEltVT = VT.getVectorElementType();
6205 auto &TLI = DAG.getTargetLoweringInfo();
6206
6207 if (!TLI.isTypeLegal(VT) || !TLI.isTypeLegal(SrcVT))
6208 return SDValue();
6209 if (!SrcVT.isVector() || !VT.isVector())
6210 return SDValue();
6211 if (SrcVT.getSizeInBits() != VT.getSizeInBits())
6212 return SDValue();
6213 if (DstEltVT.getSizeInBits() != SrcEltVT.getSizeInBits() * 2)
6214 return SDValue();
6215 if (!SrcEltVT.isInteger() || SrcEltVT.getSizeInBits() > 32)
6216 return SDValue();
6217
6218 unsigned TargetOpc;
6219 if (Opc == ISD::ADD)
6220 TargetOpc = isSigned ? LoongArchISD::VHADDW : LoongArchISD::VHADDW_U;
6221 else
6222 TargetOpc = isSigned ? LoongArchISD::VHSUBW : LoongArchISD::VHSUBW_U;
6223
6224 return DAG.getNode(TargetOpc, DL, VT, LHSVec, RHSVec);
6225}
6226
6229 const LoongArchSubtarget &Subtarget) {
6230 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6231 return V;
6232
6233 if (DCI.isBeforeLegalizeOps())
6234 return SDValue();
6235
6236 EVT VT = N->getValueType(0);
6237 if (!VT.isVector())
6238 return SDValue();
6239
6240 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
6241 return SDValue();
6242
6243 EVT EltVT = VT.getVectorElementType();
6244 if (!EltVT.isInteger())
6245 return SDValue();
6246
6247 // match:
6248 //
6249 // add
6250 // (and
6251 // (srl X, shift-1) / X
6252 // 1)
6253 // (srl/sra X, shift)
6254
6255 SDValue Add0 = N->getOperand(0);
6256 SDValue Add1 = N->getOperand(1);
6257 SDValue And;
6258 SDValue Shr;
6259
6260 if (Add0.getOpcode() == ISD::AND) {
6261 And = Add0;
6262 Shr = Add1;
6263 } else if (Add1.getOpcode() == ISD::AND) {
6264 And = Add1;
6265 Shr = Add0;
6266 } else {
6267 return SDValue();
6268 }
6269
6270 // match:
6271 //
6272 // srl/sra X, shift
6273
6274 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
6275 return SDValue();
6276
6277 SDValue X = Shr.getOperand(0);
6278 SDValue Shift = Shr.getOperand(1);
6279 APInt ShiftVal;
6280
6281 if (!isConstantSplatVector(Shift, ShiftVal, EltVT.getSizeInBits()))
6282 return SDValue();
6283
6284 if (ShiftVal == 0)
6285 return SDValue();
6286
6287 // match:
6288 //
6289 // and
6290 // (srl X, shift-1) / X
6291 // 1
6292
6293 SDValue One = And.getOperand(1);
6294 APInt SplatVal;
6295
6296 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
6297 return SDValue();
6298
6299 if (SplatVal != 1)
6300 return SDValue();
6301
6302 if (And.getOperand(0) == X) {
6303 // match:
6304 //
6305 // shift == 1
6306
6307 if (ShiftVal != 1)
6308 return SDValue();
6309 } else {
6310 // match:
6311 //
6312 // srl X, shift-1
6313
6314 SDValue Srl = And.getOperand(0);
6315
6316 if (Srl.getOpcode() != ISD::SRL)
6317 return SDValue();
6318
6319 if (Srl.getOperand(0) != X)
6320 return SDValue();
6321
6322 // match:
6323 //
6324 // shift-1
6325
6326 SDValue ShiftMinus1 = Srl.getOperand(1);
6327
6328 if (!isConstantSplatVector(ShiftMinus1, SplatVal, EltVT.getSizeInBits()))
6329 return SDValue();
6330
6331 if (ShiftVal != (SplatVal + 1))
6332 return SDValue();
6333 }
6334
6335 // We matched a rounded right shift pattern and can lower it
6336 // to a single vector rounded shift instruction.
6337
6338 SDLoc DL(N);
6339 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
6340 : LoongArchISD::VSRAR,
6341 DL, VT, X, Shift);
6342}
6343
6346 const LoongArchSubtarget &Subtarget) {
6347 if (DCI.isBeforeLegalizeOps())
6348 return SDValue();
6349
6350 SDValue FirstOperand = N->getOperand(0);
6351 SDValue SecondOperand = N->getOperand(1);
6352 unsigned FirstOperandOpc = FirstOperand.getOpcode();
6353 EVT ValTy = N->getValueType(0);
6354 SDLoc DL(N);
6355 uint64_t lsb, msb;
6356 unsigned SMIdx, SMLen;
6357 ConstantSDNode *CN;
6358 SDValue NewOperand;
6359 MVT GRLenVT = Subtarget.getGRLenVT();
6360
6361 if (SDValue R = combineAndNotIntoVANDN(N, DL, DAG))
6362 return R;
6363
6364 // BSTRPICK requires the 32S feature.
6365 if (!Subtarget.has32S())
6366 return SDValue();
6367
6368 // Op's second operand must be a shifted mask.
6369 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
6370 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
6371 return SDValue();
6372
6373 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
6374 // Pattern match BSTRPICK.
6375 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
6376 // => BSTRPICK $dst, $src, msb, lsb
6377 // where msb = lsb + len - 1
6378
6379 // The second operand of the shift must be an immediate.
6380 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
6381 return SDValue();
6382
6383 lsb = CN->getZExtValue();
6384
6385 // Return if the shifted mask does not start at bit 0 or the sum of its
6386 // length and lsb exceeds the word's size.
6387 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
6388 return SDValue();
6389
6390 NewOperand = FirstOperand.getOperand(0);
6391 } else {
6392 // Pattern match BSTRPICK.
6393 // $dst = and $src, (2**len- 1) , if len > 12
6394 // => BSTRPICK $dst, $src, msb, lsb
6395 // where lsb = 0 and msb = len - 1
6396
6397 // If the mask is <= 0xfff, andi can be used instead.
6398 if (CN->getZExtValue() <= 0xfff)
6399 return SDValue();
6400
6401 // Return if the MSB exceeds.
6402 if (SMIdx + SMLen > ValTy.getSizeInBits())
6403 return SDValue();
6404
6405 if (SMIdx > 0) {
6406 // Omit if the constant has more than 2 uses. This a conservative
6407 // decision. Whether it is a win depends on the HW microarchitecture.
6408 // However it should always be better for 1 and 2 uses.
6409 if (CN->use_size() > 2)
6410 return SDValue();
6411 // Return if the constant can be composed by a single LU12I.W.
6412 if ((CN->getZExtValue() & 0xfff) == 0)
6413 return SDValue();
6414 // Return if the constand can be composed by a single ADDI with
6415 // the zero register.
6416 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
6417 return SDValue();
6418 }
6419
6420 lsb = SMIdx;
6421 NewOperand = FirstOperand;
6422 }
6423
6424 msb = lsb + SMLen - 1;
6425 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
6426 DAG.getConstant(msb, DL, GRLenVT),
6427 DAG.getConstant(lsb, DL, GRLenVT));
6428 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
6429 return NR0;
6430 // Try to optimize to
6431 // bstrpick $Rd, $Rs, msb, lsb
6432 // slli $Rd, $Rd, lsb
6433 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
6434 DAG.getConstant(lsb, DL, GRLenVT));
6435}
6436
6437// Return the original source vector if N consists of the half
6438// of each 128-bit lane.
6441
6442 EVT DstVT = N.getValueType();
6443 if (!DstVT.isVector())
6444 return SDValue();
6445
6446 unsigned NumElts = DstVT.getVectorNumElements();
6447
6448 // LSX canonical form:
6449 if (N.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
6450 SDValue Src = N.getOperand(0);
6451 EVT SrcVT = Src.getValueType();
6452
6453 if (!SrcVT.isVector() || !SrcVT.is128BitVector())
6454 return SDValue();
6455 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6456 return SDValue();
6457 if (SrcVT.getVectorNumElements() != NumElts * 2)
6458 return SDValue();
6459 if (N.getConstantOperandVal(1) != (isLow ? 0 : NumElts))
6460 return SDValue();
6461
6462 return Src;
6463 }
6464
6465 // LASX canonical form:
6466 auto *BV = dyn_cast<BuildVectorSDNode>(N);
6467 if (!BV)
6468 return SDValue();
6469
6470 if (NumElts % 2 != 0)
6471 return SDValue();
6472
6473 SDValue Src;
6474 EVT SrcVT;
6475
6476 for (unsigned I = 0; I != NumElts; ++I) {
6477 SDValue Elt = BV->getOperand(I);
6478 if (Elt.isUndef())
6479 continue;
6481 return SDValue();
6482
6483 SDValue ThisSrc = Elt.getOperand(0);
6484 SDValue Idx = Elt.getOperand(1);
6485 auto *CI = dyn_cast<ConstantSDNode>(Idx);
6486 if (!CI)
6487 return SDValue();
6488
6489 if (!Src) {
6490 Src = ThisSrc;
6491 SrcVT = Src.getValueType();
6492 if (!SrcVT.isVector())
6493 return SDValue();
6494
6495 if (!SrcVT.is256BitVector())
6496 return SDValue();
6497 if (SrcVT.getSizeInBits() != DstVT.getSizeInBits() * 2)
6498 return SDValue();
6499 if (SrcVT.getVectorNumElements() != NumElts * 2)
6500 return SDValue();
6501 } else if (ThisSrc != Src) {
6502 return SDValue();
6503 }
6504
6505 unsigned Half = NumElts / 2;
6506 unsigned ExpectedIdx = (I < Half) ? I : (I + Half);
6507 ExpectedIdx += isLow ? 0 : Half;
6508
6509 if (CI->getZExtValue() != ExpectedIdx)
6510 return SDValue();
6511 }
6512
6513 return Src;
6514}
6515
6518 const LoongArchSubtarget &Subtarget) {
6519 assert(N->getOpcode() == ISD::SHL && "Unexpected opcode");
6520
6521 EVT VT = N->getValueType(0);
6522 SDLoc DL(N);
6523
6524 SDValue LHS = N->getOperand(0);
6525 SDValue RHS = N->getOperand(1);
6526
6527 bool isSigned;
6528 unsigned ExtOpc = LHS.getOpcode();
6529 if (ExtOpc == ISD::SIGN_EXTEND)
6530 isSigned = true;
6531 else if (ExtOpc == ISD::ZERO_EXTEND)
6532 isSigned = false;
6533 else
6534 return SDValue();
6535
6536 if (!LHS.hasOneUse())
6537 return SDValue();
6538
6539 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
6540 N->getValueSizeInBits(0) != LHS->getOperand(0).getValueSizeInBits() * 2)
6541 return SDValue();
6542
6543 SDValue Vec = matchHalfOf128BitLanes(LHS.getOperand(0), /*isLow=*/true);
6544 if (!Vec)
6545 return SDValue();
6546
6547 EVT SrcVT = Vec.getValueType();
6548 EVT SrcEltVT = SrcVT.getVectorElementType();
6549 EVT DstEltVT = VT.getVectorElementType();
6550 APInt Imm;
6551 if (!isConstantSplatVector(RHS, Imm, DstEltVT.getSizeInBits()))
6552 return SDValue();
6553 if (!Imm.ult(SrcEltVT.getSizeInBits()))
6554 return SDValue();
6555
6556 unsigned Opc = isSigned ? LoongArchISD::VSLLWIL : LoongArchISD::VSLLWIL_U;
6557 SDValue Sht = DAG.getConstant(Imm.getZExtValue(), DL, Subtarget.getGRLenVT());
6558 return DAG.getNode(Opc, DL, VT, Vec, Sht);
6559}
6560
6563 const LoongArchSubtarget &Subtarget) {
6564 // BSTRPICK requires the 32S feature.
6565 if (!Subtarget.has32S())
6566 return SDValue();
6567
6568 if (DCI.isBeforeLegalizeOps())
6569 return SDValue();
6570
6571 // $dst = srl (and $src, Mask), Shamt
6572 // =>
6573 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
6574 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
6575 //
6576
6577 SDValue FirstOperand = N->getOperand(0);
6578 ConstantSDNode *CN;
6579 EVT ValTy = N->getValueType(0);
6580 SDLoc DL(N);
6581 MVT GRLenVT = Subtarget.getGRLenVT();
6582 unsigned MaskIdx, MaskLen;
6583 uint64_t Shamt;
6584
6585 // The first operand must be an AND and the second operand of the AND must be
6586 // a shifted mask.
6587 if (FirstOperand.getOpcode() != ISD::AND ||
6588 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
6589 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
6590 return SDValue();
6591
6592 // The second operand (shift amount) must be an immediate.
6593 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
6594 return SDValue();
6595
6596 Shamt = CN->getZExtValue();
6597 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
6598 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
6599 FirstOperand->getOperand(0),
6600 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
6601 DAG.getConstant(Shamt, DL, GRLenVT));
6602
6603 return SDValue();
6604}
6605
6608 const LoongArchSubtarget &Subtarget) {
6609 if (SDValue V = performHorizWideningCombine(N, DAG, Subtarget))
6610 return V;
6611
6612 return SDValue();
6613}
6614
6615// Helper to peek through bitops/trunc/setcc to determine size of source vector.
6616// Allows BITCASTCombine to determine what size vector generated a <X x i1>.
6617static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size,
6618 unsigned Depth) {
6619 // Limit recursion.
6621 return false;
6622 switch (Src.getOpcode()) {
6623 case ISD::SETCC:
6624 case ISD::TRUNCATE:
6625 return Src.getOperand(0).getValueSizeInBits() == Size;
6626 case ISD::FREEZE:
6627 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1);
6628 case ISD::AND:
6629 case ISD::XOR:
6630 case ISD::OR:
6631 return checkBitcastSrcVectorSize(Src.getOperand(0), Size, Depth + 1) &&
6632 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1);
6633 case ISD::SELECT:
6634 case ISD::VSELECT:
6635 return Src.getOperand(0).getScalarValueSizeInBits() == 1 &&
6636 checkBitcastSrcVectorSize(Src.getOperand(1), Size, Depth + 1) &&
6637 checkBitcastSrcVectorSize(Src.getOperand(2), Size, Depth + 1);
6638 case ISD::BUILD_VECTOR:
6639 return ISD::isBuildVectorAllZeros(Src.getNode()) ||
6640 ISD::isBuildVectorAllOnes(Src.getNode());
6641 }
6642 return false;
6643}
6644
6645// Helper to push sign extension of vXi1 SETCC result through bitops.
6647 SDValue Src, const SDLoc &DL) {
6648 switch (Src.getOpcode()) {
6649 case ISD::SETCC:
6650 case ISD::FREEZE:
6651 case ISD::TRUNCATE:
6652 case ISD::BUILD_VECTOR:
6653 return DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6654 case ISD::AND:
6655 case ISD::XOR:
6656 case ISD::OR:
6657 return DAG.getNode(
6658 Src.getOpcode(), DL, SExtVT,
6659 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(0), DL),
6660 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL));
6661 case ISD::SELECT:
6662 case ISD::VSELECT:
6663 return DAG.getSelect(
6664 DL, SExtVT, Src.getOperand(0),
6665 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(1), DL),
6666 signExtendBitcastSrcVector(DAG, SExtVT, Src.getOperand(2), DL));
6667 }
6668 llvm_unreachable("Unexpected node type for vXi1 sign extension");
6669}
6670
6671static SDValue
6674 const LoongArchSubtarget &Subtarget) {
6675 SDLoc DL(N);
6676 EVT VT = N->getValueType(0);
6677 SDValue Src = N->getOperand(0);
6678 EVT SrcVT = Src.getValueType();
6679
6680 if (Src.getOpcode() != ISD::SETCC || !Src.hasOneUse())
6681 return SDValue();
6682
6683 bool UseLASX;
6684 unsigned Opc = ISD::DELETED_NODE;
6685 EVT CmpVT = Src.getOperand(0).getValueType();
6686 EVT EltVT = CmpVT.getVectorElementType();
6687
6688 if (Subtarget.hasExtLSX() && CmpVT.getSizeInBits() == 128)
6689 UseLASX = false;
6690 else if (Subtarget.has32S() && Subtarget.hasExtLASX() &&
6691 CmpVT.getSizeInBits() == 256)
6692 UseLASX = true;
6693 else
6694 return SDValue();
6695
6696 SDValue SrcN1 = Src.getOperand(1);
6697 switch (cast<CondCodeSDNode>(Src.getOperand(2))->get()) {
6698 default:
6699 break;
6700 case ISD::SETEQ:
6701 // x == 0 => not (vmsknez.b x)
6702 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6703 Opc = UseLASX ? LoongArchISD::XVMSKEQZ : LoongArchISD::VMSKEQZ;
6704 break;
6705 case ISD::SETGT:
6706 // x > -1 => vmskgez.b x
6707 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) && EltVT == MVT::i8)
6708 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6709 break;
6710 case ISD::SETGE:
6711 // x >= 0 => vmskgez.b x
6712 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6713 Opc = UseLASX ? LoongArchISD::XVMSKGEZ : LoongArchISD::VMSKGEZ;
6714 break;
6715 case ISD::SETLT:
6716 // x < 0 => vmskltz.{b,h,w,d} x
6717 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) &&
6718 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6719 EltVT == MVT::i64))
6720 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6721 break;
6722 case ISD::SETLE:
6723 // x <= -1 => vmskltz.{b,h,w,d} x
6724 if (ISD::isBuildVectorAllOnes(SrcN1.getNode()) &&
6725 (EltVT == MVT::i8 || EltVT == MVT::i16 || EltVT == MVT::i32 ||
6726 EltVT == MVT::i64))
6727 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6728 break;
6729 case ISD::SETNE:
6730 // x != 0 => vmsknez.b x
6731 if (ISD::isBuildVectorAllZeros(SrcN1.getNode()) && EltVT == MVT::i8)
6732 Opc = UseLASX ? LoongArchISD::XVMSKNEZ : LoongArchISD::VMSKNEZ;
6733 break;
6734 }
6735
6736 if (Opc == ISD::DELETED_NODE)
6737 return SDValue();
6738
6739 SDValue V = DAG.getNode(Opc, DL, Subtarget.getGRLenVT(), Src.getOperand(0));
6741 V = DAG.getZExtOrTrunc(V, DL, T);
6742 return DAG.getBitcast(VT, V);
6743}
6744
6747 const LoongArchSubtarget &Subtarget) {
6748 SDLoc DL(N);
6749 EVT VT = N->getValueType(0);
6750 SDValue Src = N->getOperand(0);
6751 EVT SrcVT = Src.getValueType();
6752 MVT GRLenVT = Subtarget.getGRLenVT();
6753
6754 if (!DCI.isBeforeLegalizeOps())
6755 return SDValue();
6756
6757 if (!SrcVT.isSimple() || SrcVT.getScalarType() != MVT::i1)
6758 return SDValue();
6759
6760 // Combine SETCC and BITCAST into [X]VMSK{LT,GE,NE} when possible
6761 SDValue Res = performSETCC_BITCASTCombine(N, DAG, DCI, Subtarget);
6762 if (Res)
6763 return Res;
6764
6765 // Generate vXi1 using [X]VMSKLTZ
6766 MVT SExtVT;
6767 unsigned Opc;
6768 bool UseLASX = false;
6769 bool PropagateSExt = false;
6770
6771 if (Src.getOpcode() == ISD::SETCC && Src.hasOneUse()) {
6772 EVT CmpVT = Src.getOperand(0).getValueType();
6773 if (CmpVT.getSizeInBits() > 256)
6774 return SDValue();
6775 }
6776
6777 switch (SrcVT.getSimpleVT().SimpleTy) {
6778 default:
6779 return SDValue();
6780 case MVT::v2i1:
6781 SExtVT = MVT::v2i64;
6782 break;
6783 case MVT::v4i1:
6784 SExtVT = MVT::v4i32;
6785 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6786 SExtVT = MVT::v4i64;
6787 UseLASX = true;
6788 PropagateSExt = true;
6789 }
6790 break;
6791 case MVT::v8i1:
6792 SExtVT = MVT::v8i16;
6793 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6794 SExtVT = MVT::v8i32;
6795 UseLASX = true;
6796 PropagateSExt = true;
6797 }
6798 break;
6799 case MVT::v16i1:
6800 SExtVT = MVT::v16i8;
6801 if (Subtarget.hasExtLASX() && checkBitcastSrcVectorSize(Src, 256, 0)) {
6802 SExtVT = MVT::v16i16;
6803 UseLASX = true;
6804 PropagateSExt = true;
6805 }
6806 break;
6807 case MVT::v32i1:
6808 SExtVT = MVT::v32i8;
6809 UseLASX = true;
6810 break;
6811 };
6812 Src = PropagateSExt ? signExtendBitcastSrcVector(DAG, SExtVT, Src, DL)
6813 : DAG.getNode(ISD::SIGN_EXTEND, DL, SExtVT, Src);
6814
6815 SDValue V;
6816 if (!Subtarget.has32S() || !Subtarget.hasExtLASX()) {
6817 if (Src.getSimpleValueType() == MVT::v32i8) {
6818 SDValue Lo, Hi;
6819 std::tie(Lo, Hi) = DAG.SplitVector(Src, DL);
6820 Lo = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Lo);
6821 Hi = DAG.getNode(LoongArchISD::VMSKLTZ, DL, GRLenVT, Hi);
6822 Hi = DAG.getNode(ISD::SHL, DL, GRLenVT, Hi,
6823 DAG.getShiftAmountConstant(16, GRLenVT, DL));
6824 V = DAG.getNode(ISD::OR, DL, GRLenVT, Lo, Hi);
6825 } else if (UseLASX) {
6826 return SDValue();
6827 }
6828 }
6829
6830 if (!V) {
6831 Opc = UseLASX ? LoongArchISD::XVMSKLTZ : LoongArchISD::VMSKLTZ;
6832 V = DAG.getNode(Opc, DL, GRLenVT, Src);
6833 }
6834
6836 V = DAG.getZExtOrTrunc(V, DL, T);
6837 return DAG.getBitcast(VT, V);
6838}
6839
6842 const LoongArchSubtarget &Subtarget) {
6843 MVT GRLenVT = Subtarget.getGRLenVT();
6844 EVT ValTy = N->getValueType(0);
6845 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
6846 ConstantSDNode *CN0, *CN1;
6847 SDLoc DL(N);
6848 unsigned ValBits = ValTy.getSizeInBits();
6849 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
6850 unsigned Shamt;
6851 bool SwapAndRetried = false;
6852
6853 // BSTRPICK requires the 32S feature.
6854 if (!Subtarget.has32S())
6855 return SDValue();
6856
6857 if (DCI.isBeforeLegalizeOps())
6858 return SDValue();
6859
6860 if (ValBits != 32 && ValBits != 64)
6861 return SDValue();
6862
6863Retry:
6864 // 1st pattern to match BSTRINS:
6865 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
6866 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
6867 // =>
6868 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6869 if (N0.getOpcode() == ISD::AND &&
6870 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6871 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6872 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
6873 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6874 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6875 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
6876 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6877 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6878 (MaskIdx0 + MaskLen0 <= ValBits)) {
6879 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
6880 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6881 N1.getOperand(0).getOperand(0),
6882 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6883 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6884 }
6885
6886 // 2nd pattern to match BSTRINS:
6887 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
6888 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
6889 // =>
6890 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
6891 if (N0.getOpcode() == ISD::AND &&
6892 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6893 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6894 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
6895 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6896 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
6897 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6898 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
6899 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
6900 (MaskIdx0 + MaskLen0 <= ValBits)) {
6901 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
6902 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6903 N1.getOperand(0).getOperand(0),
6904 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
6905 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6906 }
6907
6908 // 3rd pattern to match BSTRINS:
6909 // R = or (and X, mask0), (and Y, mask1)
6910 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
6911 // =>
6912 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
6913 // where msb = lsb + size - 1
6914 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
6915 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6916 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6917 (MaskIdx0 + MaskLen0 <= 64) &&
6918 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
6919 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
6920 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
6921 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6922 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
6923 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
6924 DAG.getConstant(ValBits == 32
6925 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
6926 : (MaskIdx0 + MaskLen0 - 1),
6927 DL, GRLenVT),
6928 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6929 }
6930
6931 // 4th pattern to match BSTRINS:
6932 // R = or (and X, mask), (shl Y, shamt)
6933 // where mask = (2**shamt - 1)
6934 // =>
6935 // R = BSTRINS X, Y, ValBits - 1, shamt
6936 // where ValBits = 32 or 64
6937 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
6938 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6939 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
6940 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6941 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
6942 (MaskIdx0 + MaskLen0 <= ValBits)) {
6943 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
6944 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6945 N1.getOperand(0),
6946 DAG.getConstant((ValBits - 1), DL, GRLenVT),
6947 DAG.getConstant(Shamt, DL, GRLenVT));
6948 }
6949
6950 // 5th pattern to match BSTRINS:
6951 // R = or (and X, mask), const
6952 // where ~mask = (2**size - 1) << lsb, mask & const = 0
6953 // =>
6954 // R = BSTRINS X, (const >> lsb), msb, lsb
6955 // where msb = lsb + size - 1
6956 if (N0.getOpcode() == ISD::AND &&
6957 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
6958 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
6959 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
6960 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
6961 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
6962 return DAG.getNode(
6963 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
6964 DAG.getSignedConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
6965 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
6966 : (MaskIdx0 + MaskLen0 - 1),
6967 DL, GRLenVT),
6968 DAG.getConstant(MaskIdx0, DL, GRLenVT));
6969 }
6970
6971 // 6th pattern.
6972 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
6973 // by the incoming bits are known to be zero.
6974 // =>
6975 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
6976 //
6977 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
6978 // pattern is more common than the 1st. So we put the 1st before the 6th in
6979 // order to match as many nodes as possible.
6980 ConstantSDNode *CNMask, *CNShamt;
6981 unsigned MaskIdx, MaskLen;
6982 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
6983 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
6984 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
6985 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
6986 CNShamt->getZExtValue() + MaskLen <= ValBits) {
6987 Shamt = CNShamt->getZExtValue();
6988 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
6989 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
6990 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
6991 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
6992 N1.getOperand(0).getOperand(0),
6993 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
6994 DAG.getConstant(Shamt, DL, GRLenVT));
6995 }
6996 }
6997
6998 // 7th pattern.
6999 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
7000 // overwritten by the incoming bits are known to be zero.
7001 // =>
7002 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
7003 //
7004 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
7005 // before the 7th in order to match as many nodes as possible.
7006 if (N1.getOpcode() == ISD::AND &&
7007 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7008 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
7009 N1.getOperand(0).getOpcode() == ISD::SHL &&
7010 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
7011 CNShamt->getZExtValue() == MaskIdx) {
7012 APInt ShMask(ValBits, CNMask->getZExtValue());
7013 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7014 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
7015 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7016 N1.getOperand(0).getOperand(0),
7017 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7018 DAG.getConstant(MaskIdx, DL, GRLenVT));
7019 }
7020 }
7021
7022 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
7023 if (!SwapAndRetried) {
7024 std::swap(N0, N1);
7025 SwapAndRetried = true;
7026 goto Retry;
7027 }
7028
7029 SwapAndRetried = false;
7030Retry2:
7031 // 8th pattern.
7032 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
7033 // the incoming bits are known to be zero.
7034 // =>
7035 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
7036 //
7037 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
7038 // we put it here in order to match as many nodes as possible or generate less
7039 // instructions.
7040 if (N1.getOpcode() == ISD::AND &&
7041 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
7042 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
7043 APInt ShMask(ValBits, CNMask->getZExtValue());
7044 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
7045 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
7046 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
7047 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
7048 N1->getOperand(0),
7049 DAG.getConstant(MaskIdx, DL, GRLenVT)),
7050 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
7051 DAG.getConstant(MaskIdx, DL, GRLenVT));
7052 }
7053 }
7054 // Swap N0/N1 and retry.
7055 if (!SwapAndRetried) {
7056 std::swap(N0, N1);
7057 SwapAndRetried = true;
7058 goto Retry2;
7059 }
7060
7061 return SDValue();
7062}
7063
7064static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
7065 ExtType = ISD::NON_EXTLOAD;
7066
7067 switch (V.getNode()->getOpcode()) {
7068 case ISD::LOAD: {
7069 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
7070 if ((LoadNode->getMemoryVT() == MVT::i8) ||
7071 (LoadNode->getMemoryVT() == MVT::i16)) {
7072 ExtType = LoadNode->getExtensionType();
7073 return true;
7074 }
7075 return false;
7076 }
7077 case ISD::AssertSext: {
7078 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7079 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7080 ExtType = ISD::SEXTLOAD;
7081 return true;
7082 }
7083 return false;
7084 }
7085 case ISD::AssertZext: {
7086 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
7087 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
7088 ExtType = ISD::ZEXTLOAD;
7089 return true;
7090 }
7091 return false;
7092 }
7093 default:
7094 return false;
7095 }
7096
7097 return false;
7098}
7099
7100// Fold a lane-mask extraction that is only compared against zero into one of
7101// all-lane check instructions, which write the results into fcc register, so
7102// BCEQZ could use it directly.
7103//
7104// (VMSKLTZ X) != 0 -> VSETNEZ.V X
7105// (VMSKLTZ X) == 0 -> VSETEQZ.V X
7106//
7107// This is valid when X is the result of a vector compare instruction,
7108// so each lane of X has to be all-ones or all-zeros.
7110 const SDLoc &DL, SelectionDAG &DAG,
7111 const LoongArchSubtarget &Subtarget) {
7112 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7113 return SDValue();
7114 if (!isNullConstant(RHS))
7115 return SDValue();
7116
7117 unsigned MskOpc = LHS.getOpcode();
7118 if (MskOpc != LoongArchISD::VMSKLTZ && MskOpc != LoongArchISD::XVMSKLTZ)
7119 return SDValue();
7120 // Keeping the mask alive for another user would defeat the purpose.
7121 if (!LHS.hasOneUse())
7122 return SDValue();
7123
7124 SDValue Src = LHS.getOperand(0);
7125 EVT SrcVT = Src.getValueType();
7126 // Make sure every lane is all-ones or all-zeros.
7127 if (!SrcVT.isVector() ||
7128 DAG.ComputeNumSignBits(Src) != SrcVT.getScalarSizeInBits())
7129 return SDValue();
7130
7131 return DAG.getNode(CC == ISD::SETNE ? LoongArchISD::VANYNONZERO
7132 : LoongArchISD::VALLZERO,
7133 DL, Subtarget.getGRLenVT(), Src);
7134}
7135
7136// Eliminate redundant truncation and zero-extension nodes.
7137// * Case 1:
7138// +------------+ +------------+ +------------+
7139// | Input1 | | Input2 | | CC |
7140// +------------+ +------------+ +------------+
7141// | | |
7142// V V +----+
7143// +------------+ +------------+ |
7144// | TRUNCATE | | TRUNCATE | |
7145// +------------+ +------------+ |
7146// | | |
7147// V V |
7148// +------------+ +------------+ |
7149// | ZERO_EXT | | ZERO_EXT | |
7150// +------------+ +------------+ |
7151// | | |
7152// | +-------------+ |
7153// V V | |
7154// +----------------+ | |
7155// | AND | | |
7156// +----------------+ | |
7157// | | |
7158// +---------------+ | |
7159// | | |
7160// V V V
7161// +-------------+
7162// | CMP |
7163// +-------------+
7164// * Case 2:
7165// +------------+ +------------+ +-------------+ +------------+ +------------+
7166// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
7167// +------------+ +------------+ +-------------+ +------------+ +------------+
7168// | | | | |
7169// V | | | |
7170// +------------+ | | | |
7171// | XOR |<---------------------+ | |
7172// +------------+ | | |
7173// | | | |
7174// V V +---------------+ |
7175// +------------+ +------------+ | |
7176// | TRUNCATE | | TRUNCATE | | +-------------------------+
7177// +------------+ +------------+ | |
7178// | | | |
7179// V V | |
7180// +------------+ +------------+ | |
7181// | ZERO_EXT | | ZERO_EXT | | |
7182// +------------+ +------------+ | |
7183// | | | |
7184// V V | |
7185// +----------------+ | |
7186// | AND | | |
7187// +----------------+ | |
7188// | | |
7189// +---------------+ | |
7190// | | |
7191// V V V
7192// +-------------+
7193// | CMP |
7194// +-------------+
7197 const LoongArchSubtarget &Subtarget) {
7198 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
7199
7200 if (N->getValueType(0) == Subtarget.getGRLenVT())
7201 if (SDValue V = foldVMskZeroTest(N->getOperand(0), N->getOperand(1), CC,
7202 SDLoc(N), DAG, Subtarget))
7203 return V;
7204
7205 SDNode *AndNode = N->getOperand(0).getNode();
7206 if (AndNode->getOpcode() != ISD::AND)
7207 return SDValue();
7208
7209 SDValue AndInputValue2 = AndNode->getOperand(1);
7210 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
7211 return SDValue();
7212
7213 SDValue CmpInputValue = N->getOperand(1);
7214 SDValue AndInputValue1 = AndNode->getOperand(0);
7215 if (AndInputValue1.getOpcode() == ISD::XOR) {
7216 if (CC != ISD::SETEQ && CC != ISD::SETNE)
7217 return SDValue();
7218 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
7219 if (!CN || !CN->isAllOnes())
7220 return SDValue();
7221 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
7222 if (!CN || !CN->isZero())
7223 return SDValue();
7224 AndInputValue1 = AndInputValue1.getOperand(0);
7225 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
7226 return SDValue();
7227 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
7228 if (AndInputValue2 != CmpInputValue)
7229 return SDValue();
7230 } else {
7231 return SDValue();
7232 }
7233
7234 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
7235 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
7236 return SDValue();
7237
7238 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
7239 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
7240 return SDValue();
7241
7242 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
7243 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
7244 ISD::LoadExtType ExtType1;
7245 ISD::LoadExtType ExtType2;
7246
7247 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
7248 !checkValueWidth(TruncInputValue2, ExtType2))
7249 return SDValue();
7250
7251 if (TruncInputValue1->getValueType(0) != TruncInputValue2->getValueType(0) ||
7252 AndNode->getValueType(0) != TruncInputValue1->getValueType(0))
7253 return SDValue();
7254
7255 if ((ExtType2 != ISD::ZEXTLOAD) &&
7256 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
7257 return SDValue();
7258
7259 // These truncation and zero-extension nodes are not necessary, remove them.
7260 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
7261 TruncInputValue1, TruncInputValue2);
7262 SDValue NewSetCC =
7263 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
7264 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
7265 return SDValue(N, 0);
7266}
7267
7268// Strip a single outer ISD::SIGN_EXTEND_INREG from \p V, if present, and
7269// return the inner value together with the narrow VT it was extending
7270// from. If no such node is present, returns \p V unchanged and an invalid
7271// EVT.
7272//
7273// i32 (and other sub-GRLen) arithmetic is legalized to operate on the full
7274// GRLen-width register, with a `sign_extend_inreg` re-normalizing the
7275// result back into the narrow type's range afterwards (see e.g. the
7276// `add i32` -> `add` + `sign_extend_inreg ..., i32` legalization). Any
7277// combine that reassociates such a binop must track and reapply this
7278// extension, otherwise the transformed code can produce a value whose
7279// high bits no longer match the narrow-type semantics.
7280static std::pair<SDValue, EVT> stripSignExtendInReg(SDValue V) {
7281 if (V.getOpcode() == ISD::SIGN_EXTEND_INREG)
7282 return {V.getOperand(0), cast<VTSDNode>(V.getOperand(1))->getVT()};
7283 return {V, EVT()};
7284}
7285
7286// Try to match \p BinV (after optionally stripping an outer
7287// sign_extend_inreg) as a supported binary operation that has \p X as one
7288// of its operands, returning the matched opcode, the other operand (the
7289// "delta"), and the narrow VT of the sign_extend_inreg that was stripped
7290// (invalid EVT if none was present).
7291//
7292// For commutative ops (add/or/xor), \p X may be either operand, since
7293// `binop(X, Y) == binop(Y, X)` and the identity element (0) works on
7294// either side.
7295//
7296// For `sub`, the operation is NOT commutative: `sub(X, Y) != sub(Y, X)`.
7297// Only `sub(X, Y)` (i.e. \p X is the *minuend*, the first operand) can be
7298// rewritten using the identity `X - 0 == X`. If \p X were the *subtrahend*
7299// (second operand, i.e. the pattern is actually `sub(Y, X)`), there is no
7300// way to express `cond ? (Y - X) : X` (or the symmetric case) as
7301// `X op (select ...)` without introducing an extra negation, so that case
7302// must be rejected instead of "optimized" into worse code.
7303static std::tuple<unsigned, SDValue, EVT>
7305 auto [Inner, ExtVT] = stripSignExtendInReg(BinV);
7306
7307 unsigned Opc = Inner.getOpcode();
7308 switch (Opc) {
7309 case ISD::ADD:
7310 case ISD::OR:
7311 case ISD::XOR:
7312 if (Inner.getOperand(0) == X)
7313 return {Opc, Inner.getOperand(1), ExtVT};
7314 if (Inner.getOperand(1) == X)
7315 return {Opc, Inner.getOperand(0), ExtVT};
7316 return {0, SDValue(), EVT()};
7317 case ISD::SUB:
7318 // Only accept X as the minuend (first operand); see comment above.
7319 if (Inner.getOperand(0) == X)
7320 return {Opc, Inner.getOperand(1), ExtVT};
7321 return {0, SDValue(), EVT()};
7322 default:
7323 return {0, SDValue(), EVT()};
7324 }
7325}
7326
7327// Try to combine:
7328// select cond, binop(X, Y), X -> binop X, (select cond, Y, 0)
7329// select cond, X, binop(X, Y) -> binop X, (select cond, 0, Y)
7330// for binop in {add, or, xor, sub}, where 0 is the identity element of the
7331// respective operation, additionally handling the common legalized form
7332// where the binop result is wrapped in a `sign_extend_inreg` (as happens
7333// for sub-GRLen types such as i32 on a 64-bit GRLen target). See
7334// matchBinOpWithSharedOperand() for the restrictions applied to
7335// non-commutative operations (currently only `sub`).
7338 const LoongArchSubtarget &Subtarget) {
7339 if (DCI.isBeforeLegalizeOps())
7340 return SDValue();
7341
7342 EVT VT = N->getValueType(0);
7343 // Restrict to the scalar GRLen integer type that maskeqz/masknez operate
7344 // on; this also naturally excludes float and vector selects.
7345 if (VT != Subtarget.getGRLenVT())
7346 return SDValue();
7347
7348 SDValue Cond = N->getOperand(0);
7349 SDValue TrueV = N->getOperand(1);
7350 SDValue FalseV = N->getOperand(2);
7351 SDLoc DL(N);
7352
7353 auto TryFold = [&](SDValue BinV, SDValue SharedV,
7354 bool BinIsTrueArm) -> SDValue {
7355 auto [Opc, Delta, ExtVT] = matchBinOpWithSharedOperand(BinV, SharedV);
7356 if (!Opc)
7357 return SDValue();
7358
7359 // Avoid infinite combine loops: bail out if Delta is trivially the
7360 // same node we would otherwise be selecting on (shouldn't normally
7361 // happen, but guards against degenerate/self-referential IR).
7362 if (Delta.getNode() == N)
7363 return SDValue();
7364
7365 SDValue Zero = DAG.getConstant(0, DL, VT);
7366 SDValue NewSel = BinIsTrueArm ? DAG.getSelect(DL, VT, Cond, Delta, Zero)
7367 : DAG.getSelect(DL, VT, Cond, Zero, Delta);
7368 SDValue NewBin = DAG.getNode(Opc, DL, VT, SharedV, NewSel);
7369
7370 // If the original binop result was normalized back into a narrower
7371 // type via sign_extend_inreg (e.g. i32 arithmetic on a 64-bit GRLen
7372 // target), the new binop must be re-normalized the same way: SharedV
7373 // is already known-sign-extended for that narrow type, but NewSel
7374 // (Delta or 0, selected) combined with SharedV via Opc can still
7375 // produce a 64-bit result whose high bits don't match the narrow
7376 // type's sign-extended representation.
7377 if (ExtVT != EVT())
7378 NewBin = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, NewBin,
7379 DAG.getValueType(ExtVT));
7380
7381 return NewBin;
7382 };
7383
7384 if (SDValue R = TryFold(TrueV, FalseV, /*BinIsTrueArm=*/true))
7385 return R;
7386 if (SDValue R = TryFold(FalseV, TrueV, /*BinIsTrueArm=*/false))
7387 return R;
7388
7389 return SDValue();
7390}
7391
7392// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
7395 const LoongArchSubtarget &Subtarget) {
7396 if (DCI.isBeforeLegalizeOps())
7397 return SDValue();
7398
7399 SDValue Src = N->getOperand(0);
7400 if (Src.getOpcode() != LoongArchISD::REVB_2W)
7401 return SDValue();
7402
7403 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
7404 Src.getOperand(0));
7405}
7406
7407// Perform common combines for BR_CC and SELECT_CC conditions.
7408static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
7409 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
7410 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7411
7412 // As far as arithmetic right shift always saves the sign,
7413 // shift can be omitted.
7414 // Fold setlt (sra X, N), 0 -> setlt X, 0 and
7415 // setge (sra X, N), 0 -> setge X, 0
7416 if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
7417 LHS.getOpcode() == ISD::SRA) {
7418 LHS = LHS.getOperand(0);
7419 return true;
7420 }
7421
7422 if (!ISD::isIntEqualitySetCC(CCVal))
7423 return false;
7424
7425 // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
7426 // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
7427 if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
7428 LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
7429 // If we're looking for eq 0 instead of ne 0, we need to invert the
7430 // condition.
7431 bool Invert = CCVal == ISD::SETEQ;
7432 CCVal = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
7433 if (Invert)
7434 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7435
7436 RHS = LHS.getOperand(1);
7437 LHS = LHS.getOperand(0);
7438 translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
7439
7440 CC = DAG.getCondCode(CCVal);
7441 return true;
7442 }
7443
7444 // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
7445 if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
7446 LHS.getOperand(1).getOpcode() == ISD::Constant) {
7447 SDValue LHS0 = LHS.getOperand(0);
7448 if (LHS0.getOpcode() == ISD::AND &&
7449 LHS0.getOperand(1).getOpcode() == ISD::Constant) {
7450 uint64_t Mask = LHS0.getConstantOperandVal(1);
7451 uint64_t ShAmt = LHS.getConstantOperandVal(1);
7452 if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
7453 CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
7454 CC = DAG.getCondCode(CCVal);
7455
7456 ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
7457 LHS = LHS0.getOperand(0);
7458 if (ShAmt != 0)
7459 LHS =
7460 DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
7461 DAG.getConstant(ShAmt, DL, LHS.getValueType()));
7462 return true;
7463 }
7464 }
7465 }
7466
7467 // (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
7468 // This can occur when legalizing some floating point comparisons.
7469 APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
7470 if (isOneConstant(RHS) && DAG.MaskedValueIsZero(LHS, Mask)) {
7471 CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
7472 CC = DAG.getCondCode(CCVal);
7473 RHS = DAG.getConstant(0, DL, LHS.getValueType());
7474 return true;
7475 }
7476
7477 // Fold ((shl (extract_vector_elt X, I), GRLen - EleBits)), 0, eq/ne) ->
7478 // ((extract_vector_elt X, I), 0, eq/ne)
7479 if (isNullConstant(RHS) && (CCVal == ISD::SETEQ || CCVal == ISD::SETNE) &&
7480 LHS.getOpcode() == ISD::SHL && LHS.hasOneUse() &&
7481 isa<ConstantSDNode>(LHS.getOperand(1))) {
7482 SDValue Ext = LHS.getOperand(0);
7483 unsigned Sht = LHS.getConstantOperandVal(1);
7484 if (Ext.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
7485 SDValue Vec = Ext.getOperand(0);
7486 unsigned EleBits = Vec.getScalarValueSizeInBits();
7487 if ((EleBits + Sht) == Subtarget.getGRLen()) {
7488 LHS = Ext;
7489 return true;
7490 }
7491 }
7492 }
7493
7494 // Fold (C1, C2, cond) -> (0, 0, seteq/setne)
7496 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
7497 EVT VT = LHS.getValueType();
7498 EVT SetCCResVT =
7499 TLI->getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
7500 if (SDValue Folded = DAG.FoldSetCC(SetCCResVT, LHS, RHS, CCVal, DL)) {
7501 LHS = DAG.getConstant(0, DL, VT);
7502 RHS = DAG.getConstant(0, DL, VT);
7503 CC = DAG.getCondCode(!isNullConstant(Folded) ? ISD::SETEQ : ISD::SETNE);
7504 return true;
7505 }
7506 }
7507
7508 return false;
7509}
7510
7513 const LoongArchSubtarget &Subtarget) {
7514 SDValue LHS = N->getOperand(1);
7515 SDValue RHS = N->getOperand(2);
7516 SDValue CC = N->getOperand(3);
7517 SDLoc DL(N);
7518
7519 // CC was folded into V, so always return ISD::SETNE is fine.
7521 DL, DAG, Subtarget))
7522 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7523 N->getOperand(0), V,
7524 DAG.getConstant(0, DL, Subtarget.getGRLenVT()),
7525 DAG.getCondCode(ISD::SETNE), N->getOperand(4));
7526
7527 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7528 return DAG.getNode(LoongArchISD::BR_CC, DL, N->getValueType(0),
7529 N->getOperand(0), LHS, RHS, CC, N->getOperand(4));
7530
7531 return SDValue();
7532}
7533
7536 const LoongArchSubtarget &Subtarget) {
7537 // Transform
7538 SDValue LHS = N->getOperand(0);
7539 SDValue RHS = N->getOperand(1);
7540 SDValue CC = N->getOperand(2);
7541 ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
7542 SDValue TrueV = N->getOperand(3);
7543 SDValue FalseV = N->getOperand(4);
7544 SDLoc DL(N);
7545 EVT VT = N->getValueType(0);
7546
7547 // If the True and False values are the same, we don't need a select_cc.
7548 if (TrueV == FalseV)
7549 return TrueV;
7550
7551 // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
7552 // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
7553 if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
7555 (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
7556 if (CCVal == ISD::CondCode::SETGE)
7557 std::swap(TrueV, FalseV);
7558
7559 int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
7560 int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
7561 // Only handle simm12, if it is not in this range, it can be considered as
7562 // register.
7563 if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
7564 isInt<12>(TrueSImm - FalseSImm)) {
7565 SDValue SRA =
7566 DAG.getNode(ISD::SRA, DL, VT, LHS,
7567 DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
7568 SDValue AND =
7569 DAG.getNode(ISD::AND, DL, VT, SRA,
7570 DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
7571 return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
7572 }
7573
7574 if (CCVal == ISD::CondCode::SETGE)
7575 std::swap(TrueV, FalseV);
7576 }
7577
7578 if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
7579 return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
7580 {LHS, RHS, CC, TrueV, FalseV});
7581
7582 return SDValue();
7583}
7584
7585template <unsigned N>
7587 SelectionDAG &DAG,
7588 const LoongArchSubtarget &Subtarget,
7589 bool IsSigned = false) {
7590 SDLoc DL(Node);
7591 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7592 // Check the ImmArg.
7593 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7594 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7595 DAG.getContext()->emitError(Node->getOperationName(0) +
7596 ": argument out of range.");
7597 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
7598 }
7599 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
7600}
7601
7602template <unsigned N>
7603static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
7604 SelectionDAG &DAG, bool IsSigned = false) {
7605 SDLoc DL(Node);
7606 EVT ResTy = Node->getValueType(0);
7607 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
7608
7609 // Check the ImmArg.
7610 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
7611 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
7612 DAG.getContext()->emitError(Node->getOperationName(0) +
7613 ": argument out of range.");
7614 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7615 }
7616 return DAG.getConstant(
7618 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
7619 DL, ResTy);
7620}
7621
7623 SDLoc DL(Node);
7624 EVT ResTy = Node->getValueType(0);
7625 SDValue Vec = Node->getOperand(2);
7626 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
7627 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
7628}
7629
7631 SDLoc DL(Node);
7632 EVT ResTy = Node->getValueType(0);
7633 SDValue One = DAG.getConstant(1, DL, ResTy);
7634 SDValue Bit =
7635 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
7636
7637 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
7638 DAG.getNOT(DL, Bit, ResTy));
7639}
7640
7641template <unsigned N>
7643 SDLoc DL(Node);
7644 EVT ResTy = Node->getValueType(0);
7645 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7646 // Check the unsigned ImmArg.
7647 if (!isUInt<N>(CImm->getZExtValue())) {
7648 DAG.getContext()->emitError(Node->getOperationName(0) +
7649 ": argument out of range.");
7650 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7651 }
7652
7653 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7654 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
7655
7656 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
7657}
7658
7659template <unsigned N>
7661 SDLoc DL(Node);
7662 EVT ResTy = Node->getValueType(0);
7663 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7664 // Check the unsigned ImmArg.
7665 if (!isUInt<N>(CImm->getZExtValue())) {
7666 DAG.getContext()->emitError(Node->getOperationName(0) +
7667 ": argument out of range.");
7668 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7669 }
7670
7671 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7672 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7673 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
7674}
7675
7676template <unsigned N>
7678 SDLoc DL(Node);
7679 EVT ResTy = Node->getValueType(0);
7680 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
7681 // Check the unsigned ImmArg.
7682 if (!isUInt<N>(CImm->getZExtValue())) {
7683 DAG.getContext()->emitError(Node->getOperationName(0) +
7684 ": argument out of range.");
7685 return DAG.getNode(ISD::UNDEF, DL, ResTy);
7686 }
7687
7688 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
7689 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
7690 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
7691}
7692
7693template <unsigned W>
7695 unsigned ResOp) {
7696 unsigned Imm = N->getConstantOperandVal(2);
7697 if (!isUInt<W>(Imm)) {
7698 const StringRef ErrorMsg = "argument out of range";
7699 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
7700 return DAG.getUNDEF(N->getValueType(0));
7701 }
7702 SDLoc DL(N);
7703 SDValue Vec = N->getOperand(1);
7704 SDValue Idx = DAG.getConstant(Imm, DL, MVT::i32);
7706 return DAG.getNode(ResOp, DL, N->getValueType(0), Vec, Idx, EltVT);
7707}
7708
7709static SDValue
7712 const LoongArchSubtarget &Subtarget) {
7713 SDLoc DL(N);
7714 switch (N->getConstantOperandVal(0)) {
7715 default:
7716 break;
7717 case Intrinsic::loongarch_lsx_vadd_b:
7718 case Intrinsic::loongarch_lsx_vadd_h:
7719 case Intrinsic::loongarch_lsx_vadd_w:
7720 case Intrinsic::loongarch_lsx_vadd_d:
7721 case Intrinsic::loongarch_lasx_xvadd_b:
7722 case Intrinsic::loongarch_lasx_xvadd_h:
7723 case Intrinsic::loongarch_lasx_xvadd_w:
7724 case Intrinsic::loongarch_lasx_xvadd_d:
7725 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7726 N->getOperand(2));
7727 case Intrinsic::loongarch_lsx_vaddi_bu:
7728 case Intrinsic::loongarch_lsx_vaddi_hu:
7729 case Intrinsic::loongarch_lsx_vaddi_wu:
7730 case Intrinsic::loongarch_lsx_vaddi_du:
7731 case Intrinsic::loongarch_lasx_xvaddi_bu:
7732 case Intrinsic::loongarch_lasx_xvaddi_hu:
7733 case Intrinsic::loongarch_lasx_xvaddi_wu:
7734 case Intrinsic::loongarch_lasx_xvaddi_du:
7735 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
7736 lowerVectorSplatImm<5>(N, 2, DAG));
7737 case Intrinsic::loongarch_lsx_vsub_b:
7738 case Intrinsic::loongarch_lsx_vsub_h:
7739 case Intrinsic::loongarch_lsx_vsub_w:
7740 case Intrinsic::loongarch_lsx_vsub_d:
7741 case Intrinsic::loongarch_lasx_xvsub_b:
7742 case Intrinsic::loongarch_lasx_xvsub_h:
7743 case Intrinsic::loongarch_lasx_xvsub_w:
7744 case Intrinsic::loongarch_lasx_xvsub_d:
7745 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7746 N->getOperand(2));
7747 case Intrinsic::loongarch_lsx_vsubi_bu:
7748 case Intrinsic::loongarch_lsx_vsubi_hu:
7749 case Intrinsic::loongarch_lsx_vsubi_wu:
7750 case Intrinsic::loongarch_lsx_vsubi_du:
7751 case Intrinsic::loongarch_lasx_xvsubi_bu:
7752 case Intrinsic::loongarch_lasx_xvsubi_hu:
7753 case Intrinsic::loongarch_lasx_xvsubi_wu:
7754 case Intrinsic::loongarch_lasx_xvsubi_du:
7755 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
7756 lowerVectorSplatImm<5>(N, 2, DAG));
7757 case Intrinsic::loongarch_lsx_vneg_b:
7758 case Intrinsic::loongarch_lsx_vneg_h:
7759 case Intrinsic::loongarch_lsx_vneg_w:
7760 case Intrinsic::loongarch_lsx_vneg_d:
7761 case Intrinsic::loongarch_lasx_xvneg_b:
7762 case Intrinsic::loongarch_lasx_xvneg_h:
7763 case Intrinsic::loongarch_lasx_xvneg_w:
7764 case Intrinsic::loongarch_lasx_xvneg_d:
7765 return DAG.getNode(
7766 ISD::SUB, DL, N->getValueType(0),
7767 DAG.getConstant(
7768 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
7769 /*isSigned=*/true),
7770 SDLoc(N), N->getValueType(0)),
7771 N->getOperand(1));
7772 case Intrinsic::loongarch_lsx_vmax_b:
7773 case Intrinsic::loongarch_lsx_vmax_h:
7774 case Intrinsic::loongarch_lsx_vmax_w:
7775 case Intrinsic::loongarch_lsx_vmax_d:
7776 case Intrinsic::loongarch_lasx_xvmax_b:
7777 case Intrinsic::loongarch_lasx_xvmax_h:
7778 case Intrinsic::loongarch_lasx_xvmax_w:
7779 case Intrinsic::loongarch_lasx_xvmax_d:
7780 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7781 N->getOperand(2));
7782 case Intrinsic::loongarch_lsx_vmax_bu:
7783 case Intrinsic::loongarch_lsx_vmax_hu:
7784 case Intrinsic::loongarch_lsx_vmax_wu:
7785 case Intrinsic::loongarch_lsx_vmax_du:
7786 case Intrinsic::loongarch_lasx_xvmax_bu:
7787 case Intrinsic::loongarch_lasx_xvmax_hu:
7788 case Intrinsic::loongarch_lasx_xvmax_wu:
7789 case Intrinsic::loongarch_lasx_xvmax_du:
7790 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7791 N->getOperand(2));
7792 case Intrinsic::loongarch_lsx_vmaxi_b:
7793 case Intrinsic::loongarch_lsx_vmaxi_h:
7794 case Intrinsic::loongarch_lsx_vmaxi_w:
7795 case Intrinsic::loongarch_lsx_vmaxi_d:
7796 case Intrinsic::loongarch_lasx_xvmaxi_b:
7797 case Intrinsic::loongarch_lasx_xvmaxi_h:
7798 case Intrinsic::loongarch_lasx_xvmaxi_w:
7799 case Intrinsic::loongarch_lasx_xvmaxi_d:
7800 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
7801 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7802 case Intrinsic::loongarch_lsx_vmaxi_bu:
7803 case Intrinsic::loongarch_lsx_vmaxi_hu:
7804 case Intrinsic::loongarch_lsx_vmaxi_wu:
7805 case Intrinsic::loongarch_lsx_vmaxi_du:
7806 case Intrinsic::loongarch_lasx_xvmaxi_bu:
7807 case Intrinsic::loongarch_lasx_xvmaxi_hu:
7808 case Intrinsic::loongarch_lasx_xvmaxi_wu:
7809 case Intrinsic::loongarch_lasx_xvmaxi_du:
7810 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
7811 lowerVectorSplatImm<5>(N, 2, DAG));
7812 case Intrinsic::loongarch_lsx_vmin_b:
7813 case Intrinsic::loongarch_lsx_vmin_h:
7814 case Intrinsic::loongarch_lsx_vmin_w:
7815 case Intrinsic::loongarch_lsx_vmin_d:
7816 case Intrinsic::loongarch_lasx_xvmin_b:
7817 case Intrinsic::loongarch_lasx_xvmin_h:
7818 case Intrinsic::loongarch_lasx_xvmin_w:
7819 case Intrinsic::loongarch_lasx_xvmin_d:
7820 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7821 N->getOperand(2));
7822 case Intrinsic::loongarch_lsx_vmin_bu:
7823 case Intrinsic::loongarch_lsx_vmin_hu:
7824 case Intrinsic::loongarch_lsx_vmin_wu:
7825 case Intrinsic::loongarch_lsx_vmin_du:
7826 case Intrinsic::loongarch_lasx_xvmin_bu:
7827 case Intrinsic::loongarch_lasx_xvmin_hu:
7828 case Intrinsic::loongarch_lasx_xvmin_wu:
7829 case Intrinsic::loongarch_lasx_xvmin_du:
7830 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7831 N->getOperand(2));
7832 case Intrinsic::loongarch_lsx_vmini_b:
7833 case Intrinsic::loongarch_lsx_vmini_h:
7834 case Intrinsic::loongarch_lsx_vmini_w:
7835 case Intrinsic::loongarch_lsx_vmini_d:
7836 case Intrinsic::loongarch_lasx_xvmini_b:
7837 case Intrinsic::loongarch_lasx_xvmini_h:
7838 case Intrinsic::loongarch_lasx_xvmini_w:
7839 case Intrinsic::loongarch_lasx_xvmini_d:
7840 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
7841 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
7842 case Intrinsic::loongarch_lsx_vmini_bu:
7843 case Intrinsic::loongarch_lsx_vmini_hu:
7844 case Intrinsic::loongarch_lsx_vmini_wu:
7845 case Intrinsic::loongarch_lsx_vmini_du:
7846 case Intrinsic::loongarch_lasx_xvmini_bu:
7847 case Intrinsic::loongarch_lasx_xvmini_hu:
7848 case Intrinsic::loongarch_lasx_xvmini_wu:
7849 case Intrinsic::loongarch_lasx_xvmini_du:
7850 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
7851 lowerVectorSplatImm<5>(N, 2, DAG));
7852 case Intrinsic::loongarch_lsx_vmul_b:
7853 case Intrinsic::loongarch_lsx_vmul_h:
7854 case Intrinsic::loongarch_lsx_vmul_w:
7855 case Intrinsic::loongarch_lsx_vmul_d:
7856 case Intrinsic::loongarch_lasx_xvmul_b:
7857 case Intrinsic::loongarch_lasx_xvmul_h:
7858 case Intrinsic::loongarch_lasx_xvmul_w:
7859 case Intrinsic::loongarch_lasx_xvmul_d:
7860 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
7861 N->getOperand(2));
7862 case Intrinsic::loongarch_lsx_vmadd_b:
7863 case Intrinsic::loongarch_lsx_vmadd_h:
7864 case Intrinsic::loongarch_lsx_vmadd_w:
7865 case Intrinsic::loongarch_lsx_vmadd_d:
7866 case Intrinsic::loongarch_lasx_xvmadd_b:
7867 case Intrinsic::loongarch_lasx_xvmadd_h:
7868 case Intrinsic::loongarch_lasx_xvmadd_w:
7869 case Intrinsic::loongarch_lasx_xvmadd_d: {
7870 EVT ResTy = N->getValueType(0);
7871 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
7872 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7873 N->getOperand(3)));
7874 }
7875 case Intrinsic::loongarch_lsx_vmsub_b:
7876 case Intrinsic::loongarch_lsx_vmsub_h:
7877 case Intrinsic::loongarch_lsx_vmsub_w:
7878 case Intrinsic::loongarch_lsx_vmsub_d:
7879 case Intrinsic::loongarch_lasx_xvmsub_b:
7880 case Intrinsic::loongarch_lasx_xvmsub_h:
7881 case Intrinsic::loongarch_lasx_xvmsub_w:
7882 case Intrinsic::loongarch_lasx_xvmsub_d: {
7883 EVT ResTy = N->getValueType(0);
7884 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
7885 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
7886 N->getOperand(3)));
7887 }
7888 case Intrinsic::loongarch_lsx_vdiv_b:
7889 case Intrinsic::loongarch_lsx_vdiv_h:
7890 case Intrinsic::loongarch_lsx_vdiv_w:
7891 case Intrinsic::loongarch_lsx_vdiv_d:
7892 case Intrinsic::loongarch_lasx_xvdiv_b:
7893 case Intrinsic::loongarch_lasx_xvdiv_h:
7894 case Intrinsic::loongarch_lasx_xvdiv_w:
7895 case Intrinsic::loongarch_lasx_xvdiv_d:
7896 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
7897 N->getOperand(2));
7898 case Intrinsic::loongarch_lsx_vdiv_bu:
7899 case Intrinsic::loongarch_lsx_vdiv_hu:
7900 case Intrinsic::loongarch_lsx_vdiv_wu:
7901 case Intrinsic::loongarch_lsx_vdiv_du:
7902 case Intrinsic::loongarch_lasx_xvdiv_bu:
7903 case Intrinsic::loongarch_lasx_xvdiv_hu:
7904 case Intrinsic::loongarch_lasx_xvdiv_wu:
7905 case Intrinsic::loongarch_lasx_xvdiv_du:
7906 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
7907 N->getOperand(2));
7908 case Intrinsic::loongarch_lsx_vmod_b:
7909 case Intrinsic::loongarch_lsx_vmod_h:
7910 case Intrinsic::loongarch_lsx_vmod_w:
7911 case Intrinsic::loongarch_lsx_vmod_d:
7912 case Intrinsic::loongarch_lasx_xvmod_b:
7913 case Intrinsic::loongarch_lasx_xvmod_h:
7914 case Intrinsic::loongarch_lasx_xvmod_w:
7915 case Intrinsic::loongarch_lasx_xvmod_d:
7916 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
7917 N->getOperand(2));
7918 case Intrinsic::loongarch_lsx_vmod_bu:
7919 case Intrinsic::loongarch_lsx_vmod_hu:
7920 case Intrinsic::loongarch_lsx_vmod_wu:
7921 case Intrinsic::loongarch_lsx_vmod_du:
7922 case Intrinsic::loongarch_lasx_xvmod_bu:
7923 case Intrinsic::loongarch_lasx_xvmod_hu:
7924 case Intrinsic::loongarch_lasx_xvmod_wu:
7925 case Intrinsic::loongarch_lasx_xvmod_du:
7926 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
7927 N->getOperand(2));
7928 case Intrinsic::loongarch_lsx_vand_v:
7929 case Intrinsic::loongarch_lasx_xvand_v:
7930 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
7931 N->getOperand(2));
7932 case Intrinsic::loongarch_lsx_vor_v:
7933 case Intrinsic::loongarch_lasx_xvor_v:
7934 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7935 N->getOperand(2));
7936 case Intrinsic::loongarch_lsx_vxor_v:
7937 case Intrinsic::loongarch_lasx_xvxor_v:
7938 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
7939 N->getOperand(2));
7940 case Intrinsic::loongarch_lsx_vnor_v:
7941 case Intrinsic::loongarch_lasx_xvnor_v: {
7942 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7943 N->getOperand(2));
7944 return DAG.getNOT(DL, Res, Res->getValueType(0));
7945 }
7946 case Intrinsic::loongarch_lsx_vandi_b:
7947 case Intrinsic::loongarch_lasx_xvandi_b:
7948 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
7949 lowerVectorSplatImm<8>(N, 2, DAG));
7950 case Intrinsic::loongarch_lsx_vori_b:
7951 case Intrinsic::loongarch_lasx_xvori_b:
7952 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
7953 lowerVectorSplatImm<8>(N, 2, DAG));
7954 case Intrinsic::loongarch_lsx_vxori_b:
7955 case Intrinsic::loongarch_lasx_xvxori_b:
7956 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
7957 lowerVectorSplatImm<8>(N, 2, DAG));
7958 case Intrinsic::loongarch_lsx_vsll_b:
7959 case Intrinsic::loongarch_lsx_vsll_h:
7960 case Intrinsic::loongarch_lsx_vsll_w:
7961 case Intrinsic::loongarch_lsx_vsll_d:
7962 case Intrinsic::loongarch_lasx_xvsll_b:
7963 case Intrinsic::loongarch_lasx_xvsll_h:
7964 case Intrinsic::loongarch_lasx_xvsll_w:
7965 case Intrinsic::loongarch_lasx_xvsll_d:
7966 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7967 truncateVecElts(N, DAG));
7968 case Intrinsic::loongarch_lsx_vslli_b:
7969 case Intrinsic::loongarch_lasx_xvslli_b:
7970 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7971 lowerVectorSplatImm<3>(N, 2, DAG));
7972 case Intrinsic::loongarch_lsx_vslli_h:
7973 case Intrinsic::loongarch_lasx_xvslli_h:
7974 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7975 lowerVectorSplatImm<4>(N, 2, DAG));
7976 case Intrinsic::loongarch_lsx_vslli_w:
7977 case Intrinsic::loongarch_lasx_xvslli_w:
7978 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7979 lowerVectorSplatImm<5>(N, 2, DAG));
7980 case Intrinsic::loongarch_lsx_vslli_d:
7981 case Intrinsic::loongarch_lasx_xvslli_d:
7982 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
7983 lowerVectorSplatImm<6>(N, 2, DAG));
7984 case Intrinsic::loongarch_lsx_vsrl_b:
7985 case Intrinsic::loongarch_lsx_vsrl_h:
7986 case Intrinsic::loongarch_lsx_vsrl_w:
7987 case Intrinsic::loongarch_lsx_vsrl_d:
7988 case Intrinsic::loongarch_lasx_xvsrl_b:
7989 case Intrinsic::loongarch_lasx_xvsrl_h:
7990 case Intrinsic::loongarch_lasx_xvsrl_w:
7991 case Intrinsic::loongarch_lasx_xvsrl_d:
7992 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7993 truncateVecElts(N, DAG));
7994 case Intrinsic::loongarch_lsx_vsrli_b:
7995 case Intrinsic::loongarch_lasx_xvsrli_b:
7996 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
7997 lowerVectorSplatImm<3>(N, 2, DAG));
7998 case Intrinsic::loongarch_lsx_vsrli_h:
7999 case Intrinsic::loongarch_lasx_xvsrli_h:
8000 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8001 lowerVectorSplatImm<4>(N, 2, DAG));
8002 case Intrinsic::loongarch_lsx_vsrli_w:
8003 case Intrinsic::loongarch_lasx_xvsrli_w:
8004 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8005 lowerVectorSplatImm<5>(N, 2, DAG));
8006 case Intrinsic::loongarch_lsx_vsrli_d:
8007 case Intrinsic::loongarch_lasx_xvsrli_d:
8008 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
8009 lowerVectorSplatImm<6>(N, 2, DAG));
8010 case Intrinsic::loongarch_lsx_vsra_b:
8011 case Intrinsic::loongarch_lsx_vsra_h:
8012 case Intrinsic::loongarch_lsx_vsra_w:
8013 case Intrinsic::loongarch_lsx_vsra_d:
8014 case Intrinsic::loongarch_lasx_xvsra_b:
8015 case Intrinsic::loongarch_lasx_xvsra_h:
8016 case Intrinsic::loongarch_lasx_xvsra_w:
8017 case Intrinsic::loongarch_lasx_xvsra_d:
8018 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8019 truncateVecElts(N, DAG));
8020 case Intrinsic::loongarch_lsx_vsrai_b:
8021 case Intrinsic::loongarch_lasx_xvsrai_b:
8022 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8023 lowerVectorSplatImm<3>(N, 2, DAG));
8024 case Intrinsic::loongarch_lsx_vsrai_h:
8025 case Intrinsic::loongarch_lasx_xvsrai_h:
8026 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8027 lowerVectorSplatImm<4>(N, 2, DAG));
8028 case Intrinsic::loongarch_lsx_vsrai_w:
8029 case Intrinsic::loongarch_lasx_xvsrai_w:
8030 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8031 lowerVectorSplatImm<5>(N, 2, DAG));
8032 case Intrinsic::loongarch_lsx_vsrai_d:
8033 case Intrinsic::loongarch_lasx_xvsrai_d:
8034 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
8035 lowerVectorSplatImm<6>(N, 2, DAG));
8036 case Intrinsic::loongarch_lsx_vclz_b:
8037 case Intrinsic::loongarch_lsx_vclz_h:
8038 case Intrinsic::loongarch_lsx_vclz_w:
8039 case Intrinsic::loongarch_lsx_vclz_d:
8040 case Intrinsic::loongarch_lasx_xvclz_b:
8041 case Intrinsic::loongarch_lasx_xvclz_h:
8042 case Intrinsic::loongarch_lasx_xvclz_w:
8043 case Intrinsic::loongarch_lasx_xvclz_d:
8044 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
8045 case Intrinsic::loongarch_lsx_vpcnt_b:
8046 case Intrinsic::loongarch_lsx_vpcnt_h:
8047 case Intrinsic::loongarch_lsx_vpcnt_w:
8048 case Intrinsic::loongarch_lsx_vpcnt_d:
8049 case Intrinsic::loongarch_lasx_xvpcnt_b:
8050 case Intrinsic::loongarch_lasx_xvpcnt_h:
8051 case Intrinsic::loongarch_lasx_xvpcnt_w:
8052 case Intrinsic::loongarch_lasx_xvpcnt_d:
8053 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
8054 case Intrinsic::loongarch_lsx_vbitclr_b:
8055 case Intrinsic::loongarch_lsx_vbitclr_h:
8056 case Intrinsic::loongarch_lsx_vbitclr_w:
8057 case Intrinsic::loongarch_lsx_vbitclr_d:
8058 case Intrinsic::loongarch_lasx_xvbitclr_b:
8059 case Intrinsic::loongarch_lasx_xvbitclr_h:
8060 case Intrinsic::loongarch_lasx_xvbitclr_w:
8061 case Intrinsic::loongarch_lasx_xvbitclr_d:
8062 return lowerVectorBitClear(N, DAG);
8063 case Intrinsic::loongarch_lsx_vbitclri_b:
8064 case Intrinsic::loongarch_lasx_xvbitclri_b:
8065 return lowerVectorBitClearImm<3>(N, DAG);
8066 case Intrinsic::loongarch_lsx_vbitclri_h:
8067 case Intrinsic::loongarch_lasx_xvbitclri_h:
8068 return lowerVectorBitClearImm<4>(N, DAG);
8069 case Intrinsic::loongarch_lsx_vbitclri_w:
8070 case Intrinsic::loongarch_lasx_xvbitclri_w:
8071 return lowerVectorBitClearImm<5>(N, DAG);
8072 case Intrinsic::loongarch_lsx_vbitclri_d:
8073 case Intrinsic::loongarch_lasx_xvbitclri_d:
8074 return lowerVectorBitClearImm<6>(N, DAG);
8075 case Intrinsic::loongarch_lsx_vbitset_b:
8076 case Intrinsic::loongarch_lsx_vbitset_h:
8077 case Intrinsic::loongarch_lsx_vbitset_w:
8078 case Intrinsic::loongarch_lsx_vbitset_d:
8079 case Intrinsic::loongarch_lasx_xvbitset_b:
8080 case Intrinsic::loongarch_lasx_xvbitset_h:
8081 case Intrinsic::loongarch_lasx_xvbitset_w:
8082 case Intrinsic::loongarch_lasx_xvbitset_d: {
8083 EVT VecTy = N->getValueType(0);
8084 SDValue One = DAG.getConstant(1, DL, VecTy);
8085 return DAG.getNode(
8086 ISD::OR, DL, VecTy, N->getOperand(1),
8087 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8088 }
8089 case Intrinsic::loongarch_lsx_vbitseti_b:
8090 case Intrinsic::loongarch_lasx_xvbitseti_b:
8091 return lowerVectorBitSetImm<3>(N, DAG);
8092 case Intrinsic::loongarch_lsx_vbitseti_h:
8093 case Intrinsic::loongarch_lasx_xvbitseti_h:
8094 return lowerVectorBitSetImm<4>(N, DAG);
8095 case Intrinsic::loongarch_lsx_vbitseti_w:
8096 case Intrinsic::loongarch_lasx_xvbitseti_w:
8097 return lowerVectorBitSetImm<5>(N, DAG);
8098 case Intrinsic::loongarch_lsx_vbitseti_d:
8099 case Intrinsic::loongarch_lasx_xvbitseti_d:
8100 return lowerVectorBitSetImm<6>(N, DAG);
8101 case Intrinsic::loongarch_lsx_vbitrev_b:
8102 case Intrinsic::loongarch_lsx_vbitrev_h:
8103 case Intrinsic::loongarch_lsx_vbitrev_w:
8104 case Intrinsic::loongarch_lsx_vbitrev_d:
8105 case Intrinsic::loongarch_lasx_xvbitrev_b:
8106 case Intrinsic::loongarch_lasx_xvbitrev_h:
8107 case Intrinsic::loongarch_lasx_xvbitrev_w:
8108 case Intrinsic::loongarch_lasx_xvbitrev_d: {
8109 EVT VecTy = N->getValueType(0);
8110 SDValue One = DAG.getConstant(1, DL, VecTy);
8111 return DAG.getNode(
8112 ISD::XOR, DL, VecTy, N->getOperand(1),
8113 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
8114 }
8115 case Intrinsic::loongarch_lsx_vbitrevi_b:
8116 case Intrinsic::loongarch_lasx_xvbitrevi_b:
8117 return lowerVectorBitRevImm<3>(N, DAG);
8118 case Intrinsic::loongarch_lsx_vbitrevi_h:
8119 case Intrinsic::loongarch_lasx_xvbitrevi_h:
8120 return lowerVectorBitRevImm<4>(N, DAG);
8121 case Intrinsic::loongarch_lsx_vbitrevi_w:
8122 case Intrinsic::loongarch_lasx_xvbitrevi_w:
8123 return lowerVectorBitRevImm<5>(N, DAG);
8124 case Intrinsic::loongarch_lsx_vbitrevi_d:
8125 case Intrinsic::loongarch_lasx_xvbitrevi_d:
8126 return lowerVectorBitRevImm<6>(N, DAG);
8127 case Intrinsic::loongarch_lsx_vfadd_s:
8128 case Intrinsic::loongarch_lsx_vfadd_d:
8129 case Intrinsic::loongarch_lasx_xvfadd_s:
8130 case Intrinsic::loongarch_lasx_xvfadd_d:
8131 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
8132 N->getOperand(2));
8133 case Intrinsic::loongarch_lsx_vfsub_s:
8134 case Intrinsic::loongarch_lsx_vfsub_d:
8135 case Intrinsic::loongarch_lasx_xvfsub_s:
8136 case Intrinsic::loongarch_lasx_xvfsub_d:
8137 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
8138 N->getOperand(2));
8139 case Intrinsic::loongarch_lsx_vfmul_s:
8140 case Intrinsic::loongarch_lsx_vfmul_d:
8141 case Intrinsic::loongarch_lasx_xvfmul_s:
8142 case Intrinsic::loongarch_lasx_xvfmul_d:
8143 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
8144 N->getOperand(2));
8145 case Intrinsic::loongarch_lsx_vfdiv_s:
8146 case Intrinsic::loongarch_lsx_vfdiv_d:
8147 case Intrinsic::loongarch_lasx_xvfdiv_s:
8148 case Intrinsic::loongarch_lasx_xvfdiv_d:
8149 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
8150 N->getOperand(2));
8151 case Intrinsic::loongarch_lsx_vfmadd_s:
8152 case Intrinsic::loongarch_lsx_vfmadd_d:
8153 case Intrinsic::loongarch_lasx_xvfmadd_s:
8154 case Intrinsic::loongarch_lasx_xvfmadd_d:
8155 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
8156 N->getOperand(2), N->getOperand(3));
8157 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
8158 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8159 N->getOperand(1), N->getOperand(2),
8160 legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
8161 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
8162 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
8163 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8164 N->getOperand(1), N->getOperand(2),
8165 legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
8166 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
8167 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
8168 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8169 N->getOperand(1), N->getOperand(2),
8170 legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
8171 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
8172 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
8173 N->getOperand(1), N->getOperand(2),
8174 legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
8175 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
8176 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
8177 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
8178 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
8179 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
8180 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
8181 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
8182 case Intrinsic::loongarch_lasx_xvreplgr2vr_d:
8183 return DAG.getNode(LoongArchISD::VREPLGR2VR, DL, N->getValueType(0),
8184 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8185 N->getOperand(1)));
8186 case Intrinsic::loongarch_lsx_vreplve_b:
8187 case Intrinsic::loongarch_lsx_vreplve_h:
8188 case Intrinsic::loongarch_lsx_vreplve_w:
8189 case Intrinsic::loongarch_lsx_vreplve_d:
8190 case Intrinsic::loongarch_lasx_xvreplve_b:
8191 case Intrinsic::loongarch_lasx_xvreplve_h:
8192 case Intrinsic::loongarch_lasx_xvreplve_w:
8193 case Intrinsic::loongarch_lasx_xvreplve_d:
8194 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
8195 N->getOperand(1),
8196 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
8197 N->getOperand(2)));
8198 case Intrinsic::loongarch_lsx_vpickve2gr_b:
8199 if (!Subtarget.is64Bit())
8200 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8201 break;
8202 case Intrinsic::loongarch_lsx_vpickve2gr_h:
8203 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
8204 if (!Subtarget.is64Bit())
8205 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8206 break;
8207 case Intrinsic::loongarch_lsx_vpickve2gr_w:
8208 if (!Subtarget.is64Bit())
8209 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_SEXT_ELT);
8210 break;
8211 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
8212 if (!Subtarget.is64Bit())
8213 return lowerVectorPickVE2GR<4>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8214 break;
8215 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
8216 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
8217 if (!Subtarget.is64Bit())
8218 return lowerVectorPickVE2GR<3>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8219 break;
8220 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
8221 if (!Subtarget.is64Bit())
8222 return lowerVectorPickVE2GR<2>(N, DAG, LoongArchISD::VPICK_ZEXT_ELT);
8223 break;
8224 case Intrinsic::loongarch_lsx_bz_b:
8225 case Intrinsic::loongarch_lsx_bz_h:
8226 case Intrinsic::loongarch_lsx_bz_w:
8227 case Intrinsic::loongarch_lsx_bz_d:
8228 case Intrinsic::loongarch_lasx_xbz_b:
8229 case Intrinsic::loongarch_lasx_xbz_h:
8230 case Intrinsic::loongarch_lasx_xbz_w:
8231 case Intrinsic::loongarch_lasx_xbz_d:
8232 if (!Subtarget.is64Bit())
8233 return DAG.getNode(LoongArchISD::VALL_ZERO, DL, N->getValueType(0),
8234 N->getOperand(1));
8235 break;
8236 case Intrinsic::loongarch_lsx_bz_v:
8237 case Intrinsic::loongarch_lasx_xbz_v:
8238 if (!Subtarget.is64Bit())
8239 return DAG.getNode(LoongArchISD::VANY_ZERO, DL, N->getValueType(0),
8240 N->getOperand(1));
8241 break;
8242 case Intrinsic::loongarch_lsx_bnz_b:
8243 case Intrinsic::loongarch_lsx_bnz_h:
8244 case Intrinsic::loongarch_lsx_bnz_w:
8245 case Intrinsic::loongarch_lsx_bnz_d:
8246 case Intrinsic::loongarch_lasx_xbnz_b:
8247 case Intrinsic::loongarch_lasx_xbnz_h:
8248 case Intrinsic::loongarch_lasx_xbnz_w:
8249 case Intrinsic::loongarch_lasx_xbnz_d:
8250 if (!Subtarget.is64Bit())
8251 return DAG.getNode(LoongArchISD::VALL_NONZERO, DL, N->getValueType(0),
8252 N->getOperand(1));
8253 break;
8254 case Intrinsic::loongarch_lsx_bnz_v:
8255 case Intrinsic::loongarch_lasx_xbnz_v:
8256 if (!Subtarget.is64Bit())
8257 return DAG.getNode(LoongArchISD::VANY_NONZERO, DL, N->getValueType(0),
8258 N->getOperand(1));
8259 break;
8260 case Intrinsic::loongarch_lasx_concat_128_s:
8261 case Intrinsic::loongarch_lasx_concat_128_d:
8262 case Intrinsic::loongarch_lasx_concat_128:
8263 return DAG.getNode(ISD::CONCAT_VECTORS, DL, N->getValueType(0),
8264 N->getOperand(1), N->getOperand(2));
8265 }
8266 return SDValue();
8267}
8268
8271 const LoongArchSubtarget &Subtarget) {
8272 // If the input to MOVGR2FR_W_LA64 is just MOVFR2GR_S_LA64 the the
8273 // conversion is unnecessary and can be replaced with the
8274 // MOVFR2GR_S_LA64 operand.
8275 SDValue Op0 = N->getOperand(0);
8276 if (Op0.getOpcode() == LoongArchISD::MOVFR2GR_S_LA64)
8277 return Op0.getOperand(0);
8278 return SDValue();
8279}
8280
8283 const LoongArchSubtarget &Subtarget) {
8284 // If the input to MOVFR2GR_S_LA64 is just MOVGR2FR_W_LA64 then the
8285 // conversion is unnecessary and can be replaced with the MOVGR2FR_W_LA64
8286 // operand.
8287 SDValue Op0 = N->getOperand(0);
8288 if (Op0->getOpcode() == LoongArchISD::MOVGR2FR_W_LA64) {
8289 assert(Op0.getOperand(0).getValueType() == N->getSimpleValueType(0) &&
8290 "Unexpected value type!");
8291 return Op0.getOperand(0);
8292 }
8293 return SDValue();
8294}
8295
8296static SDValue
8299 MVT VT = N->getSimpleValueType(0);
8300 unsigned NumBits = VT.getScalarSizeInBits();
8301
8302 // Simplify the inputs.
8303 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8304 APInt DemandedMask(APInt::getAllOnes(NumBits));
8305 if (TLI.SimplifyDemandedBits(SDValue(N, 0), DemandedMask, DCI))
8306 return SDValue(N, 0);
8307
8308 return SDValue();
8309}
8310
8311static SDValue
8314 const LoongArchSubtarget &Subtarget) {
8315 SDValue Op0 = N->getOperand(0);
8316 SDLoc DL(N);
8317
8318 // If the input to SplitPairF64 is just BuildPairF64 then the operation is
8319 // redundant. Instead, use BuildPairF64's operands directly.
8320 if (Op0->getOpcode() == LoongArchISD::BUILD_PAIR_F64)
8321 return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
8322
8323 if (Op0->isUndef()) {
8324 SDValue Lo = DAG.getUNDEF(MVT::i32);
8325 SDValue Hi = DAG.getUNDEF(MVT::i32);
8326 return DCI.CombineTo(N, Lo, Hi);
8327 }
8328
8329 // It's cheaper to materialise two 32-bit integers than to load a double
8330 // from the constant pool and transfer it to integer registers through the
8331 // stack.
8333 APInt V = C->getValueAPF().bitcastToAPInt();
8334 SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32);
8335 SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32);
8336 return DCI.CombineTo(N, Lo, Hi);
8337 }
8338
8339 return SDValue();
8340}
8341
8342/// Do target-specific dag combines on LoongArchISD::VANDN nodes.
8345 const LoongArchSubtarget &Subtarget) {
8346 SDValue N0 = N->getOperand(0);
8347 SDValue N1 = N->getOperand(1);
8348 MVT VT = N->getSimpleValueType(0);
8349 SDLoc DL(N);
8350
8351 // VANDN(undef, x) -> 0
8352 // VANDN(x, undef) -> 0
8353 if (N0.isUndef() || N1.isUndef())
8354 return DAG.getConstant(0, DL, VT);
8355
8356 // VANDN(0, x) -> x
8358 return N1;
8359
8360 // VANDN(x, 0) -> 0
8362 return DAG.getConstant(0, DL, VT);
8363
8364 // VANDN(x, -1) -> NOT(x) -> XOR(x, -1)
8366 return DAG.getNOT(DL, N0, VT);
8367
8368 // Turn VANDN back to AND if input is inverted.
8369 if (SDValue Not = isNOT(N0, DAG))
8370 return DAG.getNode(ISD::AND, DL, VT, DAG.getBitcast(VT, Not), N1);
8371
8372 // Folds for better commutativity:
8373 if (N1->hasOneUse()) {
8374 // VANDN(x,NOT(y)) -> AND(NOT(x),NOT(y)) -> NOT(OR(X,Y)).
8375 if (SDValue Not = isNOT(N1, DAG))
8376 return DAG.getNOT(
8377 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)), VT);
8378
8379 // VANDN(x, SplatVector(Imm)) -> AND(NOT(x), NOT(SplatVector(~Imm)))
8380 // -> NOT(OR(x, SplatVector(-Imm))
8381 // Combination is performed only when VT is v16i8/v32i8, using `vnori.b` to
8382 // gain benefits.
8383 if (!DCI.isBeforeLegalizeOps() && (VT == MVT::v16i8 || VT == MVT::v32i8) &&
8384 N1.getOpcode() == ISD::BUILD_VECTOR) {
8385 if (SDValue SplatValue =
8386 cast<BuildVectorSDNode>(N1.getNode())->getSplatValue()) {
8387 if (!N1->isOnlyUserOf(SplatValue.getNode()))
8388 return SDValue();
8389
8390 if (auto *C = dyn_cast<ConstantSDNode>(SplatValue)) {
8391 uint8_t NCVal = static_cast<uint8_t>(~(C->getSExtValue()));
8392 SDValue Not =
8393 DAG.getSplat(VT, DL, DAG.getTargetConstant(NCVal, DL, MVT::i8));
8394 return DAG.getNOT(
8395 DL, DAG.getNode(ISD::OR, DL, VT, N0, DAG.getBitcast(VT, Not)),
8396 VT);
8397 }
8398 }
8399 }
8400 }
8401
8402 return SDValue();
8403}
8404
8405static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp) {
8406 SDLoc DL(N);
8407 EVT VT = N->getValueType(0);
8408 SDValue Src = N->getOperand(0);
8409 EVT SrcVT = Src.getValueType();
8410
8411 unsigned DstElts = VT.getVectorNumElements();
8412 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8413 unsigned DstEltBits = VT.getScalarSizeInBits();
8414
8415 if (SrcEltBits >= DstEltBits)
8416 return SDValue();
8417
8418 MVT WidenEltVT = MVT::getIntegerVT(DstEltBits);
8419 EVT WidenSrcVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, DstElts);
8420
8421 SDValue Extend = DAG.getNode(ExtendOp, DL, WidenSrcVT, Src);
8422 return DAG.getNode(N->getOpcode(), DL, VT, Extend);
8423}
8424
8425// Merge two 64 to 32 convert instructions into one,
8426// e.g.
8427// vffint.s.l $vr0, $vr1, $vr2
8428// will convert 4 si64 into 4 float at once.
8429// or
8430// vftintrz.w.d $vr0, $vr1, $vr2
8431// which will convert 4 double into 4 si32 at once.
8432// also deal with their 256-bits LASX version.
8433static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode,
8434 unsigned BlockBits) {
8435 SDLoc DL(N);
8436 MVT DstVT = N->getSimpleValueType(0);
8437 SDValue Src = N->getOperand(0);
8438 MVT SrcVT = Src.getSimpleValueType();
8439 unsigned SrcBits = SrcVT.getSizeInBits();
8440
8442 unsigned BlockNumElts = BlockBits / SrcVT.getScalarSizeInBits();
8443 MVT BlockVT = MVT::getVectorVT(SrcVT.getScalarType(), BlockNumElts);
8444 if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
8445 Src.getOperand(0).getValueType() == BlockVT) {
8446 for (unsigned i = 0; i < Src.getNumOperands(); ++i)
8447 Blocks.push_back(Src.getOperand(i));
8448 } else if (SrcBits > BlockBits) {
8449 // Wider than one register: extract each BlockBits-wide sub-vector.
8450 for (unsigned i = 0; i < SrcBits / BlockBits; ++i)
8451 Blocks.push_back(
8452 DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, BlockVT, Src,
8453 DAG.getVectorIdxConstant(i * BlockNumElts, DL)));
8454 } else {
8455 BlockBits = SrcBits;
8456 Blocks.push_back(Src);
8457 }
8458
8459 MVT NativeVecVT = MVT::getVectorVT(DstVT.getScalarType(),
8460 BlockBits / DstVT.getScalarSizeInBits());
8462 for (unsigned i = 0; i < Blocks.size(); i += 2) {
8463 SDValue Lo = Blocks[i];
8464 SDValue Hi = Blocks.size() > 1 ? Blocks[i + 1] : Lo;
8465 SDValue Res = DAG.getNode(Opcode, DL, NativeVecVT, Hi, Lo);
8466
8467 if (BlockBits == 256) {
8468 SDValue Undef = DAG.getUNDEF(NativeVecVT);
8469 SmallVector<int, 8> Mask = {0, 1, 4, 5, 2, 3, 6, 7};
8470 Res = DAG.getVectorShuffle(NativeVecVT, DL, Res, Undef, Mask);
8471 Res = DAG.getBitcast(NativeVecVT, Res);
8472 }
8473
8474 Parts.push_back(Res);
8475 }
8476
8477 if (Blocks.size() == 1)
8478 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
8479 DAG.getVectorIdxConstant(0, DL));
8480 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
8481}
8482
8485 const LoongArchSubtarget &Subtarget) {
8486 SDLoc DL(N);
8487 EVT VT = N->getValueType(0);
8488 SDValue Src = N->getOperand(0);
8489 EVT SrcVT = Src.getValueType();
8490
8491 if (VT.isVector()) {
8492 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8493 unsigned DstEltBits = VT.getScalarSizeInBits();
8494 unsigned NumElts = VT.getVectorNumElements();
8495 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8496
8497 // Sign-extend src to avoid scalarization.
8498 if (SrcEltBits <= DstEltBits)
8499 return ExtendSrcToDst(N, DAG, ISD::SIGN_EXTEND);
8500
8501 if (SrcEltBits != 64 || DstEltBits != 32 || !isPowerOf2_32(NumElts))
8502 return SDValue();
8503
8504 if (!SrcVT.isSimple() || !VT.isSimple())
8505 return SDValue();
8506
8507 // Combine [x]vffint.s.l for vector si64 to float conversion.
8508 return MergeBlocksConvert(N, DAG, LoongArchISD::VFFINT, BlockBits);
8509 }
8510
8511 if (VT != MVT::f32 && VT != MVT::f64)
8512 return SDValue();
8513 if (VT == MVT::f32 && !Subtarget.hasBasicF())
8514 return SDValue();
8515 if (VT == MVT::f64 && !Subtarget.hasBasicD())
8516 return SDValue();
8517
8518 // Only optimize when the source and destination types have the same width.
8519 if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
8520 return SDValue();
8521
8522 // If the result of an integer load is only used by an integer-to-float
8523 // conversion, use a fp load instead. This eliminates an integer-to-float-move
8524 // (movgr2fr) instruction.
8525 if (ISD::isNormalLoad(Src.getNode()) && Src.hasOneUse() &&
8526 // Do not change the width of a volatile load. This condition check is
8527 // inspired by AArch64.
8528 !cast<LoadSDNode>(Src)->isVolatile()) {
8529 LoadSDNode *LN0 = cast<LoadSDNode>(Src);
8530 SDValue Load = DAG.getLoad(VT, DL, LN0->getChain(), LN0->getBasePtr(),
8531 LN0->getPointerInfo(), LN0->getAlign(),
8532 LN0->getMemOperand()->getFlags());
8533
8534 // Make sure successors of the original load stay after it by updating them
8535 // to use the new Chain.
8536 DAG.ReplaceAllUsesOfValueWith(SDValue(LN0, 1), Load.getValue(1));
8537 return DAG.getNode(LoongArchISD::SITOF, SDLoc(N), VT, Load);
8538 }
8539
8540 return SDValue();
8541}
8542
8545 const LoongArchSubtarget &Subtarget) {
8546 SDLoc DL(N);
8547 EVT VT = N->getValueType(0);
8548
8549 // Zero-extend src to avoid scalarization.
8550 if (VT.isVector())
8551 return ExtendSrcToDst(N, DAG, ISD::ZERO_EXTEND);
8552
8553 return SDValue();
8554}
8555
8556// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
8557// For example:
8558// v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
8559// Can be combined into:
8560// v4i32 = VFTINTRZ_W_D v2f64. v2f64
8563 const LoongArchSubtarget &Subtarget) {
8564 if (!Subtarget.hasExtLSX())
8565 return SDValue();
8566
8567 SDLoc DL(N);
8568 EVT DstVT = N->getValueType(0);
8569 SDValue Src = N->getOperand(0);
8570 EVT SrcVT = Src.getValueType();
8571 bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
8572
8573 if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
8574 return SDValue();
8575
8576 unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
8577 unsigned SrcBits = SrcVT.getSizeInBits();
8578 unsigned DstEltBits = DstVT.getScalarSizeInBits();
8579 unsigned NumElts = DstVT.getVectorNumElements();
8580 unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
8581
8582 if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
8583 return SDValue();
8584
8585 if (SrcBits % BlockBits != 0 && SrcBits != 128)
8586 return SDValue();
8587
8588 if (DstEltBits < 32) {
8589 MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
8590 SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
8591 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
8592 }
8593
8594 if (SrcEltBits != 64 || DstEltBits != 32)
8595 return SDValue();
8596
8597 if (!IsSigned) {
8598 // LASX already has pattern for double convert to uint32.
8599 if (Subtarget.hasExtLASX())
8600 return SDValue();
8601 MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
8602 SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
8603 return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
8604 }
8605
8606 return MergeBlocksConvert(N, DAG, LoongArchISD::VFTINTRZ, BlockBits);
8607}
8608
8609// Try to widen AND, OR and XOR nodes to VT in order to remove casts around
8610// logical operations, like in the example below.
8611// or (and (truncate x, truncate y)),
8612// (xor (truncate z, build_vector (constants)))
8613// Given a target type \p VT, we generate
8614// or (and x, y), (xor z, zext(build_vector (constants)))
8615// given x, y and z are of type \p VT. We can do so, if operands are either
8616// truncates from VT types, the second operand is a vector of constants, can
8617// be recursively promoted or is an existing extension we can extend further.
8619 SelectionDAG &DAG,
8620 const LoongArchSubtarget &Subtarget,
8621 unsigned Depth) {
8622 // Limit recursion to avoid excessive compile times.
8624 return SDValue();
8625
8626 if (!ISD::isBitwiseLogicOp(N.getOpcode()))
8627 return SDValue();
8628
8629 SDValue N0 = N.getOperand(0);
8630 SDValue N1 = N.getOperand(1);
8631
8632 const TargetLowering &TLI = DAG.getTargetLoweringInfo();
8633 if (!TLI.isOperationLegalOrPromote(N.getOpcode(), VT))
8634 return SDValue();
8635
8636 if (SDValue NN0 =
8637 PromoteMaskArithmetic(N0, DL, VT, DAG, Subtarget, Depth + 1))
8638 N0 = NN0;
8639 else {
8640 // The left side has to be a 'trunc'.
8641 bool LHSTrunc = N0.getOpcode() == ISD::TRUNCATE &&
8642 N0.getOperand(0).getValueType() == VT;
8643 if (LHSTrunc)
8644 N0 = N0.getOperand(0);
8645 else
8646 return SDValue();
8647 }
8648
8649 if (SDValue NN1 =
8650 PromoteMaskArithmetic(N1, DL, VT, DAG, Subtarget, Depth + 1))
8651 N1 = NN1;
8652 else {
8653 // The right side has to be a 'trunc', a (foldable) constant or an
8654 // existing extension we can extend further.
8655 bool RHSTrunc = N1.getOpcode() == ISD::TRUNCATE &&
8656 N1.getOperand(0).getValueType() == VT;
8657 if (RHSTrunc)
8658 N1 = N1.getOperand(0);
8659 else if (ISD::isExtVecInRegOpcode(N1.getOpcode()) && VT.is256BitVector() &&
8660 Subtarget.hasExtLASX() && N1.hasOneUse())
8661 N1 = DAG.getNode(N1.getOpcode(), DL, VT, N1.getOperand(0));
8662 // On 32-bit platform, i64 is an illegal integer scalar type, and
8663 // FoldConstantArithmetic will fail for v4i64. This may be optimized in the
8664 // future.
8665 else if (SDValue Cst =
8667 N1 = Cst;
8668 else
8669 return SDValue();
8670 }
8671
8672 return DAG.getNode(N.getOpcode(), DL, VT, N0, N1);
8673}
8674
8675// On LASX the type v4i1/v8i1/v16i1 may be legalized to v4i32/v8i16/v16i8, which
8676// is LSX-sized register. In most cases we actually compare or select LASX-sized
8677// registers and mixing the two types creates horrible code. This method
8678// optimizes some of the transition sequences.
8680 SelectionDAG &DAG,
8681 const LoongArchSubtarget &Subtarget) {
8682 EVT VT = N.getValueType();
8683 assert(VT.isVector() && "Expected vector type");
8684 assert((N.getOpcode() == ISD::ANY_EXTEND ||
8685 N.getOpcode() == ISD::ZERO_EXTEND ||
8686 N.getOpcode() == ISD::SIGN_EXTEND) &&
8687 "Invalid Node");
8688
8689 if (!Subtarget.hasExtLASX() || !VT.is256BitVector())
8690 return SDValue();
8691
8692 SDValue Narrow = N.getOperand(0);
8693 EVT NarrowVT = Narrow.getValueType();
8694
8695 // Generate the wide operation.
8696 SDValue Op = PromoteMaskArithmetic(Narrow, DL, VT, DAG, Subtarget, 0);
8697 if (!Op)
8698 return SDValue();
8699 switch (N.getOpcode()) {
8700 default:
8701 llvm_unreachable("Unexpected opcode");
8702 case ISD::ANY_EXTEND:
8703 return Op;
8704 case ISD::ZERO_EXTEND:
8705 return DAG.getZeroExtendInReg(Op, DL, NarrowVT);
8706 case ISD::SIGN_EXTEND:
8707 return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Op,
8708 DAG.getValueType(NarrowVT));
8709 }
8710}
8711
8714 const LoongArchSubtarget &Subtarget) {
8715 EVT VT = N->getValueType(0);
8716 SDLoc DL(N);
8717
8718 if (VT.isVector()) {
8719 if (SDValue R = PromoteMaskArithmetic(SDValue(N, 0), DL, DAG, Subtarget))
8720 return R;
8721
8722 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT) ||
8723 N->getValueSizeInBits(0) != N->getOperand(0).getValueSizeInBits() * 2)
8724 return SDValue();
8725
8726 if (SDValue R = matchHalfOf128BitLanes(N->getOperand(0), /*isLow=*/false)) {
8727 if (N->getOpcode() == ISD::SIGN_EXTEND)
8728 return DAG.getNode(LoongArchISD::VEXTH, DL, VT, R);
8729 if (N->getOpcode() == ISD::ZERO_EXTEND)
8730 return DAG.getNode(LoongArchISD::VEXTH_U, DL, VT, R);
8731 }
8732 }
8733
8734 return SDValue();
8735}
8736
8737static SDValue
8740 const LoongArchSubtarget &Subtarget) {
8741 SDLoc DL(N);
8742 EVT VT = N->getValueType(0);
8743
8744 if (VT.isVector() && N->getNumOperands() == 2)
8745 if (SDValue R = combineFP_ROUND(SDValue(N, 0), DL, DAG, Subtarget))
8746 return R;
8747
8748 return SDValue();
8749}
8750
8753 const LoongArchSubtarget &Subtarget) {
8754 if (DCI.isBeforeLegalizeOps())
8755 return SDValue();
8756
8757 EVT VT = N->getValueType(0);
8758 if (!VT.isVector())
8759 return SDValue();
8760
8761 if (!DAG.getTargetLoweringInfo().isTypeLegal(VT))
8762 return SDValue();
8763
8764 EVT EltVT = VT.getVectorElementType();
8765 if (!EltVT.isInteger())
8766 return SDValue();
8767
8768 SDValue Cond = N->getOperand(0);
8769 SDValue TrueVal = N->getOperand(1);
8770 SDValue FalseVal = N->getOperand(2);
8771
8772 // match:
8773 //
8774 // vselect (setcc shift, 0, seteq),
8775 // x,
8776 // rounded_shift
8777
8778 if (Cond.getOpcode() != ISD::SETCC)
8779 return SDValue();
8780
8781 if (!ISD::isConstantSplatVectorAllZeros(Cond.getOperand(1).getNode()))
8782 return SDValue();
8783
8784 auto *CC = cast<CondCodeSDNode>(Cond.getOperand(2));
8785 if (CC->get() != ISD::SETEQ)
8786 return SDValue();
8787
8788 SDValue Shift = Cond.getOperand(0);
8789
8790 // True branch must be original value:
8791 //
8792 // vselect cond, x, ...
8793
8794 SDValue X = TrueVal;
8795
8796 // Now match rounded shift pattern:
8797 //
8798 // add
8799 // (and
8800 // (srl X, shift-1)
8801 // 1)
8802 // (srl/sra X, shift)
8803
8804 if (FalseVal.getOpcode() != ISD::ADD)
8805 return SDValue();
8806
8807 SDValue Add0 = FalseVal.getOperand(0);
8808 SDValue Add1 = FalseVal.getOperand(1);
8809 SDValue And;
8810 SDValue Shr;
8811
8812 if (Add0.getOpcode() == ISD::AND) {
8813 And = Add0;
8814 Shr = Add1;
8815 } else if (Add1.getOpcode() == ISD::AND) {
8816 And = Add1;
8817 Shr = Add0;
8818 } else {
8819 return SDValue();
8820 }
8821
8822 // match:
8823 //
8824 // srl/sra X, shift
8825
8826 if (Shr.getOpcode() != ISD::SRL && Shr.getOpcode() != ISD::SRA)
8827 return SDValue();
8828
8829 if (Shr.getOperand(0) != X)
8830 return SDValue();
8831
8832 if (Shr.getOperand(1) != Shift)
8833 return SDValue();
8834
8835 // match:
8836 //
8837 // and
8838 // (srl X, shift-1)
8839 // 1
8840
8841 SDValue Srl = And.getOperand(0);
8842 SDValue One = And.getOperand(1);
8843 APInt SplatVal;
8844
8845 if (Srl.getOpcode() != ISD::SRL)
8846 return SDValue();
8847
8848 One = peekThroughBitcasts(One);
8849 if (!isConstantSplatVector(One, SplatVal, EltVT.getSizeInBits()))
8850 return SDValue();
8851
8852 if (SplatVal != 1)
8853 return SDValue();
8854
8855 if (Srl.getOperand(0) != X)
8856 return SDValue();
8857
8858 // match:
8859 //
8860 // shift-1
8861
8862 SDValue ShiftMinus1 = Srl.getOperand(1);
8863
8864 if (ShiftMinus1.getOpcode() != ISD::ADD)
8865 return SDValue();
8866
8867 if (ShiftMinus1.getOperand(0) != Shift)
8868 return SDValue();
8869
8871 return SDValue();
8872
8873 // We matched a rounded right shift pattern and can lower it
8874 // to a single vector rounded shift instruction.
8875
8876 SDLoc DL(N);
8877 return DAG.getNode(Shr.getOpcode() == ISD::SRL ? LoongArchISD::VSRLR
8878 : LoongArchISD::VSRAR,
8879 DL, VT, X, Shift);
8880}
8881
8883 DAGCombinerInfo &DCI) const {
8884 SelectionDAG &DAG = DCI.DAG;
8885 switch (N->getOpcode()) {
8886 default:
8887 break;
8888 case ISD::ADD:
8889 return performADDCombine(N, DAG, DCI, Subtarget);
8890 case ISD::AND:
8891 return performANDCombine(N, DAG, DCI, Subtarget);
8892 case ISD::OR:
8893 return performORCombine(N, DAG, DCI, Subtarget);
8894 case ISD::SETCC:
8895 return performSETCCCombine(N, DAG, DCI, Subtarget);
8896 case ISD::SELECT:
8897 return performSELECTCombine(N, DAG, DCI, Subtarget);
8898 case ISD::SHL:
8899 return performSHLCombine(N, DAG, DCI, Subtarget);
8900 case ISD::SRL:
8901 return performSRLCombine(N, DAG, DCI, Subtarget);
8902 case ISD::SUB:
8903 return performSUBCombine(N, DAG, DCI, Subtarget);
8904 case ISD::BITCAST:
8905 return performBITCASTCombine(N, DAG, DCI, Subtarget);
8906 case ISD::ANY_EXTEND:
8907 case ISD::ZERO_EXTEND:
8908 case ISD::SIGN_EXTEND:
8909 return performEXTENDCombine(N, DAG, DCI, Subtarget);
8910 case ISD::SINT_TO_FP:
8911 return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8912 case ISD::UINT_TO_FP:
8913 return performUINT_TO_FPCombine(N, DAG, DCI, Subtarget);
8914 case ISD::FP_TO_SINT:
8915 case ISD::FP_TO_UINT:
8916 return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
8917 case LoongArchISD::BITREV_W:
8918 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
8919 case LoongArchISD::BR_CC:
8920 return performBR_CCCombine(N, DAG, DCI, Subtarget);
8921 case LoongArchISD::SELECT_CC:
8922 return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
8924 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
8925 case LoongArchISD::MOVGR2FR_W_LA64:
8926 return performMOVGR2FR_WCombine(N, DAG, DCI, Subtarget);
8927 case LoongArchISD::MOVFR2GR_S_LA64:
8928 return performMOVFR2GR_SCombine(N, DAG, DCI, Subtarget);
8929 case LoongArchISD::CRC_W_B_W:
8930 case LoongArchISD::CRC_W_H_W:
8931 case LoongArchISD::CRCC_W_B_W:
8932 case LoongArchISD::CRCC_W_H_W:
8933 case LoongArchISD::VMSKLTZ:
8934 case LoongArchISD::XVMSKLTZ:
8935 return performDemandedBitsCombine(N, DAG, DCI);
8936 case LoongArchISD::SPLIT_PAIR_F64:
8937 return performSPLIT_PAIR_F64Combine(N, DAG, DCI, Subtarget);
8938 case LoongArchISD::VANDN:
8939 return performVANDNCombine(N, DAG, DCI, Subtarget);
8941 return performCONCAT_VECTORSCombine(N, DAG, DCI, Subtarget);
8942 case ISD::VSELECT:
8943 return performVSELECTCombine(N, DAG, DCI, Subtarget);
8944 case LoongArchISD::VPACKEV:
8945 case LoongArchISD::VPERMI:
8946 if (SDValue Result =
8947 combineFP_ROUND(SDValue(N, 0), SDLoc(N), DAG, Subtarget))
8948 return Result;
8949 }
8950 return SDValue();
8951}
8952
8955 if (!ZeroDivCheck)
8956 return MBB;
8957
8958 // Build instructions:
8959 // MBB:
8960 // div(or mod) $dst, $dividend, $divisor
8961 // bne $divisor, $zero, SinkMBB
8962 // BreakMBB:
8963 // break 7 // BRK_DIVZERO
8964 // SinkMBB:
8965 // fallthrough
8966 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
8967 MachineFunction::iterator It = ++MBB->getIterator();
8968 MachineFunction *MF = MBB->getParent();
8969 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
8970 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
8971 MF->insert(It, BreakMBB);
8972 MF->insert(It, SinkMBB);
8973
8974 // Transfer the remainder of MBB and its successor edges to SinkMBB.
8975 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
8976 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
8977
8978 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
8979 DebugLoc DL = MI.getDebugLoc();
8980 MachineOperand &Divisor = MI.getOperand(2);
8981 Register DivisorReg = Divisor.getReg();
8982
8983 // MBB:
8984 BuildMI(MBB, DL, TII.get(LoongArch::BNE))
8985 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
8986 .addReg(LoongArch::R0)
8987 .addMBB(SinkMBB);
8988 MBB->addSuccessor(BreakMBB);
8989 MBB->addSuccessor(SinkMBB);
8990
8991 // BreakMBB:
8992 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
8993 // definition of BRK_DIVZERO.
8994 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
8995 BreakMBB->addSuccessor(SinkMBB);
8996
8997 // Clear Divisor's kill flag.
8998 Divisor.setIsKill(false);
8999
9000 return SinkMBB;
9001}
9002
9003static MachineBasicBlock *
9005 const LoongArchSubtarget &Subtarget) {
9006 unsigned CondOpc;
9007 switch (MI.getOpcode()) {
9008 default:
9009 llvm_unreachable("Unexpected opcode");
9010 case LoongArch::PseudoVBZ:
9011 CondOpc = LoongArch::VSETEQZ_V;
9012 break;
9013 case LoongArch::PseudoVBZ_B:
9014 CondOpc = LoongArch::VSETANYEQZ_B;
9015 break;
9016 case LoongArch::PseudoVBZ_H:
9017 CondOpc = LoongArch::VSETANYEQZ_H;
9018 break;
9019 case LoongArch::PseudoVBZ_W:
9020 CondOpc = LoongArch::VSETANYEQZ_W;
9021 break;
9022 case LoongArch::PseudoVBZ_D:
9023 CondOpc = LoongArch::VSETANYEQZ_D;
9024 break;
9025 case LoongArch::PseudoVBNZ:
9026 CondOpc = LoongArch::VSETNEZ_V;
9027 break;
9028 case LoongArch::PseudoVBNZ_B:
9029 CondOpc = LoongArch::VSETALLNEZ_B;
9030 break;
9031 case LoongArch::PseudoVBNZ_H:
9032 CondOpc = LoongArch::VSETALLNEZ_H;
9033 break;
9034 case LoongArch::PseudoVBNZ_W:
9035 CondOpc = LoongArch::VSETALLNEZ_W;
9036 break;
9037 case LoongArch::PseudoVBNZ_D:
9038 CondOpc = LoongArch::VSETALLNEZ_D;
9039 break;
9040 case LoongArch::PseudoXVBZ:
9041 CondOpc = LoongArch::XVSETEQZ_V;
9042 break;
9043 case LoongArch::PseudoXVBZ_B:
9044 CondOpc = LoongArch::XVSETANYEQZ_B;
9045 break;
9046 case LoongArch::PseudoXVBZ_H:
9047 CondOpc = LoongArch::XVSETANYEQZ_H;
9048 break;
9049 case LoongArch::PseudoXVBZ_W:
9050 CondOpc = LoongArch::XVSETANYEQZ_W;
9051 break;
9052 case LoongArch::PseudoXVBZ_D:
9053 CondOpc = LoongArch::XVSETANYEQZ_D;
9054 break;
9055 case LoongArch::PseudoXVBNZ:
9056 CondOpc = LoongArch::XVSETNEZ_V;
9057 break;
9058 case LoongArch::PseudoXVBNZ_B:
9059 CondOpc = LoongArch::XVSETALLNEZ_B;
9060 break;
9061 case LoongArch::PseudoXVBNZ_H:
9062 CondOpc = LoongArch::XVSETALLNEZ_H;
9063 break;
9064 case LoongArch::PseudoXVBNZ_W:
9065 CondOpc = LoongArch::XVSETALLNEZ_W;
9066 break;
9067 case LoongArch::PseudoXVBNZ_D:
9068 CondOpc = LoongArch::XVSETALLNEZ_D;
9069 break;
9070 }
9071
9072 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9073 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9074 DebugLoc DL = MI.getDebugLoc();
9077
9078 MachineFunction *F = BB->getParent();
9079 MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
9080 MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
9081 MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
9082
9083 F->insert(It, FalseBB);
9084 F->insert(It, TrueBB);
9085 F->insert(It, SinkBB);
9086
9087 // Transfer the remainder of MBB and its successor edges to Sink.
9088 SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
9090
9091 // Insert the real instruction to BB.
9092 Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
9093 BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
9094
9095 // Insert branch.
9096 BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
9097 BB->addSuccessor(FalseBB);
9098 BB->addSuccessor(TrueBB);
9099
9100 // FalseBB.
9101 Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9102 BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
9103 .addReg(LoongArch::R0)
9104 .addImm(0);
9105 BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
9106 FalseBB->addSuccessor(SinkBB);
9107
9108 // TrueBB.
9109 Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9110 BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
9111 .addReg(LoongArch::R0)
9112 .addImm(1);
9113 TrueBB->addSuccessor(SinkBB);
9114
9115 // SinkBB: merge the results.
9116 BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
9117 MI.getOperand(0).getReg())
9118 .addReg(RD1)
9119 .addMBB(FalseBB)
9120 .addReg(RD2)
9121 .addMBB(TrueBB);
9122
9123 // The pseudo instruction is gone now.
9124 MI.eraseFromParent();
9125 return SinkBB;
9126}
9127
9128static MachineBasicBlock *
9130 const LoongArchSubtarget &Subtarget) {
9131 unsigned InsOp;
9132 unsigned BroadcastOp;
9133 unsigned HalfSize;
9134 switch (MI.getOpcode()) {
9135 default:
9136 llvm_unreachable("Unexpected opcode");
9137 case LoongArch::PseudoXVINSGR2VR_B:
9138 HalfSize = 16;
9139 BroadcastOp = LoongArch::XVREPLGR2VR_B;
9140 InsOp = LoongArch::XVEXTRINS_B;
9141 break;
9142 case LoongArch::PseudoXVINSGR2VR_H:
9143 HalfSize = 8;
9144 BroadcastOp = LoongArch::XVREPLGR2VR_H;
9145 InsOp = LoongArch::XVEXTRINS_H;
9146 break;
9147 }
9148 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9149 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
9150 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
9151 DebugLoc DL = MI.getDebugLoc();
9153 // XDst = vector_insert XSrc, Elt, Idx
9154 Register XDst = MI.getOperand(0).getReg();
9155 Register XSrc = MI.getOperand(1).getReg();
9156 Register Elt = MI.getOperand(2).getReg();
9157 unsigned Idx = MI.getOperand(3).getImm();
9158
9159 if (XSrc.isVirtual() && MRI.getVRegDef(XSrc)->isImplicitDef() &&
9160 Idx < HalfSize) {
9161 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
9162 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
9163
9164 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
9165 .addReg(XSrc, {}, LoongArch::sub_128);
9166 BuildMI(*BB, MI, DL,
9167 TII->get(HalfSize == 8 ? LoongArch::VINSGR2VR_H
9168 : LoongArch::VINSGR2VR_B),
9169 ScratchSubReg2)
9170 .addReg(ScratchSubReg1)
9171 .addReg(Elt)
9172 .addImm(Idx);
9173
9174 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), XDst)
9175 .addReg(ScratchSubReg2)
9176 .addImm(LoongArch::sub_128);
9177 } else {
9178 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9179 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9180
9181 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Elt);
9182
9183 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg2)
9184 .addReg(ScratchReg1)
9185 .addReg(XSrc)
9186 .addImm(Idx >= HalfSize ? 48 : 18);
9187
9188 BuildMI(*BB, MI, DL, TII->get(InsOp), XDst)
9189 .addReg(XSrc)
9190 .addReg(ScratchReg2)
9191 .addImm((Idx >= HalfSize ? Idx - HalfSize : Idx) * 17);
9192 }
9193
9194 MI.eraseFromParent();
9195 return BB;
9196}
9197
9200 const LoongArchSubtarget &Subtarget) {
9201 assert(Subtarget.hasExtLSX());
9202 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9203 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9204 DebugLoc DL = MI.getDebugLoc();
9206 Register Dst = MI.getOperand(0).getReg();
9207 Register Src = MI.getOperand(1).getReg();
9208
9209 unsigned BroadcastOp, CTOp, PickOp;
9210 switch (MI.getOpcode()) {
9211 default:
9212 llvm_unreachable("Unexpected opcode");
9213 case LoongArch::PseudoCTPOP_B:
9214 BroadcastOp = LoongArch::VREPLGR2VR_B;
9215 CTOp = LoongArch::VPCNT_B;
9216 PickOp = LoongArch::VPICKVE2GR_B;
9217 break;
9218 case LoongArch::PseudoCTPOP_H:
9219 case LoongArch::PseudoCTPOP_H_LA32:
9220 BroadcastOp = LoongArch::VREPLGR2VR_H;
9221 CTOp = LoongArch::VPCNT_H;
9222 PickOp = LoongArch::VPICKVE2GR_H;
9223 break;
9224 case LoongArch::PseudoCTPOP_W:
9225 case LoongArch::PseudoCTPOP_W_LA32:
9226 BroadcastOp = LoongArch::VREPLGR2VR_W;
9227 CTOp = LoongArch::VPCNT_W;
9228 PickOp = LoongArch::VPICKVE2GR_W;
9229 break;
9230 case LoongArch::PseudoCTPOP_D:
9231 BroadcastOp = LoongArch::VREPLGR2VR_D;
9232 CTOp = LoongArch::VPCNT_D;
9233 PickOp = LoongArch::VPICKVE2GR_D;
9234 break;
9235 }
9236
9237 Register ScratchReg1 = MRI.createVirtualRegister(RC);
9238 Register ScratchReg2 = MRI.createVirtualRegister(RC);
9239 BuildMI(*BB, MI, DL, TII->get(BroadcastOp), ScratchReg1).addReg(Src);
9240 BuildMI(*BB, MI, DL, TII->get(CTOp), ScratchReg2).addReg(ScratchReg1);
9241 BuildMI(*BB, MI, DL, TII->get(PickOp), Dst).addReg(ScratchReg2).addImm(0);
9242
9243 MI.eraseFromParent();
9244 return BB;
9245}
9246
9247static MachineBasicBlock *
9249 const LoongArchSubtarget &Subtarget) {
9250 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9251 const TargetRegisterClass *RC = &LoongArch::LSX128RegClass;
9252 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
9254 Register Dst = MI.getOperand(0).getReg();
9255 Register Src = MI.getOperand(1).getReg();
9256 DebugLoc DL = MI.getDebugLoc();
9257 unsigned EleBits = 8;
9258 unsigned NotOpc = 0;
9259 unsigned MskOpc;
9260
9261 switch (MI.getOpcode()) {
9262 default:
9263 llvm_unreachable("Unexpected opcode");
9264 case LoongArch::PseudoVMSKLTZ_B:
9265 MskOpc = LoongArch::VMSKLTZ_B;
9266 break;
9267 case LoongArch::PseudoVMSKLTZ_H:
9268 MskOpc = LoongArch::VMSKLTZ_H;
9269 EleBits = 16;
9270 break;
9271 case LoongArch::PseudoVMSKLTZ_W:
9272 MskOpc = LoongArch::VMSKLTZ_W;
9273 EleBits = 32;
9274 break;
9275 case LoongArch::PseudoVMSKLTZ_D:
9276 MskOpc = LoongArch::VMSKLTZ_D;
9277 EleBits = 64;
9278 break;
9279 case LoongArch::PseudoVMSKGEZ_B:
9280 MskOpc = LoongArch::VMSKGEZ_B;
9281 break;
9282 case LoongArch::PseudoVMSKEQZ_B:
9283 MskOpc = LoongArch::VMSKNZ_B;
9284 NotOpc = LoongArch::VNOR_V;
9285 break;
9286 case LoongArch::PseudoVMSKNEZ_B:
9287 MskOpc = LoongArch::VMSKNZ_B;
9288 break;
9289 case LoongArch::PseudoXVMSKLTZ_B:
9290 MskOpc = LoongArch::XVMSKLTZ_B;
9291 RC = &LoongArch::LASX256RegClass;
9292 break;
9293 case LoongArch::PseudoXVMSKLTZ_H:
9294 MskOpc = LoongArch::XVMSKLTZ_H;
9295 RC = &LoongArch::LASX256RegClass;
9296 EleBits = 16;
9297 break;
9298 case LoongArch::PseudoXVMSKLTZ_W:
9299 MskOpc = LoongArch::XVMSKLTZ_W;
9300 RC = &LoongArch::LASX256RegClass;
9301 EleBits = 32;
9302 break;
9303 case LoongArch::PseudoXVMSKLTZ_D:
9304 MskOpc = LoongArch::XVMSKLTZ_D;
9305 RC = &LoongArch::LASX256RegClass;
9306 EleBits = 64;
9307 break;
9308 case LoongArch::PseudoXVMSKGEZ_B:
9309 MskOpc = LoongArch::XVMSKGEZ_B;
9310 RC = &LoongArch::LASX256RegClass;
9311 break;
9312 case LoongArch::PseudoXVMSKEQZ_B:
9313 MskOpc = LoongArch::XVMSKNZ_B;
9314 NotOpc = LoongArch::XVNOR_V;
9315 RC = &LoongArch::LASX256RegClass;
9316 break;
9317 case LoongArch::PseudoXVMSKNEZ_B:
9318 MskOpc = LoongArch::XVMSKNZ_B;
9319 RC = &LoongArch::LASX256RegClass;
9320 break;
9321 }
9322
9323 Register Msk = MRI.createVirtualRegister(RC);
9324 if (NotOpc) {
9325 Register Tmp = MRI.createVirtualRegister(RC);
9326 BuildMI(*BB, MI, DL, TII->get(MskOpc), Tmp).addReg(Src);
9327 BuildMI(*BB, MI, DL, TII->get(NotOpc), Msk)
9328 .addReg(Tmp)
9329 .addReg(Tmp);
9330 } else {
9331 BuildMI(*BB, MI, DL, TII->get(MskOpc), Msk).addReg(Src);
9332 }
9333
9334 if (TRI->getRegSizeInBits(*RC) > 128) {
9335 Register Lo = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9336 Register Hi = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
9337 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Lo)
9338 .addReg(Msk)
9339 .addImm(0);
9340 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPICKVE2GR_WU), Hi)
9341 .addReg(Msk)
9342 .addImm(4);
9343 BuildMI(*BB, MI, DL,
9344 TII->get(Subtarget.is64Bit() ? LoongArch::BSTRINS_D
9345 : LoongArch::BSTRINS_W),
9346 Dst)
9347 .addReg(Lo)
9348 .addReg(Hi)
9349 .addImm(256 / EleBits - 1)
9350 .addImm(128 / EleBits);
9351 } else {
9352 BuildMI(*BB, MI, DL, TII->get(LoongArch::VPICKVE2GR_HU), Dst)
9353 .addReg(Msk)
9354 .addImm(0);
9355 }
9356
9357 MI.eraseFromParent();
9358 return BB;
9359}
9360
9361static MachineBasicBlock *
9363 const LoongArchSubtarget &Subtarget) {
9364 assert(MI.getOpcode() == LoongArch::SplitPairF64Pseudo &&
9365 "Unexpected instruction");
9366
9367 MachineFunction &MF = *BB->getParent();
9368 DebugLoc DL = MI.getDebugLoc();
9370 Register LoReg = MI.getOperand(0).getReg();
9371 Register HiReg = MI.getOperand(1).getReg();
9372 Register SrcReg = MI.getOperand(2).getReg();
9373
9374 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFR2GR_S_64), LoReg).addReg(SrcReg);
9375 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVFRH2GR_S), HiReg)
9376 .addReg(SrcReg, getKillRegState(MI.getOperand(2).isKill()));
9377 MI.eraseFromParent(); // The pseudo instruction is gone now.
9378 return BB;
9379}
9380
9381static MachineBasicBlock *
9383 const LoongArchSubtarget &Subtarget) {
9384 assert(MI.getOpcode() == LoongArch::BuildPairF64Pseudo &&
9385 "Unexpected instruction");
9386
9387 MachineFunction &MF = *BB->getParent();
9388 DebugLoc DL = MI.getDebugLoc();
9391 Register TmpReg = MRI.createVirtualRegister(&LoongArch::FPR64RegClass);
9392 Register DstReg = MI.getOperand(0).getReg();
9393 Register LoReg = MI.getOperand(1).getReg();
9394 Register HiReg = MI.getOperand(2).getReg();
9395
9396 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FR_W_64), TmpReg)
9397 .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill()));
9398 BuildMI(*BB, MI, DL, TII.get(LoongArch::MOVGR2FRH_W), DstReg)
9399 .addReg(TmpReg)
9400 .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill()));
9401 MI.eraseFromParent(); // The pseudo instruction is gone now.
9402 return BB;
9403}
9404
9406 switch (MI.getOpcode()) {
9407 default:
9408 return false;
9409 case LoongArch::Select_GPR_Using_CC_GPR:
9410 return true;
9411 }
9412}
9413
9414static MachineBasicBlock *
9416 const LoongArchSubtarget &Subtarget) {
9417 // To "insert" Select_* instructions, we actually have to insert the triangle
9418 // control-flow pattern. The incoming instructions know the destination vreg
9419 // to set, the condition code register to branch on, the true/false values to
9420 // select between, and the condcode to use to select the appropriate branch.
9421 //
9422 // We produce the following control flow:
9423 // HeadMBB
9424 // | \
9425 // | IfFalseMBB
9426 // | /
9427 // TailMBB
9428 //
9429 // When we find a sequence of selects we attempt to optimize their emission
9430 // by sharing the control flow. Currently we only handle cases where we have
9431 // multiple selects with the exact same condition (same LHS, RHS and CC).
9432 // The selects may be interleaved with other instructions if the other
9433 // instructions meet some requirements we deem safe:
9434 // - They are not pseudo instructions.
9435 // - They are debug instructions. Otherwise,
9436 // - They do not have side-effects, do not access memory and their inputs do
9437 // not depend on the results of the select pseudo-instructions.
9438 // The TrueV/FalseV operands of the selects cannot depend on the result of
9439 // previous selects in the sequence.
9440 // These conditions could be further relaxed. See the X86 target for a
9441 // related approach and more information.
9442
9443 Register LHS = MI.getOperand(1).getReg();
9444 Register RHS;
9445 if (MI.getOperand(2).isReg())
9446 RHS = MI.getOperand(2).getReg();
9447 auto CC = static_cast<unsigned>(MI.getOperand(3).getImm());
9448
9449 SmallVector<MachineInstr *, 4> SelectDebugValues;
9450 SmallSet<Register, 4> SelectDests;
9451 SelectDests.insert(MI.getOperand(0).getReg());
9452
9453 MachineInstr *LastSelectPseudo = &MI;
9454 for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI);
9455 SequenceMBBI != E; ++SequenceMBBI) {
9456 if (SequenceMBBI->isDebugInstr())
9457 continue;
9458 if (isSelectPseudo(*SequenceMBBI)) {
9459 if (SequenceMBBI->getOperand(1).getReg() != LHS ||
9460 !SequenceMBBI->getOperand(2).isReg() ||
9461 SequenceMBBI->getOperand(2).getReg() != RHS ||
9462 SequenceMBBI->getOperand(3).getImm() != CC ||
9463 SelectDests.count(SequenceMBBI->getOperand(4).getReg()) ||
9464 SelectDests.count(SequenceMBBI->getOperand(5).getReg()))
9465 break;
9466 LastSelectPseudo = &*SequenceMBBI;
9467 SequenceMBBI->collectDebugValues(SelectDebugValues);
9468 SelectDests.insert(SequenceMBBI->getOperand(0).getReg());
9469 continue;
9470 }
9471 if (SequenceMBBI->hasUnmodeledSideEffects() ||
9472 SequenceMBBI->mayLoadOrStore() ||
9473 SequenceMBBI->usesCustomInsertionHook())
9474 break;
9475 if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) {
9476 return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg());
9477 }))
9478 break;
9479 }
9480
9481 const LoongArchInstrInfo &TII = *Subtarget.getInstrInfo();
9482 const BasicBlock *LLVM_BB = BB->getBasicBlock();
9483 DebugLoc DL = MI.getDebugLoc();
9485
9486 MachineBasicBlock *HeadMBB = BB;
9487 MachineFunction *F = BB->getParent();
9488 MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
9489 MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
9490
9491 F->insert(I, IfFalseMBB);
9492 F->insert(I, TailMBB);
9493
9494 // Set the call frame size on entry to the new basic blocks.
9495 unsigned CallFrameSize = TII.getCallFrameSizeAt(*LastSelectPseudo);
9496 IfFalseMBB->setCallFrameSize(CallFrameSize);
9497 TailMBB->setCallFrameSize(CallFrameSize);
9498
9499 // Transfer debug instructions associated with the selects to TailMBB.
9500 for (MachineInstr *DebugInstr : SelectDebugValues) {
9501 TailMBB->push_back(DebugInstr->removeFromParent());
9502 }
9503
9504 // Move all instructions after the sequence to TailMBB.
9505 TailMBB->splice(TailMBB->end(), HeadMBB,
9506 std::next(LastSelectPseudo->getIterator()), HeadMBB->end());
9507 // Update machine-CFG edges by transferring all successors of the current
9508 // block to the new block which will contain the Phi nodes for the selects.
9509 TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
9510 // Set the successors for HeadMBB.
9511 HeadMBB->addSuccessor(IfFalseMBB);
9512 HeadMBB->addSuccessor(TailMBB);
9513
9514 // Insert appropriate branch.
9515 if (MI.getOperand(2).isImm())
9516 BuildMI(HeadMBB, DL, TII.get(CC))
9517 .addReg(LHS)
9518 .addImm(MI.getOperand(2).getImm())
9519 .addMBB(TailMBB);
9520 else
9521 BuildMI(HeadMBB, DL, TII.get(CC)).addReg(LHS).addReg(RHS).addMBB(TailMBB);
9522
9523 // IfFalseMBB just falls through to TailMBB.
9524 IfFalseMBB->addSuccessor(TailMBB);
9525
9526 // Create PHIs for all of the select pseudo-instructions.
9527 auto SelectMBBI = MI.getIterator();
9528 auto SelectEnd = std::next(LastSelectPseudo->getIterator());
9529 auto InsertionPoint = TailMBB->begin();
9530 while (SelectMBBI != SelectEnd) {
9531 auto Next = std::next(SelectMBBI);
9532 if (isSelectPseudo(*SelectMBBI)) {
9533 // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
9534 BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(),
9535 TII.get(LoongArch::PHI), SelectMBBI->getOperand(0).getReg())
9536 .addReg(SelectMBBI->getOperand(4).getReg())
9537 .addMBB(HeadMBB)
9538 .addReg(SelectMBBI->getOperand(5).getReg())
9539 .addMBB(IfFalseMBB);
9540 SelectMBBI->eraseFromParent();
9541 }
9542 SelectMBBI = Next;
9543 }
9544
9545 F->getProperties().resetNoPHIs();
9546 return TailMBB;
9547}
9548
9549MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
9550 MachineInstr &MI, MachineBasicBlock *BB) const {
9551 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
9552 DebugLoc DL = MI.getDebugLoc();
9553
9554 switch (MI.getOpcode()) {
9555 default:
9556 llvm_unreachable("Unexpected instr type to insert");
9557 case LoongArch::DIV_W:
9558 case LoongArch::DIV_WU:
9559 case LoongArch::MOD_W:
9560 case LoongArch::MOD_WU:
9561 case LoongArch::DIV_D:
9562 case LoongArch::DIV_DU:
9563 case LoongArch::MOD_D:
9564 case LoongArch::MOD_DU:
9565 return insertDivByZeroTrap(MI, BB);
9566 break;
9567 case LoongArch::WRFCSR: {
9568 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
9569 LoongArch::FCSR0 + MI.getOperand(0).getImm())
9570 .addReg(MI.getOperand(1).getReg());
9571 MI.eraseFromParent();
9572 return BB;
9573 }
9574 case LoongArch::RDFCSR: {
9575 MachineInstr *ReadFCSR =
9576 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
9577 MI.getOperand(0).getReg())
9578 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
9579 ReadFCSR->getOperand(1).setIsUndef();
9580 MI.eraseFromParent();
9581 return BB;
9582 }
9583 case LoongArch::Select_GPR_Using_CC_GPR:
9584 return emitSelectPseudo(MI, BB, Subtarget);
9585 case LoongArch::BuildPairF64Pseudo:
9586 return emitBuildPairF64Pseudo(MI, BB, Subtarget);
9587 case LoongArch::SplitPairF64Pseudo:
9588 return emitSplitPairF64Pseudo(MI, BB, Subtarget);
9589 case LoongArch::PseudoVBZ:
9590 case LoongArch::PseudoVBZ_B:
9591 case LoongArch::PseudoVBZ_H:
9592 case LoongArch::PseudoVBZ_W:
9593 case LoongArch::PseudoVBZ_D:
9594 case LoongArch::PseudoVBNZ:
9595 case LoongArch::PseudoVBNZ_B:
9596 case LoongArch::PseudoVBNZ_H:
9597 case LoongArch::PseudoVBNZ_W:
9598 case LoongArch::PseudoVBNZ_D:
9599 case LoongArch::PseudoXVBZ:
9600 case LoongArch::PseudoXVBZ_B:
9601 case LoongArch::PseudoXVBZ_H:
9602 case LoongArch::PseudoXVBZ_W:
9603 case LoongArch::PseudoXVBZ_D:
9604 case LoongArch::PseudoXVBNZ:
9605 case LoongArch::PseudoXVBNZ_B:
9606 case LoongArch::PseudoXVBNZ_H:
9607 case LoongArch::PseudoXVBNZ_W:
9608 case LoongArch::PseudoXVBNZ_D:
9609 return emitVecCondBranchPseudo(MI, BB, Subtarget);
9610 case LoongArch::PseudoXVINSGR2VR_B:
9611 case LoongArch::PseudoXVINSGR2VR_H:
9612 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
9613 case LoongArch::PseudoCTPOP_B:
9614 case LoongArch::PseudoCTPOP_H:
9615 case LoongArch::PseudoCTPOP_W:
9616 case LoongArch::PseudoCTPOP_D:
9617 case LoongArch::PseudoCTPOP_H_LA32:
9618 case LoongArch::PseudoCTPOP_W_LA32:
9619 return emitPseudoCTPOP(MI, BB, Subtarget);
9620 case LoongArch::PseudoVMSKLTZ_B:
9621 case LoongArch::PseudoVMSKLTZ_H:
9622 case LoongArch::PseudoVMSKLTZ_W:
9623 case LoongArch::PseudoVMSKLTZ_D:
9624 case LoongArch::PseudoVMSKGEZ_B:
9625 case LoongArch::PseudoVMSKEQZ_B:
9626 case LoongArch::PseudoVMSKNEZ_B:
9627 case LoongArch::PseudoXVMSKLTZ_B:
9628 case LoongArch::PseudoXVMSKLTZ_H:
9629 case LoongArch::PseudoXVMSKLTZ_W:
9630 case LoongArch::PseudoXVMSKLTZ_D:
9631 case LoongArch::PseudoXVMSKGEZ_B:
9632 case LoongArch::PseudoXVMSKEQZ_B:
9633 case LoongArch::PseudoXVMSKNEZ_B:
9634 return emitPseudoVMSKCOND(MI, BB, Subtarget);
9635 case TargetOpcode::STATEPOINT:
9636 // STATEPOINT is a pseudo instruction which has no implicit defs/uses
9637 // while bl call instruction (where statepoint will be lowered at the
9638 // end) has implicit def. This def is early-clobber as it will be set at
9639 // the moment of the call and earlier than any use is read.
9640 // Add this implicit dead def here as a workaround.
9641 MI.addOperand(*MI.getMF(),
9643 LoongArch::R1, /*isDef*/ true,
9644 /*isImp*/ true, /*isKill*/ false, /*isDead*/ true,
9645 /*isUndef*/ false, /*isEarlyClobber*/ true));
9646 if (!Subtarget.is64Bit())
9647 report_fatal_error("STATEPOINT is only supported on 64-bit targets");
9648 return emitPatchPoint(MI, BB);
9649 case LoongArch::PROBED_STACKALLOC_DYN:
9650 return emitDynamicProbedAlloc(MI, BB);
9651 }
9652}
9653
9655 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
9656 unsigned *Fast) const {
9657 if (!Subtarget.hasUAL())
9658 return false;
9659
9660 // TODO: set reasonable speed number.
9661 if (Fast)
9662 *Fast = 1;
9663 return true;
9664}
9665
9666//===----------------------------------------------------------------------===//
9667// Calling Convention Implementation
9668//===----------------------------------------------------------------------===//
9669
9670// Eight general-purpose registers a0-a7 used for passing integer arguments,
9671// with a0-a1 reused to return values. Generally, the GPRs are used to pass
9672// fixed-point arguments, and floating-point arguments when no FPR is available
9673// or with soft float ABI.
9674const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
9675 LoongArch::R7, LoongArch::R8, LoongArch::R9,
9676 LoongArch::R10, LoongArch::R11};
9677
9678// PreserveNone calling convention:
9679// Arguments may be passed in any general-purpose registers except:
9680// - R1 : return address register
9681// - R22 : frame pointer
9682// - R31 : base pointer
9683//
9684// All general-purpose registers are treated as caller-saved,
9685// except R1 (RA) and R22 (FP).
9686//
9687// Non-volatile registers are allocated first so that a function
9688// can call normal functions without having to spill and reload
9689// argument registers.
9691 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26,
9692 LoongArch::R27, LoongArch::R28, LoongArch::R29, LoongArch::R30,
9693 LoongArch::R4, LoongArch::R5, LoongArch::R6, LoongArch::R7,
9694 LoongArch::R8, LoongArch::R9, LoongArch::R10, LoongArch::R11,
9695 LoongArch::R12, LoongArch::R13, LoongArch::R14, LoongArch::R15,
9696 LoongArch::R16, LoongArch::R17, LoongArch::R18, LoongArch::R19,
9697 LoongArch::R20};
9698
9699// Eight floating-point registers fa0-fa7 used for passing floating-point
9700// arguments, and fa0-fa1 are also used to return values.
9701const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
9702 LoongArch::F3, LoongArch::F4, LoongArch::F5,
9703 LoongArch::F6, LoongArch::F7};
9704// FPR32 and FPR64 alias each other.
9706 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
9707 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
9708
9709const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
9710 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
9711 LoongArch::VR6, LoongArch::VR7};
9712
9713const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
9714 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
9715 LoongArch::XR6, LoongArch::XR7};
9716
9718 switch (State.getCallingConv()) {
9720 if (!State.isVarArg())
9721 return State.AllocateReg(PreserveNoneArgGPRs);
9722 [[fallthrough]];
9723 default:
9724 return State.AllocateReg(ArgGPRs);
9725 }
9726}
9727
9728// Pass a 2*GRLen argument that has been split into two GRLen values through
9729// registers or the stack as necessary.
9730static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
9731 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
9732 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
9733 ISD::ArgFlagsTy ArgFlags2) {
9734 unsigned GRLenInBytes = GRLen / 8;
9735 if (Register Reg = allocateArgGPR(State)) {
9736 // At least one half can be passed via register.
9737 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
9738 VA1.getLocVT(), CCValAssign::Full));
9739 } else {
9740 // Both halves must be passed on the stack, with proper alignment.
9741 Align StackAlign =
9742 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
9743 State.addLoc(
9745 State.AllocateStack(GRLenInBytes, StackAlign),
9746 VA1.getLocVT(), CCValAssign::Full));
9747 State.addLoc(CCValAssign::getMem(
9748 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9749 LocVT2, CCValAssign::Full));
9750 return false;
9751 }
9752 if (Register Reg = allocateArgGPR(State)) {
9753 // The second half can also be passed via register.
9754 State.addLoc(
9755 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
9756 } else {
9757 // The second half is passed via the stack, without additional alignment.
9758 State.addLoc(CCValAssign::getMem(
9759 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
9760 LocVT2, CCValAssign::Full));
9761 }
9762 return false;
9763}
9764
9765// Implements the LoongArch calling convention. Returns true upon failure.
9767 unsigned ValNo, MVT ValVT,
9768 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
9769 CCState &State, bool IsRet, Type *OrigTy) {
9770 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
9771 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
9772 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
9773 MVT LocVT = ValVT;
9774
9775 // Any return value split into more than two values can't be returned
9776 // directly.
9777 if (IsRet && ValNo > 1)
9778 return true;
9779
9780 // If passing a variadic argument, or if no FPR is available.
9781 bool UseGPRForFloat = true;
9782
9783 switch (ABI) {
9784 default:
9785 llvm_unreachable("Unexpected ABI");
9786 break;
9791 UseGPRForFloat = ArgFlags.isVarArg();
9792 break;
9795 break;
9796 }
9797
9798 // If this is a variadic argument, the LoongArch calling convention requires
9799 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
9800 // byte alignment. An aligned register should be used regardless of whether
9801 // the original argument was split during legalisation or not. The argument
9802 // will not be passed by registers if the original type is larger than
9803 // 2*GRLen, so the register alignment rule does not apply.
9804 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
9805 if (ArgFlags.isVarArg() &&
9806 ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
9807 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
9808 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
9809 // Skip 'odd' register if necessary.
9810 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
9811 State.AllocateReg(ArgGPRs);
9812 }
9813
9814 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
9815 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
9816 State.getPendingArgFlags();
9817
9818 assert(PendingLocs.size() == PendingArgFlags.size() &&
9819 "PendingLocs and PendingArgFlags out of sync");
9820
9821 // FPR32 and FPR64 alias each other.
9822 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
9823 UseGPRForFloat = true;
9824
9825 if (UseGPRForFloat && ValVT == MVT::f32) {
9826 LocVT = GRLenVT;
9827 LocInfo = CCValAssign::BCvt;
9828 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
9829 LocVT = MVT::i64;
9830 LocInfo = CCValAssign::BCvt;
9831 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
9832 // Handle passing f64 on LA32D with a soft float ABI or when floating point
9833 // registers are exhausted.
9834 assert(PendingLocs.empty() && "Can't lower f64 if it is split");
9835 // Depending on available argument GPRS, f64 may be passed in a pair of
9836 // GPRs, split between a GPR and the stack, or passed completely on the
9837 // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these
9838 // cases.
9839 MCRegister Reg = allocateArgGPR(State);
9840 if (!Reg) {
9841 int64_t StackOffset = State.AllocateStack(8, Align(8));
9842 State.addLoc(
9843 CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9844 return false;
9845 }
9846 LocVT = MVT::i32;
9847 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9848 MCRegister HiReg = allocateArgGPR(State);
9849 if (HiReg) {
9850 State.addLoc(
9851 CCValAssign::getCustomReg(ValNo, ValVT, HiReg, LocVT, LocInfo));
9852 } else {
9853 int64_t StackOffset = State.AllocateStack(4, Align(4));
9854 State.addLoc(
9855 CCValAssign::getCustomMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9856 }
9857 return false;
9858 }
9859
9860 // Split arguments might be passed indirectly, so keep track of the pending
9861 // values.
9862 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
9863 LocVT = GRLenVT;
9864 LocInfo = CCValAssign::Indirect;
9865 PendingLocs.push_back(
9866 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
9867 PendingArgFlags.push_back(ArgFlags);
9868 if (!ArgFlags.isSplitEnd()) {
9869 return false;
9870 }
9871 }
9872
9873 // If the split argument only had two elements, it should be passed directly
9874 // in registers or on the stack.
9875 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
9876 PendingLocs.size() <= 2) {
9877 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
9878 // Apply the normal calling convention rules to the first half of the
9879 // split argument.
9880 CCValAssign VA = PendingLocs[0];
9881 ISD::ArgFlagsTy AF = PendingArgFlags[0];
9882 PendingLocs.clear();
9883 PendingArgFlags.clear();
9884 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
9885 ArgFlags);
9886 }
9887
9888 // Allocate to a register if possible, or else a stack slot.
9889 Register Reg;
9890 unsigned StoreSizeBytes = GRLen / 8;
9891 Align StackAlign = Align(GRLen / 8);
9892
9893 if (ValVT == MVT::f32 && !UseGPRForFloat) {
9894 Reg = State.AllocateReg(ArgFPR32s);
9895 } else if (ValVT == MVT::f64 && !UseGPRForFloat) {
9896 Reg = State.AllocateReg(ArgFPR64s);
9897 } else if (ValVT.is128BitVector()) {
9898 Reg = State.AllocateReg(ArgVRs);
9899 UseGPRForFloat = false;
9900 StoreSizeBytes = 16;
9901 StackAlign = Align(16);
9902 } else if (ValVT.is256BitVector()) {
9903 Reg = State.AllocateReg(ArgXRs);
9904 UseGPRForFloat = false;
9905 StoreSizeBytes = 32;
9906 StackAlign = Align(32);
9907 } else {
9908 Reg = allocateArgGPR(State);
9909 }
9910
9911 unsigned StackOffset =
9912 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
9913
9914 // If we reach this point and PendingLocs is non-empty, we must be at the
9915 // end of a split argument that must be passed indirectly.
9916 if (!PendingLocs.empty()) {
9917 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
9918 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
9919 for (auto &It : PendingLocs) {
9920 if (Reg)
9921 It.convertToReg(Reg);
9922 else
9923 It.convertToMem(StackOffset);
9924 State.addLoc(It);
9925 }
9926 PendingLocs.clear();
9927 PendingArgFlags.clear();
9928 return false;
9929 }
9930 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
9931 "Expected an GRLenVT at this stage");
9932
9933 if (Reg) {
9934 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
9935 return false;
9936 }
9937
9938 // When a floating-point value is passed on the stack, no bit-cast is needed.
9939 if (ValVT.isFloatingPoint()) {
9940 LocVT = ValVT;
9941 LocInfo = CCValAssign::Full;
9942 }
9943
9944 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
9945 return false;
9946}
9947
9948void LoongArchTargetLowering::analyzeInputArgs(
9949 MachineFunction &MF, CCState &CCInfo,
9950 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
9951 LoongArchCCAssignFn Fn) const {
9952 FunctionType *FType = MF.getFunction().getFunctionType();
9953 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
9954 MVT ArgVT = Ins[i].VT;
9955 Type *ArgTy = nullptr;
9956 if (IsRet)
9957 ArgTy = FType->getReturnType();
9958 else if (Ins[i].isOrigArg())
9959 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
9961 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
9962 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
9963 CCInfo, IsRet, ArgTy)) {
9964 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
9965 << '\n');
9966 llvm_unreachable("");
9967 }
9968 }
9969}
9970
9971void LoongArchTargetLowering::analyzeOutputArgs(
9972 MachineFunction &MF, CCState &CCInfo,
9973 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
9974 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
9975 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
9976 MVT ArgVT = Outs[i].VT;
9977 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
9979 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
9980 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
9981 CCInfo, IsRet, OrigTy)) {
9982 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
9983 << "\n");
9984 llvm_unreachable("");
9985 }
9986 }
9987}
9988
9989// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
9990// values.
9992 const CCValAssign &VA, const SDLoc &DL) {
9993 switch (VA.getLocInfo()) {
9994 default:
9995 llvm_unreachable("Unexpected CCValAssign::LocInfo");
9996 case CCValAssign::Full:
9998 break;
9999 case CCValAssign::BCvt:
10000 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10001 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
10002 else
10003 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
10004 break;
10005 }
10006 return Val;
10007}
10008
10010 const CCValAssign &VA, const SDLoc &DL,
10011 const ISD::InputArg &In,
10012 const LoongArchTargetLowering &TLI) {
10015 EVT LocVT = VA.getLocVT();
10016 SDValue Val;
10017 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
10018 Register VReg = RegInfo.createVirtualRegister(RC);
10019 RegInfo.addLiveIn(VA.getLocReg(), VReg);
10020 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
10021
10022 // If input is sign extended from 32 bits, note it for the OptW pass.
10023 if (In.isOrigArg()) {
10024 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
10025 if (OrigArg->getType()->isIntegerTy()) {
10026 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
10027 // An input zero extended from i31 can also be considered sign extended.
10028 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
10029 (BitWidth < 32 && In.Flags.isZExt())) {
10032 LAFI->addSExt32Register(VReg);
10033 }
10034 }
10035 }
10036
10037 return convertLocVTToValVT(DAG, Val, VA, DL);
10038}
10039
10040// The caller is responsible for loading the full value if the argument is
10041// passed with CCValAssign::Indirect.
10043 const CCValAssign &VA, const SDLoc &DL) {
10045 MachineFrameInfo &MFI = MF.getFrameInfo();
10046 EVT ValVT = VA.getValVT();
10047 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
10048 /*IsImmutable=*/true);
10049 SDValue FIN = DAG.getFrameIndex(
10051
10052 ISD::LoadExtType ExtType;
10053 switch (VA.getLocInfo()) {
10054 default:
10055 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10056 case CCValAssign::Full:
10058 case CCValAssign::BCvt:
10059 ExtType = ISD::NON_EXTLOAD;
10060 break;
10061 }
10062 return DAG.getExtLoad(
10063 ExtType, DL, VA.getLocVT(), Chain, FIN,
10065}
10066
10068 const CCValAssign &VA,
10069 const CCValAssign &HiVA,
10070 const SDLoc &DL) {
10071 assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 &&
10072 "Unexpected VA");
10074 MachineFrameInfo &MFI = MF.getFrameInfo();
10076
10077 assert(VA.isRegLoc() && "Expected register VA assignment");
10078
10079 Register LoVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10080 RegInfo.addLiveIn(VA.getLocReg(), LoVReg);
10081 SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32);
10082 SDValue Hi;
10083 if (HiVA.isMemLoc()) {
10084 // Second half of f64 is passed on the stack.
10085 int FI = MFI.CreateFixedObject(4, HiVA.getLocMemOffset(),
10086 /*IsImmutable=*/true);
10087 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
10088 Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN,
10090 } else {
10091 // Second half of f64 is passed in another GPR.
10092 Register HiVReg = RegInfo.createVirtualRegister(&LoongArch::GPRRegClass);
10093 RegInfo.addLiveIn(HiVA.getLocReg(), HiVReg);
10094 Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32);
10095 }
10096 return DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64, Lo, Hi);
10097}
10098
10100 const CCValAssign &VA, const SDLoc &DL) {
10101 EVT LocVT = VA.getLocVT();
10102
10103 switch (VA.getLocInfo()) {
10104 default:
10105 llvm_unreachable("Unexpected CCValAssign::LocInfo");
10106 case CCValAssign::Full:
10107 break;
10108 case CCValAssign::BCvt:
10109 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
10110 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
10111 else
10112 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
10113 break;
10114 }
10115 return Val;
10116}
10117
10118static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
10119 CCValAssign::LocInfo LocInfo,
10120 ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
10121 CCState &State) {
10122 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
10123 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
10124 // s0 s1 s2 s3 s4 s5 s6 s7 s8
10125 static const MCPhysReg GPRList[] = {
10126 LoongArch::R23, LoongArch::R24, LoongArch::R25,
10127 LoongArch::R26, LoongArch::R27, LoongArch::R28,
10128 LoongArch::R29, LoongArch::R30, LoongArch::R31};
10129 if (MCRegister Reg = State.AllocateReg(GPRList)) {
10130 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10131 return false;
10132 }
10133 }
10134
10135 if (LocVT == MVT::f32) {
10136 // Pass in STG registers: F1, F2, F3, F4
10137 // fs0,fs1,fs2,fs3
10138 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
10139 LoongArch::F26, LoongArch::F27};
10140 if (MCRegister Reg = State.AllocateReg(FPR32List)) {
10141 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10142 return false;
10143 }
10144 }
10145
10146 if (LocVT == MVT::f64) {
10147 // Pass in STG registers: D1, D2, D3, D4
10148 // fs4,fs5,fs6,fs7
10149 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
10150 LoongArch::F30_64, LoongArch::F31_64};
10151 if (MCRegister Reg = State.AllocateReg(FPR64List)) {
10152 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
10153 return false;
10154 }
10155 }
10156
10157 report_fatal_error("No registers left in GHC calling convention");
10158 return true;
10159}
10160
10161// Transform physical registers into virtual registers.
10163 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10164 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
10165 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
10166
10168
10169 switch (CallConv) {
10170 default:
10171 llvm_unreachable("Unsupported calling convention");
10172 case CallingConv::C:
10173 case CallingConv::Fast:
10176 break;
10177 case CallingConv::GHC:
10178 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
10179 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
10181 "GHC calling convention requires the F and D extensions");
10182 }
10183
10184 const Function &Func = MF.getFunction();
10185 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10186 MVT GRLenVT = Subtarget.getGRLenVT();
10187 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
10188
10189 // Check if this function has any musttail calls. If so, incoming indirect
10190 // arg pointers must be saved in virtual registers so they survive across
10191 // basic blocks (the SelectionDAG is cleared between BBs). Only do this
10192 // when needed to avoid adding register pressure to non-musttail functions.
10193 bool HasMusttail = llvm::any_of(Func, [](const BasicBlock &BB) {
10194 return llvm::any_of(BB, [](const Instruction &I) {
10195 if (const auto *CI = dyn_cast<CallInst>(&I))
10196 return CI->isMustTailCall();
10197 return false;
10198 });
10199 });
10200 // Used with varargs to acumulate store chains.
10201 std::vector<SDValue> OutChains;
10202
10203 // Assign locations to all of the incoming arguments.
10205 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10206
10207 if (CallConv == CallingConv::GHC)
10209 else
10210 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
10211
10212 for (unsigned i = 0, e = ArgLocs.size(), InsIdx = 0; i != e; ++i, ++InsIdx) {
10213 CCValAssign &VA = ArgLocs[i];
10214 SDValue ArgValue;
10215 // Passing f64 on LA32D with a soft float ABI must be handled as a special
10216 // case.
10217 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10218 assert(VA.needsCustom());
10219 ArgValue = unpackF64OnLA32DSoftABI(DAG, Chain, VA, ArgLocs[++i], DL);
10220 } else if (VA.isRegLoc())
10221 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[InsIdx], *this);
10222 else
10223 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
10224 if (VA.getLocInfo() == CCValAssign::Indirect) {
10225 // If the original argument was split and passed by reference, we need to
10226 // load all parts of it here (using the same address).
10227 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
10229 unsigned ArgIndex = Ins[InsIdx].OrigArgIndex;
10230 if (HasMusttail) {
10233 Register VReg =
10234 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
10235 Chain = DAG.getCopyToReg(Chain, DL, VReg, ArgValue);
10236 LAFI->setIncomingIndirectArg(ArgIndex, VReg);
10237 }
10238 unsigned ArgPartOffset = Ins[InsIdx].PartOffset;
10239 assert(ArgPartOffset == 0);
10240 while (i + 1 != e && Ins[InsIdx + 1].OrigArgIndex == ArgIndex) {
10241 CCValAssign &PartVA = ArgLocs[i + 1];
10242 unsigned PartOffset = Ins[InsIdx + 1].PartOffset - ArgPartOffset;
10243 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10244 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
10245 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
10247 ++i;
10248 ++InsIdx;
10249 }
10250 continue;
10251 }
10252 InVals.push_back(ArgValue);
10253 }
10254
10255 if (IsVarArg) {
10257 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
10258 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
10259 MachineFrameInfo &MFI = MF.getFrameInfo();
10260 MachineRegisterInfo &RegInfo = MF.getRegInfo();
10261 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
10262
10263 // Offset of the first variable argument from stack pointer, and size of
10264 // the vararg save area. For now, the varargs save area is either zero or
10265 // large enough to hold a0-a7.
10266 int VaArgOffset, VarArgsSaveSize;
10267
10268 // If all registers are allocated, then all varargs must be passed on the
10269 // stack and we don't need to save any argregs.
10270 if (ArgRegs.size() == Idx) {
10271 VaArgOffset = CCInfo.getStackSize();
10272 VarArgsSaveSize = 0;
10273 } else {
10274 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
10275 VaArgOffset = -VarArgsSaveSize;
10276 }
10277
10278 // Record the frame index of the first variable argument
10279 // which is a value necessary to VASTART.
10280 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10281 LoongArchFI->setVarArgsFrameIndex(FI);
10282
10283 // If saving an odd number of registers then create an extra stack slot to
10284 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
10285 // offsets to even-numbered registered remain 2*GRLen-aligned.
10286 if (Idx % 2) {
10287 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
10288 true);
10289 VarArgsSaveSize += GRLenInBytes;
10290 }
10291
10292 // Copy the integer registers that may have been used for passing varargs
10293 // to the vararg save area.
10294 for (unsigned I = Idx; I < ArgRegs.size();
10295 ++I, VaArgOffset += GRLenInBytes) {
10296 const Register Reg = RegInfo.createVirtualRegister(RC);
10297 RegInfo.addLiveIn(ArgRegs[I], Reg);
10298 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
10299 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
10300 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10301 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
10303 cast<StoreSDNode>(Store.getNode())
10304 ->getMemOperand()
10305 ->setValue((Value *)nullptr);
10306 OutChains.push_back(Store);
10307 }
10308 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
10309 }
10310
10311 // All stores are grouped in one node to allow the matching between
10312 // the size of Ins and InVals. This only happens for vararg functions.
10313 if (!OutChains.empty()) {
10314 OutChains.push_back(Chain);
10315 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
10316 }
10317
10318 return Chain;
10319}
10320
10322 return CI->isTailCall();
10323}
10324
10325// Check if the return value is used as only a return value, as otherwise
10326// we can't perform a tail-call.
10328 SDValue &Chain) const {
10329 if (N->getNumValues() != 1)
10330 return false;
10331 if (!N->hasNUsesOfValue(1, 0))
10332 return false;
10333
10334 SDNode *Copy = *N->user_begin();
10335 if (Copy->getOpcode() != ISD::CopyToReg)
10336 return false;
10337
10338 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
10339 // isn't safe to perform a tail call.
10340 if (Copy->getGluedNode())
10341 return false;
10342
10343 // The copy must be used by a LoongArchISD::RET, and nothing else.
10344 bool HasRet = false;
10345 for (SDNode *Node : Copy->users()) {
10346 if (Node->getOpcode() != LoongArchISD::RET)
10347 return false;
10348 HasRet = true;
10349 }
10350
10351 if (!HasRet)
10352 return false;
10353
10354 Chain = Copy->getOperand(0);
10355 return true;
10356}
10357
10358// Check whether the call is eligible for tail call optimization.
10359bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
10360 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
10361 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
10362
10363 auto CalleeCC = CLI.CallConv;
10364 auto &Outs = CLI.Outs;
10365 auto &Caller = MF.getFunction();
10366 auto CallerCC = Caller.getCallingConv();
10367
10368 bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
10369
10370 // Byval parameters hand the function a pointer directly into the stack area
10371 // we want to reuse during a tail call. Working around this *is* possible
10372 // but less efficient and uglier in LowerCall. For musttail, there is no
10373 // workaround today: a byval arg requires a local copy that becomes invalid
10374 // after the tail call deallocates the caller's frame, so rejecting here
10375 // (and triggering reportFatalInternalError in LowerCall) is safer than
10376 // miscompiling.
10377 for (auto &Arg : Outs)
10378 if (Arg.Flags.isByVal())
10379 return false;
10380
10381 // musttail bypasses the remaining checks: the checks either reject cases
10382 // we handle specially (indirect args are forwarded via incoming pointers,
10383 // stack-passed args reuse the matching incoming layout, sret is forwarded
10384 // like any other pointer arg) or are optimizations not applicable to
10385 // mandatory tail calls.
10386 if (IsMustTail)
10387 return true;
10388
10389 // Do not tail call opt if the stack is used to pass parameters.
10390 if (CCInfo.getStackSize() != 0)
10391 return false;
10392
10393 // Do not tail call opt if any parameters need to be passed indirectly.
10394 for (auto &VA : ArgLocs)
10395 if (VA.getLocInfo() == CCValAssign::Indirect)
10396 return false;
10397
10398 // Do not tail call opt if either caller or callee uses struct return
10399 // semantics.
10400 auto IsCallerStructRet = Caller.hasStructRetAttr();
10401 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
10402 if (IsCallerStructRet || IsCalleeStructRet)
10403 return false;
10404
10405 // The callee has to preserve all registers the caller needs to preserve.
10406 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
10407 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
10408 if (CalleeCC != CallerCC) {
10409 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
10410 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
10411 return false;
10412 }
10413 return true;
10414}
10415
10417 return DAG.getDataLayout().getPrefTypeAlign(
10418 VT.getTypeForEVT(*DAG.getContext()));
10419}
10420
10421// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
10422// and output parameter nodes.
10423SDValue
10425 SmallVectorImpl<SDValue> &InVals) const {
10426 SelectionDAG &DAG = CLI.DAG;
10427 SDLoc &DL = CLI.DL;
10429 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
10431 SDValue Chain = CLI.Chain;
10432 SDValue Callee = CLI.Callee;
10433 CallingConv::ID CallConv = CLI.CallConv;
10434 bool IsVarArg = CLI.IsVarArg;
10435 EVT PtrVT = getPointerTy(DAG.getDataLayout());
10436 MVT GRLenVT = Subtarget.getGRLenVT();
10437 bool &IsTailCall = CLI.IsTailCall;
10438
10440
10441 // Analyze the operands of the call, assigning locations to each operand.
10443 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
10444
10445 if (CallConv == CallingConv::GHC)
10446 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
10447 else
10448 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
10449
10450 // Check if it's really possible to do a tail call.
10451 if (IsTailCall)
10452 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
10453
10454 if (IsTailCall)
10455 ++NumTailCalls;
10456 else if (CLI.CB && CLI.CB->isMustTailCall())
10457 report_fatal_error("failed to perform tail call elimination on a call "
10458 "site marked musttail");
10459
10460 // Get a count of how many bytes are to be pushed on the stack.
10461 unsigned NumBytes = ArgCCInfo.getStackSize();
10462
10463 // Create local copies for byval args.
10464 SmallVector<SDValue> ByValArgs;
10465 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10466 ISD::ArgFlagsTy Flags = Outs[i].Flags;
10467 if (!Flags.isByVal())
10468 continue;
10469
10470 SDValue Arg = OutVals[i];
10471 unsigned Size = Flags.getByValSize();
10472 Align Alignment = Flags.getNonZeroByValAlign();
10473
10474 int FI =
10475 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
10476 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
10477 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
10478
10479 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, Alignment,
10480 /*IsVolatile=*/false,
10481 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
10483 ByValArgs.push_back(FIPtr);
10484 }
10485
10486 if (!IsTailCall)
10487 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
10488
10489 // Copy argument values to their designated locations.
10491 SmallVector<SDValue> MemOpChains;
10492 SDValue StackPtr;
10493 for (unsigned i = 0, j = 0, e = ArgLocs.size(), OutIdx = 0; i != e;
10494 ++i, ++OutIdx) {
10495 CCValAssign &VA = ArgLocs[i];
10496 SDValue ArgValue = OutVals[OutIdx];
10497 ISD::ArgFlagsTy Flags = Outs[OutIdx].Flags;
10498
10499 // Handle passing f64 on LA32D with a soft float ABI as a special case.
10500 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10501 assert(VA.isRegLoc() && "Expected register VA assignment");
10502 assert(VA.needsCustom());
10503 SDValue SplitF64 =
10504 DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10505 DAG.getVTList(MVT::i32, MVT::i32), ArgValue);
10506 SDValue Lo = SplitF64.getValue(0);
10507 SDValue Hi = SplitF64.getValue(1);
10508
10509 Register RegLo = VA.getLocReg();
10510 RegsToPass.push_back(std::make_pair(RegLo, Lo));
10511
10512 // Get the CCValAssign for the Hi part.
10513 CCValAssign &HiVA = ArgLocs[++i];
10514
10515 if (HiVA.isMemLoc()) {
10516 // Second half of f64 is passed on the stack.
10517 if (!StackPtr.getNode())
10518 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10520 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10521 DAG.getIntPtrConstant(HiVA.getLocMemOffset(), DL));
10522 // Emit the store.
10523 MemOpChains.push_back(DAG.getStore(
10524 Chain, DL, Hi, Address,
10526 } else {
10527 // Second half of f64 is passed in another GPR.
10528 Register RegHigh = HiVA.getLocReg();
10529 RegsToPass.push_back(std::make_pair(RegHigh, Hi));
10530 }
10531 continue;
10532 }
10533
10534 // Promote the value if needed.
10535 // For now, only handle fully promoted and indirect arguments.
10536 if (VA.getLocInfo() == CCValAssign::Indirect) {
10537 // For musttail calls, reuse incoming indirect pointers instead of
10538 // creating new stack temporaries. The incoming pointers point to the
10539 // caller's caller's frame, which remains valid after a tail call.
10540 if (IsTailCall && CLI.CB && CLI.CB->isMustTailCall()) {
10543 unsigned CallArgIdx = Outs[OutIdx].OrigArgIndex;
10544
10545 // Resolve which formal parameter is being passed at this call
10546 // position.
10547 //
10548 // FIXME: Ins[].OrigArgIndex is Argument::getArgNo() (unfiltered),
10549 // but Outs[].OrigArgIndex is an index into a filtered arg list
10550 // (empty types removed, via CallLoweringInfo in the target-
10551 // independent layer). IncomingIndirectArgs is keyed by the
10552 // caller's unfiltered Argument::getArgNo(), so we have to walk
10553 // the caller's formals (same filter) to translate the index.
10554 // This target-independent asymmetry should be normalized so
10555 // backends do not need to re-derive the mapping.
10556 //
10557 // Steps:
10558 // 1. Find the call operand at filtered position CallArgIdx.
10559 // 2. If it is an Argument, use getArgNo() directly (same filter
10560 // for caller formals and call operands).
10561 // 3. Otherwise (computed value), walk the caller's formals and
10562 // skip empty types to map the filtered index to getArgNo().
10563 const Argument *FormalArg = nullptr;
10564 unsigned FilteredIdx = 0;
10565 for (const auto &CallArg : CLI.CB->args()) {
10566 if (CallArg->getType()->isEmptyTy())
10567 continue;
10568 if (FilteredIdx == CallArgIdx) {
10569 FormalArg = dyn_cast<Argument>(CallArg);
10570 break;
10571 }
10572 ++FilteredIdx;
10573 }
10574
10575 // For forwarded args, getArgNo() gives the unfiltered index directly.
10576 // For computed args, walk the caller's formals to resolve it.
10577 unsigned FormalArgIdx = CallArgIdx;
10578 if (FormalArg) {
10579 FormalArgIdx = FormalArg->getArgNo();
10580 } else {
10581 FilteredIdx = 0;
10582 for (const auto &Arg : MF.getFunction().args()) {
10583 if (Arg.getType()->isEmptyTy())
10584 continue;
10585 if (FilteredIdx == CallArgIdx) {
10586 FormalArgIdx = Arg.getArgNo();
10587 break;
10588 }
10589 ++FilteredIdx;
10590 }
10591 }
10592
10593 Register VReg = LAFI->getIncomingIndirectArg(FormalArgIdx);
10594 SDValue CopyOp = DAG.getCopyFromReg(Chain, DL, VReg, PtrVT);
10595 // Thread the CopyFromReg output chain through MemOpChains so the
10596 // TokenFactor below sequences the copy with any stores we emit
10597 // for this argument.
10598 MemOpChains.push_back(CopyOp.getValue(1));
10599 SDValue IncomingPtr = CopyOp;
10600
10601 if (!FormalArg) {
10602 // Computed value: store into the incoming indirect pointer for the
10603 // same-position formal parameter (musttail guarantees matching
10604 // prototypes, so types match). The pointer survives the tail call
10605 // since it points to the caller's caller's frame.
10606 //
10607 // The data-flow edge through IncomingPtr already prevents the
10608 // store from being scheduled before the CopyFromReg. Threading
10609 // CopyOp.getValue(1) (the copy's output chain) into the store
10610 // makes that ordering explicit on the chain edge as well, which
10611 // is the convention for memory ops chaining off their producers.
10612 MemOpChains.push_back(
10613 DAG.getStore(CopyOp.getValue(1), DL, ArgValue, IncomingPtr,
10615 // Store any split parts at their respective offsets.
10616 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10617 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10618 SDValue PartValue = OutVals[OutIdx + 1];
10619 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10620 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10621 SDValue Addr =
10622 DAG.getNode(ISD::ADD, DL, PtrVT, IncomingPtr, Offset);
10623 MemOpChains.push_back(
10624 DAG.getStore(CopyOp.getValue(1), DL, PartValue, Addr,
10626 ++i;
10627 ++OutIdx;
10628 }
10629 }
10630 ArgValue = IncomingPtr;
10631
10632 // Skip any remaining split parts (for forwarded args, they are
10633 // covered by the forwarded pointer).
10634 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == CallArgIdx) {
10635 ++i;
10636 ++OutIdx;
10637 }
10638 } else {
10639 // Store the argument in a stack slot and pass its address.
10640 Align StackAlign =
10641 std::max(getPrefTypeAlign(Outs[OutIdx].ArgVT, DAG),
10642 getPrefTypeAlign(ArgValue.getValueType(), DAG));
10643 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
10644 // If the original argument was split and passed by reference, we need
10645 // to store the required parts of it here (and pass just one address).
10646 unsigned ArgIndex = Outs[OutIdx].OrigArgIndex;
10647 unsigned ArgPartOffset = Outs[OutIdx].PartOffset;
10648 assert(ArgPartOffset == 0);
10649 // Calculate the total size to store. We don't have access to what we're
10650 // actually storing other than performing the loop and collecting the
10651 // info.
10653 while (i + 1 != e && Outs[OutIdx + 1].OrigArgIndex == ArgIndex) {
10654 SDValue PartValue = OutVals[OutIdx + 1];
10655 unsigned PartOffset = Outs[OutIdx + 1].PartOffset - ArgPartOffset;
10656 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
10657 EVT PartVT = PartValue.getValueType();
10658 StoredSize += PartVT.getStoreSize();
10659 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
10660 Parts.push_back(std::make_pair(PartValue, Offset));
10661 ++i;
10662 ++OutIdx;
10663 }
10664 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
10665 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
10666 MemOpChains.push_back(
10667 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
10669 for (const auto &Part : Parts) {
10670 SDValue PartValue = Part.first;
10671 SDValue PartOffset = Part.second;
10673 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
10674 MemOpChains.push_back(
10675 DAG.getStore(Chain, DL, PartValue, Address,
10677 }
10678 ArgValue = SpillSlot;
10679 }
10680 } else {
10681 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
10682 }
10683
10684 // Use local copy if it is a byval arg.
10685 if (Flags.isByVal())
10686 ArgValue = ByValArgs[j++];
10687
10688 if (VA.isRegLoc()) {
10689 // Queue up the argument copies and emit them at the end.
10690 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
10691 } else {
10692 assert(VA.isMemLoc() && "Argument not register or memory");
10693 assert((!IsTailCall || (CLI.CB && CLI.CB->isMustTailCall())) &&
10694 "Tail call not allowed if stack is used for passing parameters");
10695
10696 // Work out the address of the stack slot.
10697 if (!StackPtr.getNode())
10698 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
10700 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
10702
10703 // Emit the store.
10704 MemOpChains.push_back(
10705 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
10706 }
10707 }
10708
10709 // Join the stores, which are independent of one another.
10710 if (!MemOpChains.empty())
10711 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
10712
10713 SDValue Glue;
10714
10715 // Build a sequence of copy-to-reg nodes, chained and glued together.
10716 for (auto &Reg : RegsToPass) {
10717 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
10718 Glue = Chain.getValue(1);
10719 }
10720
10721 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
10722 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
10723 // split it and then direct call can be matched by PseudoCALL_SMALL.
10725 const GlobalValue *GV = S->getGlobal();
10726 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
10729 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
10730 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
10731 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
10734 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
10735 }
10736
10737 // The first call operand is the chain and the second is the target address.
10739 Ops.push_back(Chain);
10740 Ops.push_back(Callee);
10741
10742 // Add argument registers to the end of the list so that they are
10743 // known live into the call.
10744 for (auto &Reg : RegsToPass)
10745 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
10746
10747 if (!IsTailCall) {
10748 // Add a register mask operand representing the call-preserved registers.
10749 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
10750 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
10751 assert(Mask && "Missing call preserved mask for calling convention");
10752 Ops.push_back(DAG.getRegisterMask(Mask));
10753 }
10754
10755 // Glue the call to the argument copies, if any.
10756 if (Glue.getNode())
10757 Ops.push_back(Glue);
10758
10759 // Emit the call.
10760 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
10761 unsigned Op;
10762 switch (DAG.getTarget().getCodeModel()) {
10763 default:
10764 report_fatal_error("Unsupported code model");
10765 case CodeModel::Small:
10766 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
10767 break;
10768 case CodeModel::Medium:
10769 Op = IsTailCall ? LoongArchISD::TAIL_MEDIUM : LoongArchISD::CALL_MEDIUM;
10770 break;
10771 case CodeModel::Large:
10772 assert(Subtarget.is64Bit() && "Large code model requires LA64");
10773 Op = IsTailCall ? LoongArchISD::TAIL_LARGE : LoongArchISD::CALL_LARGE;
10774 break;
10775 }
10776
10777 if (IsTailCall) {
10779 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
10780 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
10781 return Ret;
10782 }
10783
10784 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
10785 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
10786 Glue = Chain.getValue(1);
10787
10788 // Mark the end of the call, which is glued to the call itself.
10789 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
10790 Glue = Chain.getValue(1);
10791
10792 // Assign locations to each value returned by this call.
10794 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
10795 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
10796
10797 // Copy all of the result registers out of their specified physreg.
10798 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
10799 auto &VA = RVLocs[i];
10800 // Copy the value out.
10801 SDValue RetValue =
10802 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
10803 // Glue the RetValue to the end of the call sequence.
10804 Chain = RetValue.getValue(1);
10805 Glue = RetValue.getValue(2);
10806
10807 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10808 assert(VA.needsCustom());
10809 SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, RVLocs[++i].getLocReg(),
10810 MVT::i32, Glue);
10811 Chain = RetValue2.getValue(1);
10812 Glue = RetValue2.getValue(2);
10813 RetValue = DAG.getNode(LoongArchISD::BUILD_PAIR_F64, DL, MVT::f64,
10814 RetValue, RetValue2);
10815 } else
10816 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
10817
10818 InVals.push_back(RetValue);
10819 }
10820
10821 return Chain;
10822}
10823
10825 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
10826 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
10827 const Type *RetTy) const {
10829 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
10830
10831 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
10832 LoongArchABI::ABI ABI =
10833 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
10834 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
10835 Outs[i].Flags, CCInfo, /*IsRet=*/true, nullptr))
10836 return false;
10837 }
10838 return true;
10839}
10840
10842 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
10844 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
10845 SelectionDAG &DAG) const {
10846 // Stores the assignment of the return value to a location.
10848
10849 // Info about the registers and stack slot.
10850 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
10851 *DAG.getContext());
10852
10853 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
10854 nullptr, CC_LoongArch);
10855 if (CallConv == CallingConv::GHC && !RVLocs.empty())
10856 report_fatal_error("GHC functions return void only");
10857 SDValue Glue;
10858 SmallVector<SDValue, 4> RetOps(1, Chain);
10859
10860 // Copy the result values into the output registers.
10861 for (unsigned i = 0, e = RVLocs.size(), OutIdx = 0; i < e; ++i, ++OutIdx) {
10862 SDValue Val = OutVals[OutIdx];
10863 CCValAssign &VA = RVLocs[i];
10864 assert(VA.isRegLoc() && "Can only return in registers!");
10865
10866 if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) {
10867 // Handle returning f64 on LA32D with a soft float ABI.
10868 assert(VA.isRegLoc() && "Expected return via registers");
10869 assert(VA.needsCustom());
10870 SDValue SplitF64 = DAG.getNode(LoongArchISD::SPLIT_PAIR_F64, DL,
10871 DAG.getVTList(MVT::i32, MVT::i32), Val);
10872 SDValue Lo = SplitF64.getValue(0);
10873 SDValue Hi = SplitF64.getValue(1);
10874 Register RegLo = VA.getLocReg();
10875 Register RegHi = RVLocs[++i].getLocReg();
10876
10877 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue);
10878 Glue = Chain.getValue(1);
10879 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32));
10880 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue);
10881 Glue = Chain.getValue(1);
10882 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32));
10883 } else {
10884 // Handle a 'normal' return.
10885 Val = convertValVTToLocVT(DAG, Val, VA, DL);
10886 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
10887
10888 // Guarantee that all emitted copies are stuck together.
10889 Glue = Chain.getValue(1);
10890 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
10891 }
10892 }
10893
10894 RetOps[0] = Chain; // Update chain.
10895
10896 // Add the glue node if we have it.
10897 if (Glue.getNode())
10898 RetOps.push_back(Glue);
10899
10900 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
10901}
10902
10903// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
10904// Note: The following prefixes are excluded:
10905// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
10906// as they can be represented using [x]vrepli.[whb]
10908 const APInt &SplatValue, const unsigned SplatBitSize) const {
10909 uint64_t RequiredImm = 0;
10910 uint64_t V = SplatValue.getZExtValue();
10911 if (SplatBitSize == 16 && !(V & 0x00FF)) {
10912 // 4'b0101
10913 RequiredImm = (0b10101 << 8) | (V >> 8);
10914 return {true, RequiredImm};
10915 } else if (SplatBitSize == 32) {
10916 // 4'b0001
10917 if (!(V & 0xFFFF00FF)) {
10918 RequiredImm = (0b10001 << 8) | (V >> 8);
10919 return {true, RequiredImm};
10920 }
10921 // 4'b0010
10922 if (!(V & 0xFF00FFFF)) {
10923 RequiredImm = (0b10010 << 8) | (V >> 16);
10924 return {true, RequiredImm};
10925 }
10926 // 4'b0011
10927 if (!(V & 0x00FFFFFF)) {
10928 RequiredImm = (0b10011 << 8) | (V >> 24);
10929 return {true, RequiredImm};
10930 }
10931 // 4'b0110
10932 if ((V & 0xFFFF00FF) == 0xFF) {
10933 RequiredImm = (0b10110 << 8) | (V >> 8);
10934 return {true, RequiredImm};
10935 }
10936 // 4'b0111
10937 if ((V & 0xFF00FFFF) == 0xFFFF) {
10938 RequiredImm = (0b10111 << 8) | (V >> 16);
10939 return {true, RequiredImm};
10940 }
10941 // 4'b1010
10942 if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
10943 RequiredImm =
10944 (0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
10945 return {true, RequiredImm};
10946 }
10947 } else if (SplatBitSize == 64) {
10948 // 4'b1011
10949 if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
10950 (V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
10951 RequiredImm =
10952 (0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
10953 return {true, RequiredImm};
10954 }
10955 // 4'b1100
10956 if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
10957 (V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
10958 RequiredImm =
10959 (0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
10960 return {true, RequiredImm};
10961 }
10962 // 4'b1001
10963 auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
10964 uint8_t res = 0;
10965 for (int i = 0; i < 8; ++i) {
10966 uint8_t byte = x & 0xFF;
10967 if (byte == 0 || byte == 0xFF)
10968 res |= ((byte & 1) << i);
10969 else
10970 return {false, 0};
10971 x >>= 8;
10972 }
10973 return {true, res};
10974 };
10975 auto [IsSame, Suffix] = sameBitsPreByte(V);
10976 if (IsSame) {
10977 RequiredImm = (0b11001 << 8) | Suffix;
10978 return {true, RequiredImm};
10979 }
10980 }
10981 return {false, RequiredImm};
10982}
10983
10985 EVT VT) const {
10986 if (!Subtarget.hasExtLSX())
10987 return false;
10988
10989 if (VT == MVT::f32) {
10990 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7e07ffff;
10991 return (masked == 0x3e000000 || masked == 0x40000000);
10992 }
10993
10994 if (VT == MVT::f64) {
10995 uint64_t masked = Imm.bitcastToAPInt().getZExtValue() & 0x7fc0ffffffffffff;
10996 return (masked == 0x3fc0000000000000 || masked == 0x4000000000000000);
10997 }
10998
10999 return false;
11000}
11001
11002bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
11003 bool ForCodeSize) const {
11004 // TODO: Maybe need more checks here after vector extension is supported.
11005 if (VT == MVT::f32 && !Subtarget.hasBasicF())
11006 return false;
11007 if (VT == MVT::f64 && !Subtarget.hasBasicD())
11008 return false;
11009 return (Imm.isZero() || Imm.isOne() || isFPImmVLDILegal(Imm, VT));
11010}
11011
11013 return true;
11014}
11015
11017 return true;
11018}
11019
11020bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
11021 const Instruction *I) const {
11022 if (!Subtarget.is64Bit())
11023 return isa<LoadInst>(I) || isa<StoreInst>(I);
11024
11025 if (isa<LoadInst>(I))
11026 return true;
11027
11028 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
11029 // require fences beacuse we can use amswap_db.[w/d].
11030 Type *Ty = I->getOperand(0)->getType();
11031 if (isa<StoreInst>(I) && Ty->isIntegerTy()) {
11032 unsigned Size = Ty->getIntegerBitWidth();
11033 return (Size == 8 || Size == 16);
11034 }
11035
11036 return false;
11037}
11038
11040 LLVMContext &Context,
11041 EVT VT) const {
11042 if (!VT.isVector())
11043 return getPointerTy(DL);
11045}
11046
11048 unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const {
11049 // Do not merge to float value size (128 or 256 bits) if no implicit
11050 // float attribute is set.
11051 bool NoFloat = MF.getFunction().hasFnAttribute(Attribute::NoImplicitFloat);
11052 unsigned MaxIntSize = Subtarget.is64Bit() ? 64 : 32;
11053 if (NoFloat)
11054 return MemVT.getSizeInBits() <= MaxIntSize;
11055
11056 // Make sure we don't merge greater than our maximum supported vector width.
11057 if (Subtarget.hasExtLASX())
11058 MaxIntSize = 256;
11059 else if (Subtarget.hasExtLSX())
11060 MaxIntSize = 128;
11061
11062 return MemVT.getSizeInBits() <= MaxIntSize;
11063}
11064
11066 EVT VT = Y.getValueType();
11067
11068 if (VT.isVector())
11069 return Subtarget.hasExtLSX() && VT.isInteger();
11070
11071 return VT.isScalarInteger() && !isa<ConstantSDNode>(Y);
11072}
11073
11076 MachineFunction &MF, unsigned Intrinsic) const {
11077 switch (Intrinsic) {
11078 default:
11079 return;
11080 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
11081 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
11082 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
11083 case Intrinsic::loongarch_masked_atomicrmw_nand_i32: {
11084 IntrinsicInfo Info;
11086 Info.memVT = MVT::i32;
11087 Info.ptrVal = I.getArgOperand(0);
11088 Info.offset = 0;
11089 Info.align = Align(4);
11092 Infos.push_back(Info);
11093 return;
11094 // TODO: Add more Intrinsics later.
11095 }
11096 }
11097}
11098
11099// When -mlamcas is enabled, MinCmpXchgSizeInBits will be set to 8,
11100// atomicrmw and/or/xor operations with operands less than 32 bits cannot be
11101// expanded to am{and/or/xor}[_db].w through AtomicExpandPass. To prevent
11102// regression, we need to implement it manually.
11105
11107 Op == AtomicRMWInst::And) &&
11108 "Unable to expand");
11109 unsigned MinWordSize = 4;
11110
11111 IRBuilder<> Builder(AI);
11112 LLVMContext &Ctx = Builder.getContext();
11113 const DataLayout &DL = AI->getDataLayout();
11114 Type *ValueType = AI->getType();
11115 Type *WordType = Type::getIntNTy(Ctx, MinWordSize * 8);
11116
11117 Value *Addr = AI->getPointerOperand();
11118 PointerType *PtrTy = cast<PointerType>(Addr->getType());
11119 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
11120
11121 Value *AlignedAddr = Builder.CreateIntrinsic(
11122 Intrinsic::ptrmask, {PtrTy, IntTy},
11123 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,
11124 "AlignedAddr");
11125
11126 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
11127 Value *PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
11128 Value *ShiftAmt = Builder.CreateShl(PtrLSB, 3);
11129 ShiftAmt = Builder.CreateTrunc(ShiftAmt, WordType, "ShiftAmt");
11130 Value *Mask = Builder.CreateShl(
11131 ConstantInt::get(WordType,
11132 (1 << (DL.getTypeStoreSize(ValueType) * 8)) - 1),
11133 ShiftAmt, "Mask");
11134 Value *Inv_Mask = Builder.CreateNot(Mask, "Inv_Mask");
11135 Value *ValOperand_Shifted =
11136 Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), WordType),
11137 ShiftAmt, "ValOperand_Shifted");
11138 Value *NewOperand;
11139 if (Op == AtomicRMWInst::And)
11140 NewOperand = Builder.CreateOr(ValOperand_Shifted, Inv_Mask, "AndOperand");
11141 else
11142 NewOperand = ValOperand_Shifted;
11143
11144 AtomicRMWInst *NewAI =
11145 Builder.CreateAtomicRMW(Op, AlignedAddr, NewOperand, Align(MinWordSize),
11146 AI->getOrdering(), AI->getSyncScopeID());
11147
11148 Value *Shift = Builder.CreateLShr(NewAI, ShiftAmt, "shifted");
11149 Value *Trunc = Builder.CreateTrunc(Shift, ValueType, "extracted");
11150 Value *FinalOldResult = Builder.CreateBitCast(Trunc, ValueType);
11151 AI->replaceAllUsesWith(FinalOldResult);
11152 AI->eraseFromParent();
11153}
11154
11157 const AtomicRMWInst *AI) const {
11158 // TODO: Add more AtomicRMWInst that needs to be extended.
11159
11160 // Since floating-point operation requires a non-trivial set of data
11161 // operations, use CmpXChg to expand.
11162 if (AI->isFloatingPointOperation() ||
11168
11169 if (Subtarget.hasLAM_BH() && Subtarget.is64Bit() &&
11172 AI->getOperation() == AtomicRMWInst::Sub)) {
11174 }
11175
11176 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
11177 if (Subtarget.hasLAMCAS()) {
11178 if (Size < 32 && (AI->getOperation() == AtomicRMWInst::And ||
11182 if (AI->getOperation() == AtomicRMWInst::Nand || Size < 32)
11184 }
11185
11186 if (Size == 8 || Size == 16)
11189}
11190
11191static Intrinsic::ID
11193 AtomicRMWInst::BinOp BinOp) {
11194 if (GRLen == 64) {
11195 switch (BinOp) {
11196 default:
11197 llvm_unreachable("Unexpected AtomicRMW BinOp");
11199 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
11200 case AtomicRMWInst::Add:
11201 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
11202 case AtomicRMWInst::Sub:
11203 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
11205 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
11207 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
11209 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
11210 case AtomicRMWInst::Max:
11211 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
11212 case AtomicRMWInst::Min:
11213 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
11214 // TODO: support other AtomicRMWInst.
11215 }
11216 }
11217
11218 if (GRLen == 32) {
11219 switch (BinOp) {
11220 default:
11221 llvm_unreachable("Unexpected AtomicRMW BinOp");
11223 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
11224 case AtomicRMWInst::Add:
11225 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
11226 case AtomicRMWInst::Sub:
11227 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
11229 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
11231 return Intrinsic::loongarch_masked_atomicrmw_umax_i32;
11233 return Intrinsic::loongarch_masked_atomicrmw_umin_i32;
11234 case AtomicRMWInst::Max:
11235 return Intrinsic::loongarch_masked_atomicrmw_max_i32;
11236 case AtomicRMWInst::Min:
11237 return Intrinsic::loongarch_masked_atomicrmw_min_i32;
11238 // TODO: support other AtomicRMWInst.
11239 }
11240 }
11241
11242 llvm_unreachable("Unexpected GRLen\n");
11243}
11244
11247 const AtomicCmpXchgInst *CI) const {
11248
11249 if (Subtarget.hasLAMCAS())
11251
11253 if (Size == 8 || Size == 16)
11256}
11257
11259 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
11260 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
11261 unsigned GRLen = Subtarget.getGRLen();
11262 AtomicOrdering FailOrd = CI->getFailureOrdering();
11263 Value *FailureOrdering =
11264 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
11265 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i32;
11266 if (GRLen == 64) {
11267 CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
11268 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
11269 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
11270 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11271 }
11272 Type *Tys[] = {AlignedAddr->getType()};
11273 Value *Result = Builder.CreateIntrinsic(
11274 CmpXchgIntrID, Tys, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
11275 if (GRLen == 64)
11276 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11277 return Result;
11278}
11279
11281 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
11282 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
11283 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
11284 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
11285 // mask, as this produces better code than the LL/SC loop emitted by
11286 // int_loongarch_masked_atomicrmw_xchg.
11287 if (AI->getOperation() == AtomicRMWInst::Xchg &&
11290 if (CVal->isZero())
11291 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
11292 Builder.CreateNot(Mask, "Inv_Mask"),
11293 AI->getAlign(), Ord);
11294 if (CVal->isMinusOne())
11295 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
11296 AI->getAlign(), Ord);
11297 }
11298
11299 unsigned GRLen = Subtarget.getGRLen();
11300 Value *Ordering =
11301 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
11302 Type *Tys[] = {AlignedAddr->getType()};
11304 AI->getModule(),
11306
11307 if (GRLen == 64) {
11308 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
11309 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
11310 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
11311 }
11312
11313 Value *Result;
11314
11315 // Must pass the shift amount needed to sign extend the loaded value prior
11316 // to performing a signed comparison for min/max. ShiftAmt is the number of
11317 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
11318 // is the number of bits to left+right shift the value in order to
11319 // sign-extend.
11320 if (AI->getOperation() == AtomicRMWInst::Min ||
11322 const DataLayout &DL = AI->getDataLayout();
11323 unsigned ValWidth =
11324 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
11325 Value *SextShamt =
11326 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
11327 Result = Builder.CreateCall(LlwOpScwLoop,
11328 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
11329 } else {
11330 Result =
11331 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
11332 }
11333
11334 if (GRLen == 64)
11335 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
11336 return Result;
11337}
11338
11340 const MachineFunction &MF, EVT VT) const {
11341 VT = VT.getScalarType();
11342
11343 if (!VT.isSimple())
11344 return false;
11345
11346 switch (VT.getSimpleVT().SimpleTy) {
11347 case MVT::f32:
11348 case MVT::f64:
11349 return true;
11350 default:
11351 break;
11352 }
11353
11354 return false;
11355}
11356
11358 ExceptionHandling EH, const Constant *PersonalityFn) const {
11359 return LoongArch::R4;
11360}
11361
11363 ExceptionHandling EH, const Constant *PersonalityFn) const {
11364 return LoongArch::R5;
11365}
11366
11367//===----------------------------------------------------------------------===//
11368// Target Optimization Hooks
11369//===----------------------------------------------------------------------===//
11370
11372 const LoongArchSubtarget &Subtarget) {
11373 // Feature FRECIPE instrucions relative accuracy is 2^-14.
11374 // IEEE float has 23 digits and double has 52 digits.
11375 int RefinementSteps = VT.getScalarType() == MVT::f64 ? 2 : 1;
11376 return RefinementSteps;
11377}
11378
11379static bool
11381 assert(Subtarget.hasFrecipe() &&
11382 "Reciprocal estimate queried on unsupported target");
11383
11384 if (!VT.isSimple())
11385 return false;
11386
11387 switch (VT.getSimpleVT().SimpleTy) {
11388 case MVT::f32:
11389 // f32 is the base type for reciprocal estimate instructions.
11390 return true;
11391
11392 case MVT::f64:
11393 return Subtarget.hasBasicD();
11394
11395 case MVT::v4f32:
11396 case MVT::v2f64:
11397 return Subtarget.hasExtLSX();
11398
11399 case MVT::v8f32:
11400 case MVT::v4f64:
11401 return Subtarget.hasExtLASX();
11402
11403 default:
11404 return false;
11405 }
11406}
11407
11409 SelectionDAG &DAG, int Enabled,
11410 int &RefinementSteps,
11411 bool &UseOneConstNR,
11412 bool Reciprocal) const {
11414 "Enabled should never be Disabled here");
11415
11416 if (!Subtarget.hasFrecipe())
11417 return SDValue();
11418
11419 SDLoc DL(Operand);
11420 EVT VT = Operand.getValueType();
11421
11422 // Check supported types.
11423 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11424 return SDValue();
11425
11426 // Handle refinement steps.
11427 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11428 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11429
11430 // LoongArch only has FRSQRTE which is 1.0 / sqrt(x).
11431 UseOneConstNR = false;
11432 SDValue Rsqrt = DAG.getNode(LoongArchISD::FRSQRTE, DL, VT, Operand);
11433
11434 // If the caller wants 1.0 / sqrt(x), or if further refinement steps
11435 // are needed (which rely on the reciprocal form), return the raw reciprocal
11436 // estimate.
11437 if (Reciprocal || RefinementSteps > 0)
11438 return Rsqrt;
11439
11440 // Otherwise, return sqrt(x) by multiplying with the operand.
11441 return DAG.getNode(ISD::FMUL, DL, VT, Operand, Rsqrt);
11442}
11443
11445 SelectionDAG &DAG,
11446 int Enabled,
11447 int &RefinementSteps) const {
11449 "Enabled should never be Disabled here");
11450
11451 if (!Subtarget.hasFrecipe())
11452 return SDValue();
11453
11454 SDLoc DL(Operand);
11455 EVT VT = Operand.getValueType();
11456
11457 // Check supported types.
11458 if (!isSupportedReciprocalEstimateType(VT, Subtarget))
11459 return SDValue();
11460
11461 if (RefinementSteps == ReciprocalEstimate::Unspecified)
11462 RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
11463
11464 // FRECIPE computes 1.0 / x.
11465 return DAG.getNode(LoongArchISD::FRECIPE, DL, VT, Operand);
11466}
11467
11468//===----------------------------------------------------------------------===//
11469// LoongArch Inline Assembly Support
11470//===----------------------------------------------------------------------===//
11471
11473LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
11474 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
11475 //
11476 // 'f': A floating-point register (if available).
11477 // 'k': A memory operand whose address is formed by a base register and
11478 // (optionally scaled) index register.
11479 // 'l': A signed 16-bit constant.
11480 // 'm': A memory operand whose address is formed by a base register and
11481 // offset that is suitable for use in instructions with the same
11482 // addressing mode as st.w and ld.w.
11483 // 'q': A general-purpose register except for $r0 and $r1 (for the csrxchg
11484 // instruction)
11485 // 'I': A signed 12-bit constant (for arithmetic instructions).
11486 // 'J': Integer zero.
11487 // 'K': An unsigned 12-bit constant (for logic instructions).
11488 // "ZB": An address that is held in a general-purpose register. The offset is
11489 // zero.
11490 // "ZC": A memory operand whose address is formed by a base register and
11491 // offset that is suitable for use in instructions with the same
11492 // addressing mode as ll.w and sc.w.
11493 if (Constraint.size() == 1) {
11494 switch (Constraint[0]) {
11495 default:
11496 break;
11497 case 'f':
11498 case 'q':
11499 return C_RegisterClass;
11500 case 'l':
11501 case 'I':
11502 case 'J':
11503 case 'K':
11504 return C_Immediate;
11505 case 'k':
11506 return C_Memory;
11507 }
11508 }
11509
11510 if (Constraint == "ZC" || Constraint == "ZB")
11511 return C_Memory;
11512
11513 // 'm' is handled here.
11514 return TargetLowering::getConstraintType(Constraint);
11515}
11516
11517InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
11518 StringRef ConstraintCode) const {
11519 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
11523 .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
11524}
11525
11526std::pair<unsigned, const TargetRegisterClass *>
11527LoongArchTargetLowering::getRegForInlineAsmConstraint(
11528 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
11529 // First, see if this is a constraint that directly corresponds to a LoongArch
11530 // register class.
11531 if (Constraint.size() == 1) {
11532 switch (Constraint[0]) {
11533 case 'r':
11534 // TODO: Support fixed vectors up to GRLen?
11535 if (VT.isVector())
11536 break;
11537 return std::make_pair(0U, &LoongArch::GPRRegClass);
11538 case 'q':
11539 return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
11540 case 'f':
11541 if (Subtarget.hasBasicF() && VT == MVT::f32)
11542 return std::make_pair(0U, &LoongArch::FPR32RegClass);
11543 if (Subtarget.hasBasicD() && VT == MVT::f64)
11544 return std::make_pair(0U, &LoongArch::FPR64RegClass);
11545 if (Subtarget.hasExtLSX() &&
11546 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
11547 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11548 if (Subtarget.hasExtLSX() && VT == MVT::i128)
11549 return std::make_pair(0U, &LoongArch::LSX128RegClass);
11550 if (Subtarget.hasExtLASX() &&
11551 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
11552 return std::make_pair(0U, &LoongArch::LASX256RegClass);
11553 break;
11554 default:
11555 break;
11556 }
11557 }
11558
11559 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
11560 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
11561 // constraints while the official register name is prefixed with a '$'. So we
11562 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
11563 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
11564 // case insensitive, so no need to convert the constraint to upper case here.
11565 //
11566 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
11567 // decode the usage of register name aliases into their official names. And
11568 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
11569 // official register names.
11570 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
11571 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
11572 bool IsFP = Constraint[2] == 'f';
11573 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
11574 std::pair<unsigned, const TargetRegisterClass *> R;
11576 TRI, join_items("", Temp.first, Temp.second), VT);
11577 // Match those names to the widest floating point register type available.
11578 if (IsFP) {
11579 unsigned RegNo = R.first;
11580 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
11581 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
11582 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
11583 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
11584 }
11585 }
11586 }
11587 return R;
11588 }
11589
11590 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
11591}
11592
11593void LoongArchTargetLowering::LowerAsmOperandForConstraint(
11594 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
11595 SelectionDAG &DAG) const {
11596 // Currently only support length 1 constraints.
11597 if (Constraint.size() == 1) {
11598 switch (Constraint[0]) {
11599 case 'l':
11600 // Validate & create a 16-bit signed immediate operand.
11601 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11602 uint64_t CVal = C->getSExtValue();
11603 if (isInt<16>(CVal))
11604 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11605 Subtarget.getGRLenVT()));
11606 }
11607 return;
11608 case 'I':
11609 // Validate & create a 12-bit signed immediate operand.
11610 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11611 uint64_t CVal = C->getSExtValue();
11612 if (isInt<12>(CVal))
11613 Ops.push_back(DAG.getSignedTargetConstant(CVal, SDLoc(Op),
11614 Subtarget.getGRLenVT()));
11615 }
11616 return;
11617 case 'J':
11618 // Validate & create an integer zero operand.
11619 if (auto *C = dyn_cast<ConstantSDNode>(Op))
11620 if (C->getZExtValue() == 0)
11621 Ops.push_back(
11622 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
11623 return;
11624 case 'K':
11625 // Validate & create a 12-bit unsigned immediate operand.
11626 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
11627 uint64_t CVal = C->getZExtValue();
11628 if (isUInt<12>(CVal))
11629 Ops.push_back(
11630 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
11631 }
11632 return;
11633 default:
11634 break;
11635 }
11636 }
11638}
11639
11640#define GET_REGISTER_MATCHER
11641#include "LoongArchGenAsmMatcher.inc"
11642
11645 const MachineFunction &MF) const {
11646 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
11647 std::string NewRegName = Name.second.str();
11648 Register Reg = MatchRegisterAltName(NewRegName);
11649 if (!Reg)
11650 Reg = MatchRegisterName(NewRegName);
11651 if (!Reg)
11652 return Reg;
11653 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
11654 if (!ReservedRegs.test(Reg))
11655 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
11656 StringRef(RegName) + "\"."));
11657 return Reg;
11658}
11659
11661 EVT VT, SDValue C) const {
11662 // TODO: Support vectors.
11663 if (!VT.isScalarInteger())
11664 return false;
11665
11666 // Omit the optimization if the data size exceeds GRLen.
11667 if (VT.getSizeInBits() > Subtarget.getGRLen())
11668 return false;
11669
11670 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
11671 const APInt &Imm = ConstNode->getAPIntValue();
11672 // Break MUL into (SLLI + ADD/SUB) or ALSL.
11673 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
11674 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
11675 return true;
11676 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
11677 if (ConstNode->hasOneUse() &&
11678 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
11679 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
11680 return true;
11681 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
11682 // in which the immediate has two set bits. Or Break (MUL x, imm)
11683 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
11684 // equals to (1 << s0) - (1 << s1).
11685 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
11686 unsigned Shifts = Imm.countr_zero();
11687 // Reject immediates which can be composed via a single LUI.
11688 if (Shifts >= 12)
11689 return false;
11690 // Reject multiplications can be optimized to
11691 // (SLLI (ALSL x, x, 1/2/3/4), s).
11692 APInt ImmPop = Imm.ashr(Shifts);
11693 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
11694 return false;
11695 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
11696 // since it needs one more instruction than other 3 cases.
11697 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
11698 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
11699 (ImmSmall - Imm).isPowerOf2())
11700 return true;
11701 }
11702 }
11703
11704 return false;
11705}
11706
11708 const AddrMode &AM,
11709 Type *Ty, unsigned AS,
11710 Instruction *I) const {
11711 // LoongArch has four basic addressing modes:
11712 // 1. reg
11713 // 2. reg + 12-bit signed offset
11714 // 3. reg + 14-bit signed offset left-shifted by 2
11715 // 4. reg1 + reg2
11716 // TODO: Add more checks after support vector extension.
11717
11718 // No global is ever allowed as a base.
11719 if (AM.BaseGV)
11720 return false;
11721
11722 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
11723 // with `UAL` feature.
11724 if (!isInt<12>(AM.BaseOffs) &&
11725 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
11726 return false;
11727
11728 switch (AM.Scale) {
11729 case 0:
11730 // "r+i" or just "i", depending on HasBaseReg.
11731 break;
11732 case 1:
11733 // "r+r+i" is not allowed.
11734 if (AM.HasBaseReg && AM.BaseOffs)
11735 return false;
11736 // Otherwise we have "r+r" or "r+i".
11737 break;
11738 case 2:
11739 // "2*r+r" or "2*r+i" is not allowed.
11740 if (AM.HasBaseReg || AM.BaseOffs)
11741 return false;
11742 // Allow "2*r" as "r+r".
11743 break;
11744 default:
11745 return false;
11746 }
11747
11748 return true;
11749}
11750
11752 return isInt<12>(Imm);
11753}
11754
11756 return isInt<12>(Imm);
11757}
11758
11760 // Zexts are free if they can be combined with a load.
11761 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
11762 // poorly with type legalization of compares preferring sext.
11763 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
11764 EVT MemVT = LD->getMemoryVT();
11765 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
11766 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
11767 LD->getExtensionType() == ISD::ZEXTLOAD))
11768 return true;
11769 }
11770
11771 return TargetLowering::isZExtFree(Val, VT2);
11772}
11773
11775 EVT DstVT) const {
11776 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
11777}
11778
11780 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
11781}
11782
11784 // TODO: Support vectors.
11785 if (Y.getValueType().isVector())
11786 return false;
11787
11788 return !isa<ConstantSDNode>(Y);
11789}
11790
11792 // LAMCAS will use amcas[_DB].{b/h/w/d} which does not require extension.
11793 return Subtarget.hasLAMCAS() ? ISD::ANY_EXTEND : ISD::SIGN_EXTEND;
11794}
11795
11797 Type *Ty, bool IsSigned) const {
11798 if (Subtarget.is64Bit() && Ty->isIntegerTy(32))
11799 return true;
11800
11801 return IsSigned;
11802}
11803
11805 // Return false to suppress the unnecessary extensions if the LibCall
11806 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
11807 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
11808 Type.getSizeInBits() < Subtarget.getGRLen()))
11809 return false;
11810 return true;
11811}
11812
11813// memcpy, and other memory intrinsics, typically tries to use wider load/store
11814// if the source/dest is aligned and the copy size is large enough. We therefore
11815// want to align such objects passed to memory intrinsics.
11817 unsigned &MinSize,
11818 Align &PrefAlign) const {
11819 if (!isa<MemIntrinsic>(CI))
11820 return false;
11821
11822 if (Subtarget.is64Bit()) {
11823 MinSize = 8;
11824 PrefAlign = Align(8);
11825 } else {
11826 MinSize = 4;
11827 PrefAlign = Align(4);
11828 }
11829
11830 return true;
11831}
11832
11835 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
11836 VT.getVectorElementType() != MVT::i1)
11837 return TypeWidenVector;
11838
11840}
11841
11842bool LoongArchTargetLowering::splitValueIntoRegisterParts(
11843 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
11844 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
11845 bool IsABIRegCopy = CC.has_value();
11846 EVT ValueVT = Val.getValueType();
11847
11848 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11849 PartVT == MVT::f32) {
11850 // Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
11851 // nan, and cast to f32.
11852 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Val);
11853 Val = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Val);
11854 Val = DAG.getNode(ISD::OR, DL, MVT::i32, Val,
11855 DAG.getConstant(0xFFFF0000, DL, MVT::i32));
11856 Val = DAG.getNode(ISD::BITCAST, DL, MVT::f32, Val);
11857 Parts[0] = Val;
11858 return true;
11859 }
11860
11861 return false;
11862}
11863
11864SDValue LoongArchTargetLowering::joinRegisterPartsIntoValue(
11865 SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
11866 MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
11867 bool IsABIRegCopy = CC.has_value();
11868
11869 if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
11870 PartVT == MVT::f32) {
11871 SDValue Val = Parts[0];
11872
11873 // Cast the f32 to i32, truncate to i16, and cast back to [b]f16.
11874 Val = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Val);
11875 Val = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Val);
11876 Val = DAG.getNode(ISD::BITCAST, DL, ValueVT, Val);
11877 return Val;
11878 }
11879
11880 return SDValue();
11881}
11882
11883MVT LoongArchTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
11884 CallingConv::ID CC,
11885 EVT VT) const {
11886 // Use f32 to pass f16.
11887 if (VT == MVT::f16 && Subtarget.hasBasicF())
11888 return MVT::f32;
11889
11891}
11892
11893unsigned LoongArchTargetLowering::getNumRegistersForCallingConv(
11894 LLVMContext &Context, CallingConv::ID CC, EVT VT) const {
11895 // Use f32 to pass f16.
11896 if (VT == MVT::f16 && Subtarget.hasBasicF())
11897 return 1;
11898
11900}
11901
11903 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
11904 const SelectionDAG &DAG, unsigned Depth) const {
11905 unsigned Opc = Op.getOpcode();
11906 Known.resetAll();
11907 switch (Opc) {
11908 default:
11909 break;
11910 case LoongArchISD::VANYNONZERO:
11911 case LoongArchISD::VALLZERO: {
11912 // MOVCF2GR zero-extend the i1 cond to GPR.
11913 Known.Zero.setBitsFrom(1);
11914 break;
11915 }
11916 case LoongArchISD::VPICK_ZEXT_ELT: {
11917 assert(isa<VTSDNode>(Op->getOperand(2)) && "Unexpected operand!");
11918 EVT VT = cast<VTSDNode>(Op->getOperand(2))->getVT();
11919 unsigned VTBits = VT.getScalarSizeInBits();
11920 assert(Known.getBitWidth() >= VTBits && "Unexpected width!");
11921 Known.Zero.setBitsFrom(VTBits);
11922 break;
11923 }
11924 }
11925}
11926
11928 SDValue Op, const APInt &OriginalDemandedBits,
11929 const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO,
11930 unsigned Depth) const {
11931 EVT VT = Op.getValueType();
11932 unsigned BitWidth = OriginalDemandedBits.getBitWidth();
11933 unsigned Opc = Op.getOpcode();
11934 switch (Opc) {
11935 default:
11936 break;
11937 case LoongArchISD::CRC_W_B_W:
11938 case LoongArchISD::CRC_W_H_W:
11939 case LoongArchISD::CRCC_W_B_W:
11940 case LoongArchISD::CRCC_W_H_W: {
11941 KnownBits KnownSrc;
11942 APInt DemandedSrcBits =
11943 APInt::getLowBitsSet(BitWidth, (Opc == LoongArchISD::CRC_W_B_W ||
11944 Opc == LoongArchISD::CRCC_W_B_W)
11945 ? 8
11946 : 16);
11947 return SimplifyDemandedBits(Op.getOperand(1), DemandedSrcBits,
11948 OriginalDemandedElts, KnownSrc, TLO, Depth + 1);
11949 }
11950 case LoongArchISD::VMSKLTZ:
11951 case LoongArchISD::XVMSKLTZ: {
11952 SDValue Src = Op.getOperand(0);
11953 MVT SrcVT = Src.getSimpleValueType();
11954 unsigned SrcBits = SrcVT.getScalarSizeInBits();
11955 unsigned NumElts = SrcVT.getVectorNumElements();
11956
11957 // If we don't need the sign bits at all just return zero.
11958 if (OriginalDemandedBits.countr_zero() >= NumElts)
11959 return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT));
11960
11961 // Only demand the vector elements of the sign bits we need.
11962 APInt KnownUndef, KnownZero;
11963 APInt DemandedElts = OriginalDemandedBits.zextOrTrunc(NumElts);
11964 if (SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero,
11965 TLO, Depth + 1))
11966 return true;
11967
11968 Known.Zero = KnownZero.zext(BitWidth);
11969 Known.Zero.setHighBits(BitWidth - NumElts);
11970
11971 // [X]VMSKLTZ only uses the MSB from each vector element.
11972 KnownBits KnownSrc;
11973 APInt DemandedSrcBits = APInt::getSignMask(SrcBits);
11974 if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, KnownSrc, TLO,
11975 Depth + 1))
11976 return true;
11977
11978 if (KnownSrc.One[SrcBits - 1])
11979 Known.One.setLowBits(NumElts);
11980 else if (KnownSrc.Zero[SrcBits - 1])
11981 Known.Zero.setLowBits(NumElts);
11982
11983 // Attempt to avoid multi-use ops if we don't need anything from it.
11985 Src, DemandedSrcBits, DemandedElts, TLO.DAG, Depth + 1))
11986 return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, SDLoc(Op), VT, NewSrc));
11987 return false;
11988 }
11989 }
11990
11992 Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
11993}
11994
11996 unsigned Opc = VecOp.getOpcode();
11997
11998 // Assume target opcodes can't be scalarized.
11999 // TODO - do we have any exceptions?
12000 if (Opc >= ISD::BUILTIN_OP_END || !isBinOp(Opc))
12001 return false;
12002
12003 // If the vector op is not supported, try to convert to scalar.
12004 EVT VecVT = VecOp.getValueType();
12006 return true;
12007
12008 // If the vector op is supported, but the scalar op is not, the transform may
12009 // not be worthwhile.
12010 EVT ScalarVT = VecVT.getScalarType();
12011 return isOperationLegalOrCustomOrPromote(Opc, ScalarVT);
12012}
12013
12016 unsigned Index) const {
12019
12020 // Extract a 128-bit subvector from index 0 of a 256-bit vector is free.
12021 if (Index == 0)
12024}
12025
12027 unsigned Index) const {
12028 EVT EltVT = VT.getScalarType();
12029
12030 // Extract a scalar FP value from index 0 of a vector is free.
12031 return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
12032}
12033
12035 const MachineFunction &MF) const {
12036
12037 // If the function specifically requests inline stack probes, emit them.
12038 if (MF.getFunction().hasFnAttribute("probe-stack"))
12039 return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
12040 "inline-asm";
12041
12042 return false;
12043}
12044
12046 Align StackAlign) const {
12047 // The default stack probe size is 4096 if the function has no
12048 // stack-probe-size attribute.
12049 const Function &Fn = MF.getFunction();
12050 unsigned StackProbeSize =
12051 Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
12052 // Round down to the stack alignment.
12053 StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
12054 return StackProbeSize ? StackProbeSize : StackAlign.value();
12055}
12056
12057SDValue
12058LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
12059 SelectionDAG &DAG) const {
12061 if (!hasInlineStackProbe(MF))
12062 return SDValue();
12063
12064 const MVT GRLenVT = Subtarget.getGRLenVT();
12065 // Get the inputs.
12066 SDValue Chain = Op.getOperand(0);
12067 SDValue Size = Op.getOperand(1);
12068
12069 const MaybeAlign Align =
12070 cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
12071 const SDLoc dl(Op);
12072 const EVT VT = Op.getValueType();
12073
12074 // Construct the new SP value in a GPR.
12075 SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
12076 Chain = SP.getValue(1);
12077 SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
12078 if (Align)
12079 SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
12080 DAG.getSignedConstant(-Align->value(), dl, VT));
12081
12082 // Set the real SP to the new value with a probing loop.
12083 Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
12084 return DAG.getMergeValues({SP, Chain}, dl);
12085}
12086
12089 MachineBasicBlock *MBB) const {
12090 MachineFunction &MF = *MBB->getParent();
12091 MachineBasicBlock::iterator MBBI = MI.getIterator();
12092 DebugLoc DL = MBB->findDebugLoc(MBBI);
12093 const Register TargetReg = MI.getOperand(0).getReg();
12094
12095 const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
12096 const bool IsLA64 = Subtarget.is64Bit();
12097 const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
12098 const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
12099 const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
12100
12101 MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
12102 MachineBasicBlock *const LoopTestMBB =
12103 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12104 MF.insert(MBBInsertPoint, LoopTestMBB);
12105 MachineBasicBlock *const ExitMBB =
12106 MF.CreateMachineBasicBlock(MBB->getBasicBlock());
12107 MF.insert(MBBInsertPoint, ExitMBB);
12108 const Register SPReg = LoongArch::R3;
12109 const Register ScratchReg =
12110 MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
12111
12112 // ScratchReg = ProbeSize
12113 TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
12114
12115 // LoopTest:
12116 // sub.{w/d} $sp, $sp, ScratchReg
12117 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12118 TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
12119 .addReg(SPReg)
12120 .addReg(ScratchReg);
12121
12122 // st.{w/d} $zero, $sp, 0
12123 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
12124 TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
12125 .addReg(LoongArch::R0)
12126 .addReg(SPReg)
12127 .addImm(0);
12128
12129 // bltu TargetReg, $sp, LoopTest
12130 BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
12131 .addReg(TargetReg)
12132 .addReg(SPReg)
12133 .addMBB(LoopTestMBB);
12134
12135 // move $sp, TargetReg
12136 BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
12137 .addReg(TargetReg)
12138 .addReg(LoongArch::R0);
12139
12140 ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
12142
12143 LoopTestMBB->addSuccessor(ExitMBB);
12144 LoopTestMBB->addSuccessor(LoopTestMBB);
12145 MBB->addSuccessor(LoopTestMBB);
12146
12147 MI.eraseFromParent();
12148 MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
12149 return ExitMBB->begin()->getParent();
12150}
static MCRegister MatchRegisterName(StringRef Name)
static SDValue performSHLCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
If the operand is a bitwise AND with a constant RHS, and the shift has a constant RHS and is the only...
static bool checkValueWidth(SDValue V, unsigned width, ISD::LoadExtType &ExtType)
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSELECT_CCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
unsigned Imm
unsigned uint64_t
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static MCRegister MatchRegisterAltName(StringRef Name)
Maps from the set of all alternative registernames to a register number.
Function Alias Analysis Results
static uint64_t getConstant(const Value *IndexValue)
static SDValue getTargetNode(ConstantPoolSDNode *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG, unsigned Flags)
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static MachineBasicBlock * emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode)
static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static bool isSigned(unsigned Opcode)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RegName(no)
static SDValue performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
const MCPhysReg ArgFPR32s[]
static SDValue lower128BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 128-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_XVSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVSHUF4I (if possible).
const MCPhysReg ArgVRs[]
static SDValue lowerVECTOR_SHUFFLE_VPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKEV (if possible).
static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKOD (if possible).
static SDValue unpackF64OnLA32DSoftABI(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const CCValAssign &HiVA, const SDLoc &DL)
static bool fitsRegularPattern(typename SmallVectorImpl< ValType >::const_iterator Begin, unsigned CheckStride, typename SmallVectorImpl< ValType >::const_iterator End, ValType ExpectedIndex, unsigned ExpectedIndexStride)
Determine whether a range fits a regular pattern of values.
static SDValue lowerVECTOR_SHUFFLE_IsReverse(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE whose result is the reversed source vector.
static SDValue PromoteMaskArithmetic(SDValue N, const SDLoc &DL, EVT VT, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned Depth)
static SDValue performUINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performHorizWideningCombine(SDNode *N, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static std::pair< SDValue, EVT > stripSignExtendInReg(SDValue V)
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static SDValue ExtendSrcToDst(SDNode *N, SelectionDAG &DAG, unsigned ExtendOp)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static SDValue lowerVECTOR_SHUFFLE_XVPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF.
static int getEstimateRefinementSteps(EVT VT, const LoongArchSubtarget &Subtarget)
static bool isSupportedReciprocalEstimateType(EVT VT, const LoongArchSubtarget &Subtarget)
static void emitErrorAndReplaceIntrinsicResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, StringRef ErrorMsg, bool WithChain=true)
static SDValue lowerVECTOR_SHUFFLEAsByteRotate(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE as byte rotate (if possible).
static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVINSVE0(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVINSVE0 (if possible).
static SDValue performMOVFR2GR_SCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVH (if possible).
static SDValue performDemandedBitsCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsRet, Type *OrigTy)
static std::tuple< unsigned, SDValue, EVT > matchBinOpWithSharedOperand(SDValue BinV, SDValue X)
static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static SDValue performSPLIT_PAIR_F64Combine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performBITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static MachineBasicBlock * emitSplitPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG)
static SDValue performSETCC_BITCASTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
@ NoMaterializeFPImm
@ MaterializeFPImm2Ins
@ MaterializeFPImm5Ins
@ MaterializeFPImm6Ins
@ MaterializeFPImm3Ins
@ MaterializeFPImm4Ins
static SDValue performEXTENDCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_XVPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKOD (if possible).
static bool buildVPERMIInfo(ArrayRef< int > Mask, SDValue V1, SDValue V2, SmallVectorImpl< SDValue > &SrcVec, unsigned &MaskImm)
static std::optional< bool > matchSetCC(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue Val)
static SDValue combineAndNotIntoVANDN(SDNode *N, const SDLoc &DL, SelectionDAG &DAG)
Try to fold: (and (xor X, -1), Y) -> (vandn X, Y).
static SDValue lowerBUILD_VECTORAsBroadCastLoad(BuildVectorSDNode *BVOp, const SDLoc &DL, SelectionDAG &DAG)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG)
static bool checkBitcastSrcVectorSize(SDValue Src, unsigned Size, unsigned Depth)
static bool isConstantSplatVector(SDValue N, APInt &SplatValue, unsigned MinSizeInBits)
static SDValue lowerVECTOR_SHUFFLEAsShift(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as shift (if possible).
static SDValue lowerVECTOR_SHUFFLE_VSHUF4I(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VSHUF4I (if possible).
static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, Type *OrigTy, CCState &State)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVECTOR_SHUFFLE_VEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VEXTRINS (if possible).
static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG)
static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKEV (if possible).
static MachineBasicBlock * emitPseudoVMSKCOND(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue performVANDNCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
Do target-specific dag combines on LoongArchISD::VANDN nodes.
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue lowerVECTOR_SHUFFLEAsZeroOrAnyExtend(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const APInt &Zeroable)
Lower VECTOR_SHUFFLE as ZERO_EXTEND Or ANY_EXTEND (if possible).
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
static cl::opt< MaterializeFPImm > MaterializeFPImmInsNum("loongarch-materialize-float-imm", cl::Hidden, cl::desc("Maximum number of instructions used (including code sequence " "to generate the value and moving the value to FPR) when " "materializing floating-point immediates (default = 3)"), cl::init(MaterializeFPImm3Ins), cl::values(clEnumValN(NoMaterializeFPImm, "0", "Use constant pool"), clEnumValN(MaterializeFPImm2Ins, "2", "Materialize FP immediate within 2 instructions"), clEnumValN(MaterializeFPImm3Ins, "3", "Materialize FP immediate within 3 instructions"), clEnumValN(MaterializeFPImm4Ins, "4", "Materialize FP immediate within 4 instructions"), clEnumValN(MaterializeFPImm5Ins, "5", "Materialize FP immediate within 5 instructions"), clEnumValN(MaterializeFPImm6Ins, "6", "Materialize FP immediate within 6 instructions " "(behaves same as 5 on loongarch64)")))
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
const MCPhysReg ArgXRs[]
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
static unsigned getLoongArchWOpcode(unsigned Opcode)
const MCPhysReg ArgFPR64s[]
static MachineBasicBlock * emitPseudoCTPOP(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performMOVGR2FR_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static SDValue lowerVECTOR_SHUFFLE_VPACKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPACKOD (if possible).
static SDValue signExtendBitcastSrcVector(SelectionDAG &DAG, EVT SExtVT, SDValue Src, const SDLoc &DL)
static SDValue isNOT(SDValue V, SelectionDAG &DAG)
static SDValue lower256BitShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Dispatching routine to lower various 256-bit LoongArch vector shuffles.
static SDValue lowerVECTOR_SHUFFLE_VREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VREPLVEI (if possible).
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
const MCPhysReg PreserveNoneArgGPRs[]
static void fillVector(ArrayRef< SDValue > Ops, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, SDValue &Vector, EVT ResTy)
static SDValue fillSubVectorFromBuildVector(BuildVectorSDNode *Node, SelectionDAG &DAG, SDLoc DL, const LoongArchSubtarget &Subtarget, EVT ResTy, unsigned first)
static bool isSelectPseudo(MachineInstr &MI)
static SDValue foldVMskZeroTest(SDValue LHS, SDValue RHS, ISD::CondCode CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue foldBinOpIntoSelectIfProfitable(SDNode *BO, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
const MCPhysReg ArgGPRs[]
static SDValue lowerVECTOR_SHUFFLE_XVPERM(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVPERM (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVL (if possible).
static SDValue performFP_TO_INTCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLE_VPERMI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into VPERMI (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVEXTRINS(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVEXTRINS (if possible).
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, unsigned ExtOpc=ISD::ANY_EXTEND)
static void replaceVecCondBranchResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
#define ASRT_LE_GT_CASE(NAME)
static SDValue lowerVECTOR_SHUFFLE_XVPACKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPACKEV (if possible).
static SDValue matchDeinterleaveBuildVector(SDValue N, unsigned &StartIndex)
static SDValue performBR_CCCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static void computeZeroableShuffleElements(ArrayRef< int > Mask, SDValue V1, SDValue V2, APInt &KnownUndef, APInt &KnownZero)
Compute whether each element of a shuffle is zeroable.
static SDValue combineFP_ROUND(SDValue N, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
static SDValue performCONCAT_VECTORSCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue widenShuffleMask(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
static MachineBasicBlock * emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static bool canonicalizeShuffleVectorByLane(const SDLoc &DL, MutableArrayRef< int > Mask, MVT VT, SDValue &V1, SDValue &V2, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Shuffle vectors by lane to generate more optimized instructions.
static SDValue lowerVECTOR_SHUFFLE_XVILVH(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVILVH (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVSHUF(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVSHUF (if possible).
static void replaceCMP_XCHG_128Results(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG)
static SDValue lowerVectorPickVE2GR(SDNode *N, SelectionDAG &DAG, unsigned ResOp)
static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue matchHalfOf128BitLanes(SDValue N, bool isLow)
#define IOCSRRD_CASE(NAME, NODE)
static int matchShuffleAsByteRotate(MVT VT, SDValue &V1, SDValue &V2, ArrayRef< int > Mask)
Attempts to match vector shuffle as byte rotation.
static SDValue lowerVECTOR_SHUFFLE_XVPICKEV(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into XVPICKEV (if possible).
static SDValue lowerVECTOR_SHUFFLE_XVREPLVEI(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
Lower VECTOR_SHUFFLE into XVREPLVEI (if possible).
static int matchShuffleAsShift(MVT &ShiftVT, unsigned &Opcode, unsigned ScalarSizeInBits, ArrayRef< int > Mask, int MaskOffset, const APInt &Zeroable)
Attempts to match a shuffle mask against the VBSLL, VBSRL, VSLLI and VSRLI instruction.
static SDValue lowerVECTOR_SHUFFLE_VILVL(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VILVL (if possible).
static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG)
static MachineBasicBlock * emitBuildPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVECTOR_SHUFFLEAsLanePermuteAndShuffle(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE as lane permute and then shuffle (if possible).
static void replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
#define CSR_CASE(ID)
static SDValue MergeBlocksConvert(SDNode *N, SelectionDAG &DAG, unsigned Opcode, unsigned BlockBits)
static SDValue lowerVECTOR_SHUFFLE_VPICKOD(const SDLoc &DL, ArrayRef< int > Mask, MVT VT, SDValue V1, SDValue V2, SelectionDAG &DAG)
Lower VECTOR_SHUFFLE into VPICKOD (if possible).
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS, ISD::CondCode &CC, SelectionDAG &DAG)
static Register allocateArgGPR(CCState &State)
static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT, ArrayRef< int > Mask, SmallVectorImpl< int > &RepeatedMask)
Test whether a shuffle mask is equivalent within each sub-lane.
static SDValue convertRMEncoding(SelectionDAG &DAG, const SDLoc &DL, MVT GRLenVT, SDValue RMValue)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO)
static constexpr MCPhysReg SPReg
const SmallVectorImpl< MachineOperand > & Cond
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
This file defines the SmallSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue, bool AllowSymbol=false)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static bool isSequentialOrUndefInRange(ArrayRef< int > Mask, unsigned Pos, unsigned Size, int Low, int Step=1)
Return true if every element in Mask, beginning from position Pos and ending in Pos + Size,...
Value * RHS
Value * LHS
bool isZero() const
Definition APFloat.h:1579
LLVM_READONLY bool isOne() const
Definition APFloat.h:1661
APInt bitcastToAPInt() const
Definition APFloat.h:1475
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1350
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
Definition APInt.h:367
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1659
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:431
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1261
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
Definition APInt.h:282
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition Argument.h:50
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
An instruction that atomically checks whether a specified value is in a memory location,...
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ UDecWrap
Decrement one until a minimum value or zero.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
bool isFloatingPointOperation() const
BinOp getOperation() const
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool test(unsigned Idx) const
Returns true if bit Idx is set.
Definition BitVector.h:482
size_type count() const
Returns the number of bits which are set.
Definition BitVector.h:181
A "pseudo-class" with methods for operating on BUILD_VECTORs.
CCState - This class holds information needed while lowering arguments and return values.
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
LLVM_ABI void AnalyzeCallOperands(const SmallVectorImpl< ISD::OutputArg > &Outs, CCAssignFn Fn)
AnalyzeCallOperands - Analyze the outgoing arguments to a call, incorporating info about the passed v...
uint64_t getStackSize() const
Returns the size of the currently allocated portion of the stack.
LLVM_ABI void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
CCValAssign - Represent assignment of one arg/retval to a location.
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP, bool IsCustom=false)
static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT, MCRegister Reg, MVT LocVT, LocInfo HTP)
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool needsCustom() const
int64_t getLocMemOffset() const
unsigned getValNo() const
static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
const APFloat & getValueAPF() const
This is the shared class of boolean and integer constants.
Definition Constants.h:87
bool isMinusOne() const
This function will return true iff every bit in this constant is set to true.
Definition Constants.h:231
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition Constants.h:219
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition Constant.h:43
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
Definition DataLayout.h:501
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
A debug info location.
Definition DebugLoc.h:126
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
iterator_range< arg_iterator > args()
Definition Function.h:877
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:769
uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const
For a string attribute Kind, parse attribute as an integer.
Definition Function.cpp:781
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:356
Argument * getArg(unsigned i) const
Definition Function.h:871
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:734
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:2918
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This class is used to represent ISD::LOAD nodes.
const SDValue & getBasePtr() const
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
void setIncomingIndirectArg(unsigned ArgIndex, Register Reg)
Register getIncomingIndirectArg(unsigned ArgIndex) const
const LoongArchRegisterInfo * getRegisterInfo() const override
const LoongArchTargetLowering * getTargetLowering() const override
const LoongArchInstrInfo * getInstrInfo() const override
bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override
Return true if result of the specified node is used by a return node only.
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override
This method will be invoked for all target nodes and for any target-independent nodes that the target...
Register getExceptionPointerRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps, bool &UseOneConstNR, bool Reciprocal) const override
Hooks for building estimates in place of slower divisions and square roots.
bool isLegalICmpImmediate(int64_t Imm) const override
Return true if the specified immediate is legal icmp immediate, that is the target has icmp instructi...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< bool, uint64_t > isImmVLDILegalForMode1(const APInt &SplatValue, const unsigned SplatBitSize) const
Check if a constant splat can be generated using [x]vldi, where imm[12] is 1.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
bool hasInlineStackProbe(const MachineFunction &MF) const override
True if stack clash protection is enabled for this function.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
Register getExceptionSelectorRegister(ExceptionHandling EH, const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
bool isExtractVecEltCheap(EVT VT, unsigned Index) const override
Return true if extraction of a scalar element from the given vector type at the given index is cheap.
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override
Return true if sign-extension from FromTy to ToTy is cheaper than zero-extension.
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const override
Determine if the target supports unaligned memory accesses.
bool isCheapToSpeculateCtlz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic ctlz.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
bool shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, Align &PrefAlign) const override
Return true if the pointer arguments to CI should be aligned by aligning the object whose address is ...
Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override
Perform a masked atomicrmw using a target-specific intrinsic.
bool isZExtFree(SDValue Val, EVT VT2) const override
Return true if zero-extending the specific node Val to type VT2 is free (either because it's implicit...
void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const override
Determine which of the bits specified in Mask are known to be either zero or one and return them in t...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, unsigned Index) const override
Return the cost of extracting a subvector of type ResVT from a vector of type SrcVT,...
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
bool isLegalAddImmediate(int64_t Imm) const override
Return true if the specified immediate is legal add immediate, that is the target has add instruction...
bool isCheapToSpeculateCttz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic cttz.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
MachineBasicBlock * emitDynamicProbedAlloc(MachineInstr &MI, MachineBasicBlock *MBB) const
bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override
Returns true if arguments should be sign-extended in lib calls.
bool shouldScalarizeBinop(SDValue VecOp) const override
Try to convert an extract element of a vector binary operation into an extract element followed by a ...
bool isFPImmVLDILegal(const APFloat &Imm, EVT VT) const
bool shouldExtendTypeInLibCall(EVT Type) const override
Returns true if arguments should be extended in lib calls.
Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override
Return the register ID of the name passed in.
bool hasAndNot(SDValue Y) const override
Return true if the target has a bitwise and-not operation: X = ~A & B This can be used to simplify se...
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override
Return true if folding a constant offset with the given GlobalAddress is legal.
unsigned getStackProbeSize(const MachineFunction &MF, Align StackAlign) const
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const override
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
void emitExpandAtomicRMW(AtomicRMWInst *AI) const override
Perform a atomicrmw expansion using a target-specific way.
ISD::NodeType getExtendForAtomicCmpSwapArg() const override
Returns how the platform's atomic compare and swap expects its comparison value to be extended (ZERO_...
LoongArchTargetLowering(const TargetMachine &TM, const LoongArchSubtarget &STI)
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
bool hasAndNotCompare(SDValue Y) const override
Return true if the target should transform: (X & Y) == Y ---> (~X & Y) == 0 (X & Y) !...
SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &RefinementSteps) const override
Return a reciprocal estimate value for the input operand.
bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT, const MachineFunction &MF) const override
Returns if it's reasonable to merge stores to MemVT size.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context, const Type *RetTy) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
bool mayBeEmittedAsTailCall(const CallInst *CI) const override
Return true if the target may be able emit the call instruction as a tail call.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
bool hasFeature(unsigned Feature) const
Machine Value Type.
static MVT getFloatingPointVT(unsigned BitWidth)
bool is128BitVector() const
Return true if this is a 128-bit vector type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
bool is256BitVector() const
Return true if this is a 256-bit vector type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
MVT getDoubleNumVectorElementsVT() const
MVT getHalfNumVectorElementsVT() const
Return a VT for a vector type with the same element type but half the number of elements.
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
MVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
LLVM_ABI void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
void push_back(MachineInstr *MI)
void setCallFrameSize(unsigned N)
Set the call frame size on entry to this basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
LLVM_ABI int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
bool isImplicitDef() const
LLVM_ABI void collectDebugValues(SmallVectorImpl< MachineInstr * > &DbgValues)
Scan instructions immediately following MI and collect any matching DBG_VALUEs.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
Flags
Flags values. These may be or'd together.
@ MOVolatile
The memory access is volatile.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Align getAlign() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const MachinePointerInfo & getPointerInfo() const
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
Class to represent pointers.
unsigned getAddressSpace() const
Return the address space of the Pointer type.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
LLVM_ABI bool isOnlyUserOf(const SDNode *N) const
Return true if this node is the only use of N.
size_t use_size() const
Return the number of uses of this node.
MVT getSimpleValueType(unsigned ResNo) const
Return the type of a specified result as a simple type.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
MVT getSimpleValueType() const
Return the simple ValueType of the referenced return value.
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue FoldSetCC(EVT VT, SDValue N1, SDValue N2, ISD::CondCode Cond, const SDLoc &dl, SDNodeFlags Flags={})
Constant fold a setcc to true or false.
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, Register Reg, SDValue N)
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getShiftAmountConstant(uint64_t Val, EVT VT, const SDLoc &DL)
LLVM_ABI SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget=false, bool IsOpaque=false)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getFreeze(SDValue V)
Return a freeze using the SDLoc of the value operand.
bool isSafeToSpeculativelyExecute(unsigned Opcode) const
Some opcodes may create immediate undefined behavior when used with some values (integer division-by-...
SDValue getExtractSubvector(const SDLoc &DL, EVT VT, SDValue Vec, unsigned Idx)
Return the VT typed sub-vector of Vec at Idx.
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
SDValue getInsertSubvector(const SDLoc &DL, SDValue Vec, SDValue SubVec, unsigned Idx)
Insert SubVec at the Idx element of Vec.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
LLVM_ABI SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
LLVM_ABI SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align DstAlign, Align SrcAlign, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), BatchAAResults *BatchAA=nullptr)
const TargetLowering & getTargetLoweringInfo() const
static constexpr unsigned MaxRecursionDepth
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI bool isSplatValue(SDValue V, const APInt &DemandedElts, APInt &UndefElts, unsigned Depth=0) const
Test whether V has a splatted value for all the demanded elements.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, Register Reg, EVT VT)
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
LLVM_ABI SDValue getNegative(SDValue Val, const SDLoc &DL, EVT VT)
Create negative operation as (SUB 0, Val).
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
LLVM_ABI SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT VT)
Return the expression required to zero extend the Op value assuming it was the smaller SrcTy value.
const DataLayout & getDataLayout() const
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
SDValue getSignedTargetConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI void ReplaceAllUsesWith(SDValue From, SDValue To)
Modify anything using 'From' to use 'To' instead.
LLVM_ABI SDValue getCommutedVectorShuffle(const ShuffleVectorSDNode &SV)
Returns an ISD::VECTOR_SHUFFLE node semantically equivalent to the shuffle node in input but with swa...
LLVM_ABI SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
LLVM_ABI std::pair< SDValue, SDValue > SplitVector(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the vector with EXTRACT_SUBVECTOR using the provided VTs and return the low/high part.
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
SDValue getCALLSEQ_START(SDValue Chain, uint64_t InSize, uint64_t OutSize, const SDLoc &DL)
Return a new CALLSEQ_START node, that starts new call frame, in which InSize bytes are set up inside ...
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Loads are not normal binary operators: their result type is not determined by their operands,...
LLVM_ABI SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDValue > Ops, SDNodeFlags Flags=SDNodeFlags())
LLVM_ABI SDValue getExternalSymbol(const char *Sym, EVT VT)
const TargetMachine & getTarget() const
LLVM_ABI SDValue WidenVector(const SDValue &N, const SDLoc &DL)
Widen the vector up to the next power of two using INSERT_SUBVECTOR.
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI unsigned ComputeNumSignBits(SDValue Op, unsigned Depth=0) const
Return the number of times the sign bit of the register is replicated into the other bits.
SDValue getTargetBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset=0, unsigned TargetFlags=0)
LLVM_ABI SDValue getVectorIdxConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI void ReplaceAllUsesOfValueWith(SDValue From, SDValue To)
Replace any uses of From with To, leaving uses of other values produced by From.getNode() alone.
MachineFunction & getMachineFunction() const
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
LLVM_ABI SDValue getRegisterMask(const uint32_t *RegMask)
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVM_ABI SDValue getCondCode(ISD::CondCode Cond)
LLVM_ABI bool MaskedValueIsZero(SDValue Op, const APInt &Mask, unsigned Depth=0) const
Return true if 'Op & Mask' is known to be zero.
LLVMContext * getContext() const
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
LLVM_ABI SDValue CreateStackTemporary(TypeSize Bytes, Align Alignment)
Create a stack temporary based on the size in bytes and the alignment.
SDValue getTargetConstantPool(const Constant *C, EVT VT, MaybeAlign Align=std::nullopt, int Offset=0, unsigned TargetFlags=0)
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
SDValue getSplat(EVT VT, const SDLoc &DL, SDValue Op)
Returns a node representing a splat of one value into all lanes of the provided vector type.
LLVM_ABI std::pair< SDValue, SDValue > SplitScalar(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the scalar node with EXTRACT_ELEMENT using the provided VTs and return the low/high part.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
static LLVM_ABI bool isReverseMask(ArrayRef< int > Mask, int NumSrcElts)
Return true if this shuffle mask swaps the order of elements from exactly one source vector.
ArrayRef< int > getMask() const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:176
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:184
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
void reserve(size_type N)
typename SuperClass::const_iterator const_iterator
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:30
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
TargetInstrInfo - Interface to description of machine instruction set.
void setBooleanVectorContents(BooleanContent Ty)
Specify how the target extends the result of a vector boolean value from a vector of i1 to a wider ty...
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
MachineBasicBlock * emitPatchPoint(MachineInstr &MI, MachineBasicBlock *MBB) const
Replace/modify any TargetFrameIndex operands with a targte-dependent sequence of memory operands that...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
const TargetMachine & getTargetMachine() const
virtual unsigned getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain targets require unusual breakdowns of certain types.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain combinations of ABIs, Targets and features require that types are legal for some operations a...
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
void setMaxBytesForAlignment(unsigned MaxBytes)
bool isOperationLegalOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal using promotion.
void setPrefLoopAlignment(Align Alignment)
Set the target's preferred loop alignment.
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
virtual TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const
Return the preferred vector type legalization action.
void setMinFunctionAlignment(Align Alignment)
Set the target's minimum function alignment.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
virtual EVT getTypeToTransformTo(LLVMContext &Context, EVT VT) const
For types supported by the target, this is an identity function.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
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.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
bool isOperationLegalOrCustom(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
virtual bool isBinOp(unsigned Opcode) const
Return true if the node is a math/logic binary operator.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
LegalizeTypeAction getTypeAction(LLVMContext &Context, EVT VT) const
Return how we should legalize values of this type, either it is already legal (return 'Legal') or we ...
std::vector< ArgListEntry > ArgListTy
bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT, bool LegalOnly=false) const
Return true if the specified operation is legal on this target or can be made legal with custom lower...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
bool SimplifyDemandedVectorElts(SDValue Op, const APInt &DemandedEltMask, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Vector Op.
virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const
SDValue SimplifyMultipleUseDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth=0) const
More limited version of SimplifyDemandedBits that can be used to "lookthrough" ops that don't contrib...
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
std::pair< SDValue, SDValue > LowerCallTo(CallLoweringInfo &CLI) const
This function lowers an abstract call to a function into an actual call.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0, bool AssumeSingleUse=false) const
Look at Op.
virtual bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0) const
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
TargetLowering(const TargetLowering &)=delete
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::LibcallImpl LibcallImpl, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
Primary interface to the complete machine description for the target machine.
bool useTLSDESC() const
Returns true if this target uses TLS Descriptors.
bool useEmulatedTLS() const
Returns true if this target uses emulated TLS.
bool shouldAssumeDSOLocal(const GlobalValue *GV) const
CodeModel::Model getCodeModel() const
Returns the code model.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
This class is used to represent EVT's, which are used to parameterize some operations.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ PreserveMost
Used for runtime calls that preserves most registers.
Definition CallingConv.h:63
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
Definition CallingConv.h:50
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ PreserveNone
Used for runtime calls that preserves none general registers.
Definition CallingConv.h:90
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI bool isConstantSplatVectorAllOnes(const SDNode *N, bool BuildVectorOnly=false)
Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where all of the elements are ~0 ...
bool isNON_EXTLoad(const SDNode *N)
Returns true if the specified node is a non-extending load.
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition ISDOpcodes.h:43
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:837
@ 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:797
@ 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:871
@ 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:898
@ 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:757
@ 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:928
@ 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.
Definition ISDOpcodes.h:993
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:862
@ AVGCEILS
AVGCEILS/AVGCEILU - Rounding averaging add - Add two integers using an integer of type i[N+2],...
Definition ISDOpcodes.h:725
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:675
@ PREFETCH
PREFETCH - This corresponds to a prefetch intrinsic.
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ BR_CC
BR_CC - Conditional branch.
@ BR_JT
BR_JT - Jumptable branch.
@ FCANONICALIZE
Returns platform specific canonical encoding of a floating point number.
Definition ISDOpcodes.h:546
@ IS_FPCLASS
Performs a check of floating point class property, defined by IEEE-754.
Definition ISDOpcodes.h:553
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:377
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:814
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:235
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
@ VECREDUCE_ADD
Integer reductions may have a result type larger than the vector element type.
@ GET_ROUNDING
Returns current rounding mode: -1 Undefined 0 Round to 0 1 Round to nearest, ties to even 2 Round to ...
Definition ISDOpcodes.h:988
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:714
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:779
@ 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 - Perform floating-point minimumNumber or maximumNumber on two values,...
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition ISDOpcodes.h: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:868
@ 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:829
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ FMINNUM
FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values, following IEEE-754 definition...
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:906
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:737
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:996
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:823
@ 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:944
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:749
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ AVGFLOORS
AVGFLOORS/AVGFLOORU - Averaging add - Add two integers using an integer of type i[N+1],...
Definition ISDOpcodes.h:720
@ FREEZE
FREEZE - FREEZE(VAL) returns an arbitrary value if VAL is UNDEF (or is evaluated to UNDEF),...
Definition ISDOpcodes.h:243
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:570
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:55
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:977
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:939
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:874
@ 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:851
@ 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:732
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
bool isExtVecInRegOpcode(unsigned Opcode)
LLVM_ABI bool isConstantSplatVectorAllZeros(const SDNode *N, bool BuildVectorOnly=false)
Return true if the specified node is a BUILD_VECTOR or SPLAT_VECTOR where all of the elements are 0 o...
LLVM_ABI CondCode getSetCCInverse(CondCode Operation, EVT Type)
Return the operation corresponding to !(X op Y), where 'op' is a valid SetCC operation.
bool isBitwiseLogicOp(unsigned Opcode)
Whether this is bitwise logic opcode.
LLVM_ABI bool isFreezeUndef(const SDNode *N)
Return true if the specified node is FREEZE(UNDEF).
LLVM_ABI CondCode getSetCCSwappedOperands(CondCode Operation)
Return the operation corresponding to (Y op X) when given the operation for (X op Y).
LLVM_ABI bool isBuildVectorAllZeros(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are 0 or undef.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
LLVM_ABI bool isBuildVectorAllOnes(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are ~0 or undef.
LLVM_ABI NodeType getVecReduceBaseOpcode(unsigned VecReduceOpcode)
Get underlying scalar opcode for VECREDUCE opcode.
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
bool isNormalLoad(const SDNode *N)
Returns true if the specified node is a non-extending and unindexed load.
bool isIntEqualitySetCC(CondCode Code)
Return true if this is a setcc instruction that performs an equality comparison when used with intege...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
ABI getTargetABI(StringRef ABIName)
InstSeq generateInstSeq(int64_t Val)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:55
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
Definition PtrState.h:41
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
Definition Threading.h:280
@ Offset
Definition DWP.cpp:577
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
LLVM_ABI SDValue peekThroughBitcasts(SDValue V)
Return the non-bitcasted source operand of V if it exists.
constexpr RegState getKillRegState(bool B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
bool isIntOrFPConstant(SDValue V)
Return true if V is either a integer or FP constant.
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition bit.h:325
constexpr T alignDown(U Value, V Align, W Skew=0)
Returns the largest unsigned integer less than or equal to Value and is Skew mod Align.
Definition MathExtras.h:541
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
LLVM_ABI bool widenShuffleMaskElts(int Scale, ArrayRef< int > Mask, SmallVectorImpl< int > &ScaledMask)
Try to transform a shuffle mask by replacing elements with the scaled index for an equivalent mask of...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition MathExtras.h:274
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:262
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Other
Any other memory.
Definition ModRef.h:68
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr bool isShiftedInt(int64_t x)
Checks if a signed integer is an N bit number shifted left by S.
Definition MathExtras.h:183
constexpr unsigned BitWidth
std::string join_items(Sep Separator, Args &&... Items)
Joins the strings in the parameter pack Items, adding Separator between the elements....
ExceptionHandling
Definition CodeGen.h:54
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool isOneConstant(SDValue V)
Returns true if V is a constant integer one.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:267
LLVM_ABI bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Extended Value Type.
Definition ValueTypes.h:35
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition ValueTypes.h:90
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition ValueTypes.h:418
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:307
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:323
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:155
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition ValueTypes.h:230
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition ValueTypes.h:55
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition ValueTypes.h:235
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:484
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:160
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset, uint8_t ID=0)
Stack pointer relative access.
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
This structure contains all information that is necessary for lowering calls.
SmallVector< ISD::InputArg, 32 > Ins
SmallVector< ISD::OutputArg, 32 > Outs
LLVM_ABI SDValue CombineTo(SDNode *N, ArrayRef< SDValue > To, bool AddTo=true)
This structure is used to pass arguments to makeLibCall function.
MakeLibCallOptions & setTypeListBeforeSoften(ArrayRef< EVT > OpsVT, EVT RetVT)
A convenience struct that encapsulates a DAG, and two SDValues for returning information from TargetL...