LLVM 19.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"
18#include "LoongArchSubtarget.h"
22#include "llvm/ADT/Statistic.h"
27#include "llvm/IR/IRBuilder.h"
28#include "llvm/IR/IntrinsicsLoongArch.h"
30#include "llvm/Support/Debug.h"
34
35using namespace llvm;
36
37#define DEBUG_TYPE "loongarch-isel-lowering"
38
39STATISTIC(NumTailCalls, "Number of tail calls");
40
41static cl::opt<bool> ZeroDivCheck("loongarch-check-zero-division", cl::Hidden,
42 cl::desc("Trap on integer division by zero."),
43 cl::init(false));
44
46 const LoongArchSubtarget &STI)
47 : TargetLowering(TM), Subtarget(STI) {
48
49 MVT GRLenVT = Subtarget.getGRLenVT();
50
51 // Set up the register classes.
52
53 addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
54 if (Subtarget.hasBasicF())
55 addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
56 if (Subtarget.hasBasicD())
57 addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
58
59 static const MVT::SimpleValueType LSXVTs[] = {
60 MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64, MVT::v4f32, MVT::v2f64};
61 static const MVT::SimpleValueType LASXVTs[] = {
62 MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64, MVT::v8f32, MVT::v4f64};
63
64 if (Subtarget.hasExtLSX())
65 for (MVT VT : LSXVTs)
66 addRegisterClass(VT, &LoongArch::LSX128RegClass);
67
68 if (Subtarget.hasExtLASX())
69 for (MVT VT : LASXVTs)
70 addRegisterClass(VT, &LoongArch::LASX256RegClass);
71
72 // Set operations for LA32 and LA64.
73
75 MVT::i1, Promote);
76
83
86 GRLenVT, Custom);
87
89
94
97
101
102 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
103 // we get to know which of sll and revb.2h is faster.
106
107 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
108 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
109 // and i32 could still be byte-swapped relatively cheaply.
111
117
120
121 // Set operations for LA64 only.
122
123 if (Subtarget.is64Bit()) {
141
145 }
146
147 // Set operations for LA32 only.
148
149 if (!Subtarget.is64Bit()) {
155 }
156
158
159 static const ISD::CondCode FPCCToExpand[] = {
162
163 // Set operations for 'F' feature.
164
165 if (Subtarget.hasBasicF()) {
166 setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
167 setTruncStoreAction(MVT::f32, MVT::f16, Expand);
168 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
169
185
186 if (Subtarget.is64Bit())
188
189 if (!Subtarget.hasBasicD()) {
191 if (Subtarget.is64Bit()) {
194 }
195 }
196 }
197
198 // Set operations for 'D' feature.
199
200 if (Subtarget.hasBasicD()) {
201 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
202 setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
203 setTruncStoreAction(MVT::f64, MVT::f16, Expand);
204 setTruncStoreAction(MVT::f64, MVT::f32, Expand);
205 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
206
222
223 if (Subtarget.is64Bit())
225 }
226
227 // Set operations for 'LSX' feature.
228
229 if (Subtarget.hasExtLSX()) {
231 // Expand all truncating stores and extending loads.
232 for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) {
233 setTruncStoreAction(VT, InnerVT, Expand);
236 setLoadExtAction(ISD::EXTLOAD, VT, InnerVT, Expand);
237 }
238 // By default everything must be expanded. Then we will selectively turn
239 // on ones that can be effectively codegen'd.
240 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op)
242 }
243
244 for (MVT VT : LSXVTs) {
248
252
255 }
256 for (MVT VT : {MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v2i64}) {
260 Legal);
262 VT, Legal);
269 Expand);
270 }
271 for (MVT VT : {MVT::v4i32, MVT::v2i64}) {
274 }
275 for (MVT VT : {MVT::v4f32, MVT::v2f64}) {
283 VT, Expand);
284 }
285 }
286
287 // Set operations for 'LASX' feature.
288
289 if (Subtarget.hasExtLASX()) {
290 for (MVT VT : LASXVTs) {
294
298
301 }
302 for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16, MVT::v32i8}) {
306 Legal);
308 VT, Legal);
315 Expand);
316 }
317 for (MVT VT : {MVT::v8i32, MVT::v4i32, MVT::v4i64}) {
320 }
321 for (MVT VT : {MVT::v8f32, MVT::v4f64}) {
329 VT, Expand);
330 }
331 }
332
333 // Set DAG combine for LA32 and LA64.
334
339
340 // Set DAG combine for 'LSX' feature.
341
342 if (Subtarget.hasExtLSX())
344
345 // Compute derived properties from the register classes.
347
349
352
354
356
357 // Function alignments.
359 // Set preferred alignments.
363}
364
366 const GlobalAddressSDNode *GA) const {
367 // In order to maximise the opportunity for common subexpression elimination,
368 // keep a separate ADD node for the global address offset instead of folding
369 // it in the global address node. Later peephole optimisations may choose to
370 // fold it back in when profitable.
371 return false;
372}
373
375 SelectionDAG &DAG) const {
376 switch (Op.getOpcode()) {
378 return lowerATOMIC_FENCE(Op, DAG);
380 return lowerEH_DWARF_CFA(Op, DAG);
382 return lowerGlobalAddress(Op, DAG);
384 return lowerGlobalTLSAddress(Op, DAG);
386 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
388 return lowerINTRINSIC_W_CHAIN(Op, DAG);
390 return lowerINTRINSIC_VOID(Op, DAG);
392 return lowerBlockAddress(Op, DAG);
393 case ISD::JumpTable:
394 return lowerJumpTable(Op, DAG);
395 case ISD::SHL_PARTS:
396 return lowerShiftLeftParts(Op, DAG);
397 case ISD::SRA_PARTS:
398 return lowerShiftRightParts(Op, DAG, true);
399 case ISD::SRL_PARTS:
400 return lowerShiftRightParts(Op, DAG, false);
402 return lowerConstantPool(Op, DAG);
403 case ISD::FP_TO_SINT:
404 return lowerFP_TO_SINT(Op, DAG);
405 case ISD::BITCAST:
406 return lowerBITCAST(Op, DAG);
407 case ISD::UINT_TO_FP:
408 return lowerUINT_TO_FP(Op, DAG);
409 case ISD::SINT_TO_FP:
410 return lowerSINT_TO_FP(Op, DAG);
411 case ISD::VASTART:
412 return lowerVASTART(Op, DAG);
413 case ISD::FRAMEADDR:
414 return lowerFRAMEADDR(Op, DAG);
415 case ISD::RETURNADDR:
416 return lowerRETURNADDR(Op, DAG);
418 return lowerWRITE_REGISTER(Op, DAG);
420 return lowerINSERT_VECTOR_ELT(Op, DAG);
422 return lowerEXTRACT_VECTOR_ELT(Op, DAG);
424 return lowerBUILD_VECTOR(Op, DAG);
426 return lowerVECTOR_SHUFFLE(Op, DAG);
427 }
428 return SDValue();
429}
430
431SDValue LoongArchTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
432 SelectionDAG &DAG) const {
433 // TODO: custom shuffle.
434 return SDValue();
435}
436
437static bool isConstantOrUndef(const SDValue Op) {
438 if (Op->isUndef())
439 return true;
440 if (isa<ConstantSDNode>(Op))
441 return true;
442 if (isa<ConstantFPSDNode>(Op))
443 return true;
444 return false;
445}
446
448 for (unsigned i = 0; i < Op->getNumOperands(); ++i)
449 if (isConstantOrUndef(Op->getOperand(i)))
450 return true;
451 return false;
452}
453
454SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,
455 SelectionDAG &DAG) const {
456 BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
457 EVT ResTy = Op->getValueType(0);
458 SDLoc DL(Op);
459 APInt SplatValue, SplatUndef;
460 unsigned SplatBitSize;
461 bool HasAnyUndefs;
462 bool Is128Vec = ResTy.is128BitVector();
463 bool Is256Vec = ResTy.is256BitVector();
464
465 if ((!Subtarget.hasExtLSX() || !Is128Vec) &&
466 (!Subtarget.hasExtLASX() || !Is256Vec))
467 return SDValue();
468
469 if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
470 /*MinSplatBits=*/8) &&
471 SplatBitSize <= 64) {
472 // We can only cope with 8, 16, 32, or 64-bit elements.
473 if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
474 SplatBitSize != 64)
475 return SDValue();
476
477 EVT ViaVecTy;
478
479 switch (SplatBitSize) {
480 default:
481 return SDValue();
482 case 8:
483 ViaVecTy = Is128Vec ? MVT::v16i8 : MVT::v32i8;
484 break;
485 case 16:
486 ViaVecTy = Is128Vec ? MVT::v8i16 : MVT::v16i16;
487 break;
488 case 32:
489 ViaVecTy = Is128Vec ? MVT::v4i32 : MVT::v8i32;
490 break;
491 case 64:
492 ViaVecTy = Is128Vec ? MVT::v2i64 : MVT::v4i64;
493 break;
494 }
495
496 // SelectionDAG::getConstant will promote SplatValue appropriately.
497 SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
498
499 // Bitcast to the type we originally wanted.
500 if (ViaVecTy != ResTy)
501 Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
502
503 return Result;
504 }
505
506 if (DAG.isSplatValue(Op, /*AllowUndefs=*/false))
507 return Op;
508
510 // Use INSERT_VECTOR_ELT operations rather than expand to stores.
511 // The resulting code is the same length as the expansion, but it doesn't
512 // use memory operations.
513 EVT ResTy = Node->getValueType(0);
514
515 assert(ResTy.isVector());
516
517 unsigned NumElts = ResTy.getVectorNumElements();
518 SDValue Vector = DAG.getUNDEF(ResTy);
519 for (unsigned i = 0; i < NumElts; ++i) {
521 Node->getOperand(i),
522 DAG.getConstant(i, DL, Subtarget.getGRLenVT()));
523 }
524 return Vector;
525 }
526
527 return SDValue();
528}
529
531LoongArchTargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,
532 SelectionDAG &DAG) const {
533 EVT VecTy = Op->getOperand(0)->getValueType(0);
534 SDValue Idx = Op->getOperand(1);
535 EVT EltTy = VecTy.getVectorElementType();
536 unsigned NumElts = VecTy.getVectorNumElements();
537
538 if (isa<ConstantSDNode>(Idx) &&
539 (EltTy == MVT::i32 || EltTy == MVT::i64 || EltTy == MVT::f32 ||
540 EltTy == MVT::f64 || Idx->getAsZExtVal() < NumElts / 2))
541 return Op;
542
543 return SDValue();
544}
545
547LoongArchTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
548 SelectionDAG &DAG) const {
549 if (isa<ConstantSDNode>(Op->getOperand(2)))
550 return Op;
551 return SDValue();
552}
553
554SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
555 SelectionDAG &DAG) const {
556 SDLoc DL(Op);
557 SyncScope::ID FenceSSID =
558 static_cast<SyncScope::ID>(Op.getConstantOperandVal(2));
559
560 // singlethread fences only synchronize with signal handlers on the same
561 // thread and thus only need to preserve instruction order, not actually
562 // enforce memory ordering.
563 if (FenceSSID == SyncScope::SingleThread)
564 // MEMBARRIER is a compiler barrier; it codegens to a no-op.
565 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));
566
567 return Op;
568}
569
570SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
571 SelectionDAG &DAG) const {
572
573 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
574 DAG.getContext()->emitError(
575 "On LA64, only 64-bit registers can be written.");
576 return Op.getOperand(0);
577 }
578
579 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
580 DAG.getContext()->emitError(
581 "On LA32, only 32-bit registers can be written.");
582 return Op.getOperand(0);
583 }
584
585 return Op;
586}
587
588SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
589 SelectionDAG &DAG) const {
590 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
591 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
592 "be a constant integer");
593 return SDValue();
594 }
595
598 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
599 EVT VT = Op.getValueType();
600 SDLoc DL(Op);
601 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
602 unsigned Depth = Op.getConstantOperandVal(0);
603 int GRLenInBytes = Subtarget.getGRLen() / 8;
604
605 while (Depth--) {
606 int Offset = -(GRLenInBytes * 2);
607 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
609 FrameAddr =
610 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
611 }
612 return FrameAddr;
613}
614
615SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
616 SelectionDAG &DAG) const {
618 return SDValue();
619
620 // Currently only support lowering return address for current frame.
621 if (Op.getConstantOperandVal(0) != 0) {
622 DAG.getContext()->emitError(
623 "return address can only be determined for the current frame");
624 return SDValue();
625 }
626
629 MVT GRLenVT = Subtarget.getGRLenVT();
630
631 // Return the value of the return address register, marking it an implicit
632 // live-in.
633 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
634 getRegClassFor(GRLenVT));
635 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
636}
637
638SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
639 SelectionDAG &DAG) const {
641 auto Size = Subtarget.getGRLen() / 8;
642 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
643 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
644}
645
646SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
647 SelectionDAG &DAG) const {
649 auto *FuncInfo = MF.getInfo<LoongArchMachineFunctionInfo>();
650
651 SDLoc DL(Op);
652 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
654
655 // vastart just stores the address of the VarArgsFrameIndex slot into the
656 // memory location argument.
657 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
658 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
660}
661
662SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
663 SelectionDAG &DAG) const {
664 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
665 !Subtarget.hasBasicD() && "unexpected target features");
666
667 SDLoc DL(Op);
668 SDValue Op0 = Op.getOperand(0);
669 if (Op0->getOpcode() == ISD::AND) {
670 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
671 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
672 return Op;
673 }
674
675 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
676 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
677 Op0.getConstantOperandVal(2) == UINT64_C(0))
678 return Op;
679
680 if (Op0.getOpcode() == ISD::AssertZext &&
681 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
682 return Op;
683
684 EVT OpVT = Op0.getValueType();
685 EVT RetVT = Op.getValueType();
686 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
687 MakeLibCallOptions CallOptions;
688 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
689 SDValue Chain = SDValue();
691 std::tie(Result, Chain) =
692 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
693 return Result;
694}
695
696SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
697 SelectionDAG &DAG) const {
698 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
699 !Subtarget.hasBasicD() && "unexpected target features");
700
701 SDLoc DL(Op);
702 SDValue Op0 = Op.getOperand(0);
703
704 if ((Op0.getOpcode() == ISD::AssertSext ||
706 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
707 return Op;
708
709 EVT OpVT = Op0.getValueType();
710 EVT RetVT = Op.getValueType();
711 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
712 MakeLibCallOptions CallOptions;
713 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
714 SDValue Chain = SDValue();
716 std::tie(Result, Chain) =
717 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
718 return Result;
719}
720
721SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
722 SelectionDAG &DAG) const {
723
724 SDLoc DL(Op);
725 SDValue Op0 = Op.getOperand(0);
726
727 if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
728 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
729 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
730 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
731 }
732 return Op;
733}
734
735SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
736 SelectionDAG &DAG) const {
737
738 SDLoc DL(Op);
739
740 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
741 !Subtarget.hasBasicD()) {
742 SDValue Dst =
743 DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
744 return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
745 }
746
747 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
748 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
749 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
750}
751
753 SelectionDAG &DAG, unsigned Flags) {
754 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
755}
756
758 SelectionDAG &DAG, unsigned Flags) {
759 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
760 Flags);
761}
762
764 SelectionDAG &DAG, unsigned Flags) {
765 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
766 N->getOffset(), Flags);
767}
768
770 SelectionDAG &DAG, unsigned Flags) {
771 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
772}
773
774template <class NodeTy>
775SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
777 bool IsLocal) const {
778 SDLoc DL(N);
779 EVT Ty = getPointerTy(DAG.getDataLayout());
780 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
782
783 switch (M) {
784 default:
785 report_fatal_error("Unsupported code model");
786
787 case CodeModel::Large: {
788 assert(Subtarget.is64Bit() && "Large code model requires LA64");
789
790 // This is not actually used, but is necessary for successfully matching
791 // the PseudoLA_*_LARGE nodes.
792 SDValue Tmp = DAG.getConstant(0, DL, Ty);
793 if (IsLocal) {
794 // This generates the pattern (PseudoLA_PCREL_LARGE tmp sym), that
795 // eventually becomes the desired 5-insn code sequence.
796 Load = SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL_LARGE, DL, Ty,
797 Tmp, Addr),
798 0);
799 } else {
800 // This generates the pattern (PseudoLA_GOT_LARGE tmp sym), that
801 // eventually becomes the desired 5-insn code sequence.
802 Load = SDValue(
803 DAG.getMachineNode(LoongArch::PseudoLA_GOT_LARGE, DL, Ty, Tmp, Addr),
804 0);
805 }
806 break;
807 }
808
809 case CodeModel::Small:
811 if (IsLocal) {
812 // This generates the pattern (PseudoLA_PCREL sym), which expands to
813 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
814 Load = SDValue(
815 DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), 0);
816 } else {
817 // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
818 // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
819 Load =
820 SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
821 }
822 }
823
824 if (!IsLocal) {
825 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
831 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
832 DAG.setNodeMemRefs(cast<MachineSDNode>(Load.getNode()), {MemOp});
833 }
834
835 return Load;
836}
837
838SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
839 SelectionDAG &DAG) const {
840 return getAddr(cast<BlockAddressSDNode>(Op), DAG,
841 DAG.getTarget().getCodeModel());
842}
843
844SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
845 SelectionDAG &DAG) const {
846 return getAddr(cast<JumpTableSDNode>(Op), DAG,
847 DAG.getTarget().getCodeModel());
848}
849
850SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
851 SelectionDAG &DAG) const {
852 return getAddr(cast<ConstantPoolSDNode>(Op), DAG,
853 DAG.getTarget().getCodeModel());
854}
855
856SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
857 SelectionDAG &DAG) const {
858 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
859 assert(N->getOffset() == 0 && "unexpected offset in global node");
860 auto CM = DAG.getTarget().getCodeModel();
861 const GlobalValue *GV = N->getGlobal();
862
863 if (GV->isDSOLocal() && isa<GlobalVariable>(GV)) {
864 if (auto GCM = dyn_cast<GlobalVariable>(GV)->getCodeModel())
865 CM = *GCM;
866 }
867
868 return getAddr(N, DAG, CM, GV->isDSOLocal());
869}
870
871SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
872 SelectionDAG &DAG,
873 unsigned Opc, bool UseGOT,
874 bool Large) const {
875 SDLoc DL(N);
876 EVT Ty = getPointerTy(DAG.getDataLayout());
877 MVT GRLenVT = Subtarget.getGRLenVT();
878
879 // This is not actually used, but is necessary for successfully matching the
880 // PseudoLA_*_LARGE nodes.
881 SDValue Tmp = DAG.getConstant(0, DL, Ty);
882 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
884 ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
885 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
886 if (UseGOT) {
887 // Mark the load instruction as invariant to enable hoisting in MachineLICM.
893 LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8));
894 DAG.setNodeMemRefs(cast<MachineSDNode>(Offset.getNode()), {MemOp});
895 }
896
897 // Add the thread pointer.
898 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
899 DAG.getRegister(LoongArch::R2, GRLenVT));
900}
901
902SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
903 SelectionDAG &DAG,
904 unsigned Opc,
905 bool Large) const {
906 SDLoc DL(N);
907 EVT Ty = getPointerTy(DAG.getDataLayout());
908 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
909
910 // This is not actually used, but is necessary for successfully matching the
911 // PseudoLA_*_LARGE nodes.
912 SDValue Tmp = DAG.getConstant(0, DL, Ty);
913
914 // Use a PC-relative addressing mode to access the dynamic GOT address.
915 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
916 SDValue Load = Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
917 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
918
919 // Prepare argument list to generate call.
921 ArgListEntry Entry;
922 Entry.Node = Load;
923 Entry.Ty = CallTy;
924 Args.push_back(Entry);
925
926 // Setup call to __tls_get_addr.
928 CLI.setDebugLoc(DL)
929 .setChain(DAG.getEntryNode())
930 .setLibCallee(CallingConv::C, CallTy,
931 DAG.getExternalSymbol("__tls_get_addr", Ty),
932 std::move(Args));
933
934 return LowerCallTo(CLI).first;
935}
936
937SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
938 SelectionDAG &DAG, unsigned Opc,
939 bool Large) const {
940 SDLoc DL(N);
941 EVT Ty = getPointerTy(DAG.getDataLayout());
942 const GlobalValue *GV = N->getGlobal();
943
944 // This is not actually used, but is necessary for successfully matching the
945 // PseudoLA_*_LARGE nodes.
946 SDValue Tmp = DAG.getConstant(0, DL, Ty);
947
948 // Use a PC-relative addressing mode to access the global dynamic GOT address.
949 // This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
950 SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
951 return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
952 : SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
953}
954
956LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
957 SelectionDAG &DAG) const {
960 report_fatal_error("In GHC calling convention TLS is not supported");
961
963 assert((!Large || Subtarget.is64Bit()) && "Large code model requires LA64");
964
965 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
966 assert(N->getOffset() == 0 && "unexpected offset in global node");
967
968 if (DAG.getTarget().useEmulatedTLS())
969 report_fatal_error("the emulated TLS is prohibited",
970 /*GenCrashDiag=*/false);
971
972 bool IsDesc = DAG.getTarget().useTLSDESC();
973
974 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
976 // In this model, application code calls the dynamic linker function
977 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
978 // runtime.
979 if (!IsDesc)
980 return getDynamicTLSAddr(N, DAG,
981 Large ? LoongArch::PseudoLA_TLS_GD_LARGE
982 : LoongArch::PseudoLA_TLS_GD,
983 Large);
984 break;
986 // Same as GeneralDynamic, except for assembly modifiers and relocation
987 // records.
988 if (!IsDesc)
989 return getDynamicTLSAddr(N, DAG,
990 Large ? LoongArch::PseudoLA_TLS_LD_LARGE
991 : LoongArch::PseudoLA_TLS_LD,
992 Large);
993 break;
995 // This model uses the GOT to resolve TLS offsets.
996 return getStaticTLSAddr(N, DAG,
997 Large ? LoongArch::PseudoLA_TLS_IE_LARGE
998 : LoongArch::PseudoLA_TLS_IE,
999 /*UseGOT=*/true, Large);
1001 // This model is used when static linking as the TLS offsets are resolved
1002 // during program linking.
1003 //
1004 // This node doesn't need an extra argument for the large code model.
1005 return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE,
1006 /*UseGOT=*/false);
1007 }
1008
1009 return getTLSDescAddr(N, DAG,
1010 Large ? LoongArch::PseudoLA_TLS_DESC_PC_LARGE
1011 : LoongArch::PseudoLA_TLS_DESC_PC,
1012 Large);
1013}
1014
1015template <unsigned N>
1017 SelectionDAG &DAG, bool IsSigned = false) {
1018 auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
1019 // Check the ImmArg.
1020 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
1021 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
1022 DAG.getContext()->emitError(Op->getOperationName(0) +
1023 ": argument out of range.");
1024 return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType());
1025 }
1026 return SDValue();
1027}
1028
1029SDValue
1030LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
1031 SelectionDAG &DAG) const {
1032 SDLoc DL(Op);
1033 switch (Op.getConstantOperandVal(0)) {
1034 default:
1035 return SDValue(); // Don't custom lower most intrinsics.
1036 case Intrinsic::thread_pointer: {
1037 EVT PtrVT = getPointerTy(DAG.getDataLayout());
1038 return DAG.getRegister(LoongArch::R2, PtrVT);
1039 }
1040 case Intrinsic::loongarch_lsx_vpickve2gr_d:
1041 case Intrinsic::loongarch_lsx_vpickve2gr_du:
1042 case Intrinsic::loongarch_lsx_vreplvei_d:
1043 case Intrinsic::loongarch_lasx_xvrepl128vei_d:
1044 return checkIntrinsicImmArg<1>(Op, 2, DAG);
1045 case Intrinsic::loongarch_lsx_vreplvei_w:
1046 case Intrinsic::loongarch_lasx_xvrepl128vei_w:
1047 case Intrinsic::loongarch_lasx_xvpickve2gr_d:
1048 case Intrinsic::loongarch_lasx_xvpickve2gr_du:
1049 case Intrinsic::loongarch_lasx_xvpickve_d:
1050 case Intrinsic::loongarch_lasx_xvpickve_d_f:
1051 return checkIntrinsicImmArg<2>(Op, 2, DAG);
1052 case Intrinsic::loongarch_lasx_xvinsve0_d:
1053 return checkIntrinsicImmArg<2>(Op, 3, DAG);
1054 case Intrinsic::loongarch_lsx_vsat_b:
1055 case Intrinsic::loongarch_lsx_vsat_bu:
1056 case Intrinsic::loongarch_lsx_vrotri_b:
1057 case Intrinsic::loongarch_lsx_vsllwil_h_b:
1058 case Intrinsic::loongarch_lsx_vsllwil_hu_bu:
1059 case Intrinsic::loongarch_lsx_vsrlri_b:
1060 case Intrinsic::loongarch_lsx_vsrari_b:
1061 case Intrinsic::loongarch_lsx_vreplvei_h:
1062 case Intrinsic::loongarch_lasx_xvsat_b:
1063 case Intrinsic::loongarch_lasx_xvsat_bu:
1064 case Intrinsic::loongarch_lasx_xvrotri_b:
1065 case Intrinsic::loongarch_lasx_xvsllwil_h_b:
1066 case Intrinsic::loongarch_lasx_xvsllwil_hu_bu:
1067 case Intrinsic::loongarch_lasx_xvsrlri_b:
1068 case Intrinsic::loongarch_lasx_xvsrari_b:
1069 case Intrinsic::loongarch_lasx_xvrepl128vei_h:
1070 case Intrinsic::loongarch_lasx_xvpickve_w:
1071 case Intrinsic::loongarch_lasx_xvpickve_w_f:
1072 return checkIntrinsicImmArg<3>(Op, 2, DAG);
1073 case Intrinsic::loongarch_lasx_xvinsve0_w:
1074 return checkIntrinsicImmArg<3>(Op, 3, DAG);
1075 case Intrinsic::loongarch_lsx_vsat_h:
1076 case Intrinsic::loongarch_lsx_vsat_hu:
1077 case Intrinsic::loongarch_lsx_vrotri_h:
1078 case Intrinsic::loongarch_lsx_vsllwil_w_h:
1079 case Intrinsic::loongarch_lsx_vsllwil_wu_hu:
1080 case Intrinsic::loongarch_lsx_vsrlri_h:
1081 case Intrinsic::loongarch_lsx_vsrari_h:
1082 case Intrinsic::loongarch_lsx_vreplvei_b:
1083 case Intrinsic::loongarch_lasx_xvsat_h:
1084 case Intrinsic::loongarch_lasx_xvsat_hu:
1085 case Intrinsic::loongarch_lasx_xvrotri_h:
1086 case Intrinsic::loongarch_lasx_xvsllwil_w_h:
1087 case Intrinsic::loongarch_lasx_xvsllwil_wu_hu:
1088 case Intrinsic::loongarch_lasx_xvsrlri_h:
1089 case Intrinsic::loongarch_lasx_xvsrari_h:
1090 case Intrinsic::loongarch_lasx_xvrepl128vei_b:
1091 return checkIntrinsicImmArg<4>(Op, 2, DAG);
1092 case Intrinsic::loongarch_lsx_vsrlni_b_h:
1093 case Intrinsic::loongarch_lsx_vsrani_b_h:
1094 case Intrinsic::loongarch_lsx_vsrlrni_b_h:
1095 case Intrinsic::loongarch_lsx_vsrarni_b_h:
1096 case Intrinsic::loongarch_lsx_vssrlni_b_h:
1097 case Intrinsic::loongarch_lsx_vssrani_b_h:
1098 case Intrinsic::loongarch_lsx_vssrlni_bu_h:
1099 case Intrinsic::loongarch_lsx_vssrani_bu_h:
1100 case Intrinsic::loongarch_lsx_vssrlrni_b_h:
1101 case Intrinsic::loongarch_lsx_vssrarni_b_h:
1102 case Intrinsic::loongarch_lsx_vssrlrni_bu_h:
1103 case Intrinsic::loongarch_lsx_vssrarni_bu_h:
1104 case Intrinsic::loongarch_lasx_xvsrlni_b_h:
1105 case Intrinsic::loongarch_lasx_xvsrani_b_h:
1106 case Intrinsic::loongarch_lasx_xvsrlrni_b_h:
1107 case Intrinsic::loongarch_lasx_xvsrarni_b_h:
1108 case Intrinsic::loongarch_lasx_xvssrlni_b_h:
1109 case Intrinsic::loongarch_lasx_xvssrani_b_h:
1110 case Intrinsic::loongarch_lasx_xvssrlni_bu_h:
1111 case Intrinsic::loongarch_lasx_xvssrani_bu_h:
1112 case Intrinsic::loongarch_lasx_xvssrlrni_b_h:
1113 case Intrinsic::loongarch_lasx_xvssrarni_b_h:
1114 case Intrinsic::loongarch_lasx_xvssrlrni_bu_h:
1115 case Intrinsic::loongarch_lasx_xvssrarni_bu_h:
1116 return checkIntrinsicImmArg<4>(Op, 3, DAG);
1117 case Intrinsic::loongarch_lsx_vsat_w:
1118 case Intrinsic::loongarch_lsx_vsat_wu:
1119 case Intrinsic::loongarch_lsx_vrotri_w:
1120 case Intrinsic::loongarch_lsx_vsllwil_d_w:
1121 case Intrinsic::loongarch_lsx_vsllwil_du_wu:
1122 case Intrinsic::loongarch_lsx_vsrlri_w:
1123 case Intrinsic::loongarch_lsx_vsrari_w:
1124 case Intrinsic::loongarch_lsx_vslei_bu:
1125 case Intrinsic::loongarch_lsx_vslei_hu:
1126 case Intrinsic::loongarch_lsx_vslei_wu:
1127 case Intrinsic::loongarch_lsx_vslei_du:
1128 case Intrinsic::loongarch_lsx_vslti_bu:
1129 case Intrinsic::loongarch_lsx_vslti_hu:
1130 case Intrinsic::loongarch_lsx_vslti_wu:
1131 case Intrinsic::loongarch_lsx_vslti_du:
1132 case Intrinsic::loongarch_lsx_vbsll_v:
1133 case Intrinsic::loongarch_lsx_vbsrl_v:
1134 case Intrinsic::loongarch_lasx_xvsat_w:
1135 case Intrinsic::loongarch_lasx_xvsat_wu:
1136 case Intrinsic::loongarch_lasx_xvrotri_w:
1137 case Intrinsic::loongarch_lasx_xvsllwil_d_w:
1138 case Intrinsic::loongarch_lasx_xvsllwil_du_wu:
1139 case Intrinsic::loongarch_lasx_xvsrlri_w:
1140 case Intrinsic::loongarch_lasx_xvsrari_w:
1141 case Intrinsic::loongarch_lasx_xvslei_bu:
1142 case Intrinsic::loongarch_lasx_xvslei_hu:
1143 case Intrinsic::loongarch_lasx_xvslei_wu:
1144 case Intrinsic::loongarch_lasx_xvslei_du:
1145 case Intrinsic::loongarch_lasx_xvslti_bu:
1146 case Intrinsic::loongarch_lasx_xvslti_hu:
1147 case Intrinsic::loongarch_lasx_xvslti_wu:
1148 case Intrinsic::loongarch_lasx_xvslti_du:
1149 case Intrinsic::loongarch_lasx_xvbsll_v:
1150 case Intrinsic::loongarch_lasx_xvbsrl_v:
1151 return checkIntrinsicImmArg<5>(Op, 2, DAG);
1152 case Intrinsic::loongarch_lsx_vseqi_b:
1153 case Intrinsic::loongarch_lsx_vseqi_h:
1154 case Intrinsic::loongarch_lsx_vseqi_w:
1155 case Intrinsic::loongarch_lsx_vseqi_d:
1156 case Intrinsic::loongarch_lsx_vslei_b:
1157 case Intrinsic::loongarch_lsx_vslei_h:
1158 case Intrinsic::loongarch_lsx_vslei_w:
1159 case Intrinsic::loongarch_lsx_vslei_d:
1160 case Intrinsic::loongarch_lsx_vslti_b:
1161 case Intrinsic::loongarch_lsx_vslti_h:
1162 case Intrinsic::loongarch_lsx_vslti_w:
1163 case Intrinsic::loongarch_lsx_vslti_d:
1164 case Intrinsic::loongarch_lasx_xvseqi_b:
1165 case Intrinsic::loongarch_lasx_xvseqi_h:
1166 case Intrinsic::loongarch_lasx_xvseqi_w:
1167 case Intrinsic::loongarch_lasx_xvseqi_d:
1168 case Intrinsic::loongarch_lasx_xvslei_b:
1169 case Intrinsic::loongarch_lasx_xvslei_h:
1170 case Intrinsic::loongarch_lasx_xvslei_w:
1171 case Intrinsic::loongarch_lasx_xvslei_d:
1172 case Intrinsic::loongarch_lasx_xvslti_b:
1173 case Intrinsic::loongarch_lasx_xvslti_h:
1174 case Intrinsic::loongarch_lasx_xvslti_w:
1175 case Intrinsic::loongarch_lasx_xvslti_d:
1176 return checkIntrinsicImmArg<5>(Op, 2, DAG, /*IsSigned=*/true);
1177 case Intrinsic::loongarch_lsx_vsrlni_h_w:
1178 case Intrinsic::loongarch_lsx_vsrani_h_w:
1179 case Intrinsic::loongarch_lsx_vsrlrni_h_w:
1180 case Intrinsic::loongarch_lsx_vsrarni_h_w:
1181 case Intrinsic::loongarch_lsx_vssrlni_h_w:
1182 case Intrinsic::loongarch_lsx_vssrani_h_w:
1183 case Intrinsic::loongarch_lsx_vssrlni_hu_w:
1184 case Intrinsic::loongarch_lsx_vssrani_hu_w:
1185 case Intrinsic::loongarch_lsx_vssrlrni_h_w:
1186 case Intrinsic::loongarch_lsx_vssrarni_h_w:
1187 case Intrinsic::loongarch_lsx_vssrlrni_hu_w:
1188 case Intrinsic::loongarch_lsx_vssrarni_hu_w:
1189 case Intrinsic::loongarch_lsx_vfrstpi_b:
1190 case Intrinsic::loongarch_lsx_vfrstpi_h:
1191 case Intrinsic::loongarch_lasx_xvsrlni_h_w:
1192 case Intrinsic::loongarch_lasx_xvsrani_h_w:
1193 case Intrinsic::loongarch_lasx_xvsrlrni_h_w:
1194 case Intrinsic::loongarch_lasx_xvsrarni_h_w:
1195 case Intrinsic::loongarch_lasx_xvssrlni_h_w:
1196 case Intrinsic::loongarch_lasx_xvssrani_h_w:
1197 case Intrinsic::loongarch_lasx_xvssrlni_hu_w:
1198 case Intrinsic::loongarch_lasx_xvssrani_hu_w:
1199 case Intrinsic::loongarch_lasx_xvssrlrni_h_w:
1200 case Intrinsic::loongarch_lasx_xvssrarni_h_w:
1201 case Intrinsic::loongarch_lasx_xvssrlrni_hu_w:
1202 case Intrinsic::loongarch_lasx_xvssrarni_hu_w:
1203 case Intrinsic::loongarch_lasx_xvfrstpi_b:
1204 case Intrinsic::loongarch_lasx_xvfrstpi_h:
1205 return checkIntrinsicImmArg<5>(Op, 3, DAG);
1206 case Intrinsic::loongarch_lsx_vsat_d:
1207 case Intrinsic::loongarch_lsx_vsat_du:
1208 case Intrinsic::loongarch_lsx_vrotri_d:
1209 case Intrinsic::loongarch_lsx_vsrlri_d:
1210 case Intrinsic::loongarch_lsx_vsrari_d:
1211 case Intrinsic::loongarch_lasx_xvsat_d:
1212 case Intrinsic::loongarch_lasx_xvsat_du:
1213 case Intrinsic::loongarch_lasx_xvrotri_d:
1214 case Intrinsic::loongarch_lasx_xvsrlri_d:
1215 case Intrinsic::loongarch_lasx_xvsrari_d:
1216 return checkIntrinsicImmArg<6>(Op, 2, DAG);
1217 case Intrinsic::loongarch_lsx_vsrlni_w_d:
1218 case Intrinsic::loongarch_lsx_vsrani_w_d:
1219 case Intrinsic::loongarch_lsx_vsrlrni_w_d:
1220 case Intrinsic::loongarch_lsx_vsrarni_w_d:
1221 case Intrinsic::loongarch_lsx_vssrlni_w_d:
1222 case Intrinsic::loongarch_lsx_vssrani_w_d:
1223 case Intrinsic::loongarch_lsx_vssrlni_wu_d:
1224 case Intrinsic::loongarch_lsx_vssrani_wu_d:
1225 case Intrinsic::loongarch_lsx_vssrlrni_w_d:
1226 case Intrinsic::loongarch_lsx_vssrarni_w_d:
1227 case Intrinsic::loongarch_lsx_vssrlrni_wu_d:
1228 case Intrinsic::loongarch_lsx_vssrarni_wu_d:
1229 case Intrinsic::loongarch_lasx_xvsrlni_w_d:
1230 case Intrinsic::loongarch_lasx_xvsrani_w_d:
1231 case Intrinsic::loongarch_lasx_xvsrlrni_w_d:
1232 case Intrinsic::loongarch_lasx_xvsrarni_w_d:
1233 case Intrinsic::loongarch_lasx_xvssrlni_w_d:
1234 case Intrinsic::loongarch_lasx_xvssrani_w_d:
1235 case Intrinsic::loongarch_lasx_xvssrlni_wu_d:
1236 case Intrinsic::loongarch_lasx_xvssrani_wu_d:
1237 case Intrinsic::loongarch_lasx_xvssrlrni_w_d:
1238 case Intrinsic::loongarch_lasx_xvssrarni_w_d:
1239 case Intrinsic::loongarch_lasx_xvssrlrni_wu_d:
1240 case Intrinsic::loongarch_lasx_xvssrarni_wu_d:
1241 return checkIntrinsicImmArg<6>(Op, 3, DAG);
1242 case Intrinsic::loongarch_lsx_vsrlni_d_q:
1243 case Intrinsic::loongarch_lsx_vsrani_d_q:
1244 case Intrinsic::loongarch_lsx_vsrlrni_d_q:
1245 case Intrinsic::loongarch_lsx_vsrarni_d_q:
1246 case Intrinsic::loongarch_lsx_vssrlni_d_q:
1247 case Intrinsic::loongarch_lsx_vssrani_d_q:
1248 case Intrinsic::loongarch_lsx_vssrlni_du_q:
1249 case Intrinsic::loongarch_lsx_vssrani_du_q:
1250 case Intrinsic::loongarch_lsx_vssrlrni_d_q:
1251 case Intrinsic::loongarch_lsx_vssrarni_d_q:
1252 case Intrinsic::loongarch_lsx_vssrlrni_du_q:
1253 case Intrinsic::loongarch_lsx_vssrarni_du_q:
1254 case Intrinsic::loongarch_lasx_xvsrlni_d_q:
1255 case Intrinsic::loongarch_lasx_xvsrani_d_q:
1256 case Intrinsic::loongarch_lasx_xvsrlrni_d_q:
1257 case Intrinsic::loongarch_lasx_xvsrarni_d_q:
1258 case Intrinsic::loongarch_lasx_xvssrlni_d_q:
1259 case Intrinsic::loongarch_lasx_xvssrani_d_q:
1260 case Intrinsic::loongarch_lasx_xvssrlni_du_q:
1261 case Intrinsic::loongarch_lasx_xvssrani_du_q:
1262 case Intrinsic::loongarch_lasx_xvssrlrni_d_q:
1263 case Intrinsic::loongarch_lasx_xvssrarni_d_q:
1264 case Intrinsic::loongarch_lasx_xvssrlrni_du_q:
1265 case Intrinsic::loongarch_lasx_xvssrarni_du_q:
1266 return checkIntrinsicImmArg<7>(Op, 3, DAG);
1267 case Intrinsic::loongarch_lsx_vnori_b:
1268 case Intrinsic::loongarch_lsx_vshuf4i_b:
1269 case Intrinsic::loongarch_lsx_vshuf4i_h:
1270 case Intrinsic::loongarch_lsx_vshuf4i_w:
1271 case Intrinsic::loongarch_lasx_xvnori_b:
1272 case Intrinsic::loongarch_lasx_xvshuf4i_b:
1273 case Intrinsic::loongarch_lasx_xvshuf4i_h:
1274 case Intrinsic::loongarch_lasx_xvshuf4i_w:
1275 case Intrinsic::loongarch_lasx_xvpermi_d:
1276 return checkIntrinsicImmArg<8>(Op, 2, DAG);
1277 case Intrinsic::loongarch_lsx_vshuf4i_d:
1278 case Intrinsic::loongarch_lsx_vpermi_w:
1279 case Intrinsic::loongarch_lsx_vbitseli_b:
1280 case Intrinsic::loongarch_lsx_vextrins_b:
1281 case Intrinsic::loongarch_lsx_vextrins_h:
1282 case Intrinsic::loongarch_lsx_vextrins_w:
1283 case Intrinsic::loongarch_lsx_vextrins_d:
1284 case Intrinsic::loongarch_lasx_xvshuf4i_d:
1285 case Intrinsic::loongarch_lasx_xvpermi_w:
1286 case Intrinsic::loongarch_lasx_xvpermi_q:
1287 case Intrinsic::loongarch_lasx_xvbitseli_b:
1288 case Intrinsic::loongarch_lasx_xvextrins_b:
1289 case Intrinsic::loongarch_lasx_xvextrins_h:
1290 case Intrinsic::loongarch_lasx_xvextrins_w:
1291 case Intrinsic::loongarch_lasx_xvextrins_d:
1292 return checkIntrinsicImmArg<8>(Op, 3, DAG);
1293 case Intrinsic::loongarch_lsx_vrepli_b:
1294 case Intrinsic::loongarch_lsx_vrepli_h:
1295 case Intrinsic::loongarch_lsx_vrepli_w:
1296 case Intrinsic::loongarch_lsx_vrepli_d:
1297 case Intrinsic::loongarch_lasx_xvrepli_b:
1298 case Intrinsic::loongarch_lasx_xvrepli_h:
1299 case Intrinsic::loongarch_lasx_xvrepli_w:
1300 case Intrinsic::loongarch_lasx_xvrepli_d:
1301 return checkIntrinsicImmArg<10>(Op, 1, DAG, /*IsSigned=*/true);
1302 case Intrinsic::loongarch_lsx_vldi:
1303 case Intrinsic::loongarch_lasx_xvldi:
1304 return checkIntrinsicImmArg<13>(Op, 1, DAG, /*IsSigned=*/true);
1305 }
1306}
1307
1308// Helper function that emits error message for intrinsics with chain and return
1309// merge values of a UNDEF and the chain.
1311 StringRef ErrorMsg,
1312 SelectionDAG &DAG) {
1313 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
1314 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
1315 SDLoc(Op));
1316}
1317
1318SDValue
1319LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
1320 SelectionDAG &DAG) const {
1321 SDLoc DL(Op);
1322 MVT GRLenVT = Subtarget.getGRLenVT();
1323 EVT VT = Op.getValueType();
1324 SDValue Chain = Op.getOperand(0);
1325 const StringRef ErrorMsgOOR = "argument out of range";
1326 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
1327 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1328
1329 switch (Op.getConstantOperandVal(1)) {
1330 default:
1331 return Op;
1332 case Intrinsic::loongarch_crc_w_b_w:
1333 case Intrinsic::loongarch_crc_w_h_w:
1334 case Intrinsic::loongarch_crc_w_w_w:
1335 case Intrinsic::loongarch_crc_w_d_w:
1336 case Intrinsic::loongarch_crcc_w_b_w:
1337 case Intrinsic::loongarch_crcc_w_h_w:
1338 case Intrinsic::loongarch_crcc_w_w_w:
1339 case Intrinsic::loongarch_crcc_w_d_w:
1340 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqLA64, DAG);
1341 case Intrinsic::loongarch_csrrd_w:
1342 case Intrinsic::loongarch_csrrd_d: {
1343 unsigned Imm = Op.getConstantOperandVal(2);
1344 return !isUInt<14>(Imm)
1345 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1346 : DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
1347 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1348 }
1349 case Intrinsic::loongarch_csrwr_w:
1350 case Intrinsic::loongarch_csrwr_d: {
1351 unsigned Imm = Op.getConstantOperandVal(3);
1352 return !isUInt<14>(Imm)
1353 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1354 : DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
1355 {Chain, Op.getOperand(2),
1356 DAG.getConstant(Imm, DL, GRLenVT)});
1357 }
1358 case Intrinsic::loongarch_csrxchg_w:
1359 case Intrinsic::loongarch_csrxchg_d: {
1360 unsigned Imm = Op.getConstantOperandVal(4);
1361 return !isUInt<14>(Imm)
1362 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1363 : DAG.getNode(LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
1364 {Chain, Op.getOperand(2), Op.getOperand(3),
1365 DAG.getConstant(Imm, DL, GRLenVT)});
1366 }
1367 case Intrinsic::loongarch_iocsrrd_d: {
1368 return DAG.getNode(
1369 LoongArchISD::IOCSRRD_D, DL, {GRLenVT, MVT::Other},
1370 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))});
1371 }
1372#define IOCSRRD_CASE(NAME, NODE) \
1373 case Intrinsic::loongarch_##NAME: { \
1374 return DAG.getNode(LoongArchISD::NODE, DL, {GRLenVT, MVT::Other}, \
1375 {Chain, Op.getOperand(2)}); \
1376 }
1377 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1378 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1379 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1380#undef IOCSRRD_CASE
1381 case Intrinsic::loongarch_cpucfg: {
1382 return DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
1383 {Chain, Op.getOperand(2)});
1384 }
1385 case Intrinsic::loongarch_lddir_d: {
1386 unsigned Imm = Op.getConstantOperandVal(3);
1387 return !isUInt<8>(Imm)
1388 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1389 : Op;
1390 }
1391 case Intrinsic::loongarch_movfcsr2gr: {
1392 if (!Subtarget.hasBasicF())
1393 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgReqF, DAG);
1394 unsigned Imm = Op.getConstantOperandVal(2);
1395 return !isUInt<2>(Imm)
1396 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1397 : DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, {VT, MVT::Other},
1398 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
1399 }
1400 case Intrinsic::loongarch_lsx_vld:
1401 case Intrinsic::loongarch_lsx_vldrepl_b:
1402 case Intrinsic::loongarch_lasx_xvld:
1403 case Intrinsic::loongarch_lasx_xvldrepl_b:
1404 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1405 ? emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG)
1406 : SDValue();
1407 case Intrinsic::loongarch_lsx_vldrepl_h:
1408 case Intrinsic::loongarch_lasx_xvldrepl_h:
1409 return !isShiftedInt<11, 1>(
1410 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1412 Op, "argument out of range or not a multiple of 2", DAG)
1413 : SDValue();
1414 case Intrinsic::loongarch_lsx_vldrepl_w:
1415 case Intrinsic::loongarch_lasx_xvldrepl_w:
1416 return !isShiftedInt<10, 2>(
1417 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1419 Op, "argument out of range or not a multiple of 4", DAG)
1420 : SDValue();
1421 case Intrinsic::loongarch_lsx_vldrepl_d:
1422 case Intrinsic::loongarch_lasx_xvldrepl_d:
1423 return !isShiftedInt<9, 3>(
1424 cast<ConstantSDNode>(Op.getOperand(3))->getSExtValue())
1426 Op, "argument out of range or not a multiple of 8", DAG)
1427 : SDValue();
1428 }
1429}
1430
1431// Helper function that emits error message for intrinsics with void return
1432// value and return the chain.
1434 SelectionDAG &DAG) {
1435
1436 DAG.getContext()->emitError(Op->getOperationName(0) + ": " + ErrorMsg + ".");
1437 return Op.getOperand(0);
1438}
1439
1440SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
1441 SelectionDAG &DAG) const {
1442 SDLoc DL(Op);
1443 MVT GRLenVT = Subtarget.getGRLenVT();
1444 SDValue Chain = Op.getOperand(0);
1445 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
1446 SDValue Op2 = Op.getOperand(2);
1447 const StringRef ErrorMsgOOR = "argument out of range";
1448 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
1449 const StringRef ErrorMsgReqLA32 = "requires loongarch32";
1450 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
1451
1452 switch (IntrinsicEnum) {
1453 default:
1454 // TODO: Add more Intrinsics.
1455 return SDValue();
1456 case Intrinsic::loongarch_cacop_d:
1457 case Intrinsic::loongarch_cacop_w: {
1458 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit())
1459 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG);
1460 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit())
1461 return emitIntrinsicErrorMessage(Op, ErrorMsgReqLA32, DAG);
1462 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
1463 unsigned Imm1 = Op2->getAsZExtVal();
1464 int Imm2 = cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue();
1465 if (!isUInt<5>(Imm1) || !isInt<12>(Imm2))
1466 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
1467 return Op;
1468 }
1469 case Intrinsic::loongarch_dbar: {
1470 unsigned Imm = Op2->getAsZExtVal();
1471 return !isUInt<15>(Imm)
1472 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1473 : DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Chain,
1474 DAG.getConstant(Imm, DL, GRLenVT));
1475 }
1476 case Intrinsic::loongarch_ibar: {
1477 unsigned Imm = Op2->getAsZExtVal();
1478 return !isUInt<15>(Imm)
1479 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1480 : DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Chain,
1481 DAG.getConstant(Imm, DL, GRLenVT));
1482 }
1483 case Intrinsic::loongarch_break: {
1484 unsigned Imm = Op2->getAsZExtVal();
1485 return !isUInt<15>(Imm)
1486 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1487 : DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Chain,
1488 DAG.getConstant(Imm, DL, GRLenVT));
1489 }
1490 case Intrinsic::loongarch_movgr2fcsr: {
1491 if (!Subtarget.hasBasicF())
1492 return emitIntrinsicErrorMessage(Op, ErrorMsgReqF, DAG);
1493 unsigned Imm = Op2->getAsZExtVal();
1494 return !isUInt<2>(Imm)
1495 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1496 : DAG.getNode(LoongArchISD::MOVGR2FCSR, DL, MVT::Other, Chain,
1497 DAG.getConstant(Imm, DL, GRLenVT),
1498 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT,
1499 Op.getOperand(3)));
1500 }
1501 case Intrinsic::loongarch_syscall: {
1502 unsigned Imm = Op2->getAsZExtVal();
1503 return !isUInt<15>(Imm)
1504 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1505 : DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Chain,
1506 DAG.getConstant(Imm, DL, GRLenVT));
1507 }
1508#define IOCSRWR_CASE(NAME, NODE) \
1509 case Intrinsic::loongarch_##NAME: { \
1510 SDValue Op3 = Op.getOperand(3); \
1511 return Subtarget.is64Bit() \
1512 ? DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, \
1513 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
1514 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)) \
1515 : DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Chain, Op2, \
1516 Op3); \
1517 }
1518 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
1519 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
1520 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
1521#undef IOCSRWR_CASE
1522 case Intrinsic::loongarch_iocsrwr_d: {
1523 return !Subtarget.is64Bit()
1524 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
1525 : DAG.getNode(LoongArchISD::IOCSRWR_D, DL, MVT::Other, Chain,
1526 Op2,
1527 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
1528 Op.getOperand(3)));
1529 }
1530#define ASRT_LE_GT_CASE(NAME) \
1531 case Intrinsic::loongarch_##NAME: { \
1532 return !Subtarget.is64Bit() \
1533 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG) \
1534 : Op; \
1535 }
1536 ASRT_LE_GT_CASE(asrtle_d)
1537 ASRT_LE_GT_CASE(asrtgt_d)
1538#undef ASRT_LE_GT_CASE
1539 case Intrinsic::loongarch_ldpte_d: {
1540 unsigned Imm = Op.getConstantOperandVal(3);
1541 return !Subtarget.is64Bit()
1542 ? emitIntrinsicErrorMessage(Op, ErrorMsgReqLA64, DAG)
1543 : !isUInt<8>(Imm) ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1544 : Op;
1545 }
1546 case Intrinsic::loongarch_lsx_vst:
1547 case Intrinsic::loongarch_lasx_xvst:
1548 return !isInt<12>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue())
1549 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1550 : SDValue();
1551 case Intrinsic::loongarch_lasx_xvstelm_b:
1552 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1553 !isUInt<5>(Op.getConstantOperandVal(5)))
1554 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1555 : SDValue();
1556 case Intrinsic::loongarch_lsx_vstelm_b:
1557 return (!isInt<8>(cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1558 !isUInt<4>(Op.getConstantOperandVal(5)))
1559 ? emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG)
1560 : SDValue();
1561 case Intrinsic::loongarch_lasx_xvstelm_h:
1562 return (!isShiftedInt<8, 1>(
1563 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1564 !isUInt<4>(Op.getConstantOperandVal(5)))
1566 Op, "argument out of range or not a multiple of 2", DAG)
1567 : SDValue();
1568 case Intrinsic::loongarch_lsx_vstelm_h:
1569 return (!isShiftedInt<8, 1>(
1570 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1571 !isUInt<3>(Op.getConstantOperandVal(5)))
1573 Op, "argument out of range or not a multiple of 2", DAG)
1574 : SDValue();
1575 case Intrinsic::loongarch_lasx_xvstelm_w:
1576 return (!isShiftedInt<8, 2>(
1577 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1578 !isUInt<3>(Op.getConstantOperandVal(5)))
1580 Op, "argument out of range or not a multiple of 4", DAG)
1581 : SDValue();
1582 case Intrinsic::loongarch_lsx_vstelm_w:
1583 return (!isShiftedInt<8, 2>(
1584 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1585 !isUInt<2>(Op.getConstantOperandVal(5)))
1587 Op, "argument out of range or not a multiple of 4", DAG)
1588 : SDValue();
1589 case Intrinsic::loongarch_lasx_xvstelm_d:
1590 return (!isShiftedInt<8, 3>(
1591 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1592 !isUInt<2>(Op.getConstantOperandVal(5)))
1594 Op, "argument out of range or not a multiple of 8", DAG)
1595 : SDValue();
1596 case Intrinsic::loongarch_lsx_vstelm_d:
1597 return (!isShiftedInt<8, 3>(
1598 cast<ConstantSDNode>(Op.getOperand(4))->getSExtValue()) ||
1599 !isUInt<1>(Op.getConstantOperandVal(5)))
1601 Op, "argument out of range or not a multiple of 8", DAG)
1602 : SDValue();
1603 }
1604}
1605
1606SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
1607 SelectionDAG &DAG) const {
1608 SDLoc DL(Op);
1609 SDValue Lo = Op.getOperand(0);
1610 SDValue Hi = Op.getOperand(1);
1611 SDValue Shamt = Op.getOperand(2);
1612 EVT VT = Lo.getValueType();
1613
1614 // if Shamt-GRLen < 0: // Shamt < GRLen
1615 // Lo = Lo << Shamt
1616 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
1617 // else:
1618 // Lo = 0
1619 // Hi = Lo << (Shamt-GRLen)
1620
1621 SDValue Zero = DAG.getConstant(0, DL, VT);
1622 SDValue One = DAG.getConstant(1, DL, VT);
1623 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
1624 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
1625 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
1626 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
1627
1628 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
1629 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
1630 SDValue ShiftRightLo =
1631 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
1632 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
1633 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
1634 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
1635
1636 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
1637
1638 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
1639 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
1640
1641 SDValue Parts[2] = {Lo, Hi};
1642 return DAG.getMergeValues(Parts, DL);
1643}
1644
1645SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
1646 SelectionDAG &DAG,
1647 bool IsSRA) const {
1648 SDLoc DL(Op);
1649 SDValue Lo = Op.getOperand(0);
1650 SDValue Hi = Op.getOperand(1);
1651 SDValue Shamt = Op.getOperand(2);
1652 EVT VT = Lo.getValueType();
1653
1654 // SRA expansion:
1655 // if Shamt-GRLen < 0: // Shamt < GRLen
1656 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
1657 // Hi = Hi >>s Shamt
1658 // else:
1659 // Lo = Hi >>s (Shamt-GRLen);
1660 // Hi = Hi >>s (GRLen-1)
1661 //
1662 // SRL expansion:
1663 // if Shamt-GRLen < 0: // Shamt < GRLen
1664 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
1665 // Hi = Hi >>u Shamt
1666 // else:
1667 // Lo = Hi >>u (Shamt-GRLen);
1668 // Hi = 0;
1669
1670 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
1671
1672 SDValue Zero = DAG.getConstant(0, DL, VT);
1673 SDValue One = DAG.getConstant(1, DL, VT);
1674 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
1675 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
1676 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
1677 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
1678
1679 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
1680 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
1681 SDValue ShiftLeftHi =
1682 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
1683 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
1684 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
1685 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
1686 SDValue HiFalse =
1687 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
1688
1689 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
1690
1691 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
1692 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
1693
1694 SDValue Parts[2] = {Lo, Hi};
1695 return DAG.getMergeValues(Parts, DL);
1696}
1697
1698// Returns the opcode of the target-specific SDNode that implements the 32-bit
1699// form of the given Opcode.
1701 switch (Opcode) {
1702 default:
1703 llvm_unreachable("Unexpected opcode");
1704 case ISD::UDIV:
1705 return LoongArchISD::DIV_WU;
1706 case ISD::UREM:
1707 return LoongArchISD::MOD_WU;
1708 case ISD::SHL:
1709 return LoongArchISD::SLL_W;
1710 case ISD::SRA:
1711 return LoongArchISD::SRA_W;
1712 case ISD::SRL:
1713 return LoongArchISD::SRL_W;
1714 case ISD::ROTL:
1715 case ISD::ROTR:
1716 return LoongArchISD::ROTR_W;
1717 case ISD::CTTZ:
1718 return LoongArchISD::CTZ_W;
1719 case ISD::CTLZ:
1720 return LoongArchISD::CLZ_W;
1721 }
1722}
1723
1724// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
1725// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
1726// otherwise be promoted to i64, making it difficult to select the
1727// SLL_W/.../*W later one because the fact the operation was originally of
1728// type i8/i16/i32 is lost.
1730 unsigned ExtOpc = ISD::ANY_EXTEND) {
1731 SDLoc DL(N);
1732 LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1733 SDValue NewOp0, NewRes;
1734
1735 switch (NumOp) {
1736 default:
1737 llvm_unreachable("Unexpected NumOp");
1738 case 1: {
1739 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1740 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1741 break;
1742 }
1743 case 2: {
1744 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1745 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1746 if (N->getOpcode() == ISD::ROTL) {
1747 SDValue TmpOp = DAG.getConstant(32, DL, MVT::i64);
1748 NewOp1 = DAG.getNode(ISD::SUB, DL, MVT::i64, TmpOp, NewOp1);
1749 }
1750 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1751 break;
1752 }
1753 // TODO:Handle more NumOp.
1754 }
1755
1756 // ReplaceNodeResults requires we maintain the same type for the return
1757 // value.
1758 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
1759}
1760
1761// Converts the given 32-bit operation to a i64 operation with signed extension
1762// semantic to reduce the signed extension instructions.
1764 SDLoc DL(N);
1765 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
1766 SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
1767 SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1);
1768 SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp,
1769 DAG.getValueType(MVT::i32));
1770 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
1771}
1772
1773// Helper function that emits error message for intrinsics with/without chain
1774// and return a UNDEF or and the chain as the results.
1777 StringRef ErrorMsg, bool WithChain = true) {
1778 DAG.getContext()->emitError(N->getOperationName(0) + ": " + ErrorMsg + ".");
1779 Results.push_back(DAG.getUNDEF(N->getValueType(0)));
1780 if (!WithChain)
1781 return;
1782 Results.push_back(N->getOperand(0));
1783}
1784
1785template <unsigned N>
1786static void
1788 SelectionDAG &DAG, const LoongArchSubtarget &Subtarget,
1789 unsigned ResOp) {
1790 const StringRef ErrorMsgOOR = "argument out of range";
1791 unsigned Imm = Node->getConstantOperandVal(2);
1792 if (!isUInt<N>(Imm)) {
1794 /*WithChain=*/false);
1795 return;
1796 }
1797 SDLoc DL(Node);
1798 SDValue Vec = Node->getOperand(1);
1799
1800 SDValue PickElt =
1801 DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec,
1802 DAG.getConstant(Imm, DL, Subtarget.getGRLenVT()),
1804 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, Node->getValueType(0),
1805 PickElt.getValue(0)));
1806}
1807
1810 SelectionDAG &DAG,
1811 const LoongArchSubtarget &Subtarget,
1812 unsigned ResOp) {
1813 SDLoc DL(N);
1814 SDValue Vec = N->getOperand(1);
1815
1816 SDValue CB = DAG.getNode(ResOp, DL, Subtarget.getGRLenVT(), Vec);
1817 Results.push_back(
1818 DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), CB.getValue(0)));
1819}
1820
1821static void
1823 SelectionDAG &DAG,
1824 const LoongArchSubtarget &Subtarget) {
1825 switch (N->getConstantOperandVal(0)) {
1826 default:
1827 llvm_unreachable("Unexpected Intrinsic.");
1828 case Intrinsic::loongarch_lsx_vpickve2gr_b:
1829 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
1831 break;
1832 case Intrinsic::loongarch_lsx_vpickve2gr_h:
1833 case Intrinsic::loongarch_lasx_xvpickve2gr_w:
1834 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
1836 break;
1837 case Intrinsic::loongarch_lsx_vpickve2gr_w:
1838 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
1840 break;
1841 case Intrinsic::loongarch_lsx_vpickve2gr_bu:
1842 replaceVPICKVE2GRResults<4>(N, Results, DAG, Subtarget,
1844 break;
1845 case Intrinsic::loongarch_lsx_vpickve2gr_hu:
1846 case Intrinsic::loongarch_lasx_xvpickve2gr_wu:
1847 replaceVPICKVE2GRResults<3>(N, Results, DAG, Subtarget,
1849 break;
1850 case Intrinsic::loongarch_lsx_vpickve2gr_wu:
1851 replaceVPICKVE2GRResults<2>(N, Results, DAG, Subtarget,
1853 break;
1854 case Intrinsic::loongarch_lsx_bz_b:
1855 case Intrinsic::loongarch_lsx_bz_h:
1856 case Intrinsic::loongarch_lsx_bz_w:
1857 case Intrinsic::loongarch_lsx_bz_d:
1858 case Intrinsic::loongarch_lasx_xbz_b:
1859 case Intrinsic::loongarch_lasx_xbz_h:
1860 case Intrinsic::loongarch_lasx_xbz_w:
1861 case Intrinsic::loongarch_lasx_xbz_d:
1862 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1864 break;
1865 case Intrinsic::loongarch_lsx_bz_v:
1866 case Intrinsic::loongarch_lasx_xbz_v:
1867 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1869 break;
1870 case Intrinsic::loongarch_lsx_bnz_b:
1871 case Intrinsic::loongarch_lsx_bnz_h:
1872 case Intrinsic::loongarch_lsx_bnz_w:
1873 case Intrinsic::loongarch_lsx_bnz_d:
1874 case Intrinsic::loongarch_lasx_xbnz_b:
1875 case Intrinsic::loongarch_lasx_xbnz_h:
1876 case Intrinsic::loongarch_lasx_xbnz_w:
1877 case Intrinsic::loongarch_lasx_xbnz_d:
1878 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1880 break;
1881 case Intrinsic::loongarch_lsx_bnz_v:
1882 case Intrinsic::loongarch_lasx_xbnz_v:
1883 replaceVecCondBranchResults(N, Results, DAG, Subtarget,
1885 break;
1886 }
1887}
1888
1891 SDLoc DL(N);
1892 EVT VT = N->getValueType(0);
1893 switch (N->getOpcode()) {
1894 default:
1895 llvm_unreachable("Don't know how to legalize this operation");
1896 case ISD::ADD:
1897 case ISD::SUB:
1898 assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
1899 "Unexpected custom legalisation");
1900 Results.push_back(customLegalizeToWOpWithSExt(N, DAG));
1901 break;
1902 case ISD::UDIV:
1903 case ISD::UREM:
1904 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1905 "Unexpected custom legalisation");
1906 Results.push_back(customLegalizeToWOp(N, DAG, 2, ISD::SIGN_EXTEND));
1907 break;
1908 case ISD::SHL:
1909 case ISD::SRA:
1910 case ISD::SRL:
1911 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1912 "Unexpected custom legalisation");
1913 if (N->getOperand(1).getOpcode() != ISD::Constant) {
1914 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1915 break;
1916 }
1917 break;
1918 case ISD::ROTL:
1919 case ISD::ROTR:
1920 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1921 "Unexpected custom legalisation");
1922 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1923 break;
1924 case ISD::FP_TO_SINT: {
1925 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1926 "Unexpected custom legalisation");
1927 SDValue Src = N->getOperand(0);
1928 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1929 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1931 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1932 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1933 return;
1934 }
1935 // If the FP type needs to be softened, emit a library call using the 'si'
1936 // version. If we left it to default legalization we'd end up with 'di'.
1937 RTLIB::Libcall LC;
1938 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1939 MakeLibCallOptions CallOptions;
1940 EVT OpVT = Src.getValueType();
1941 CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1942 SDValue Chain = SDValue();
1943 SDValue Result;
1944 std::tie(Result, Chain) =
1945 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1946 Results.push_back(Result);
1947 break;
1948 }
1949 case ISD::BITCAST: {
1950 SDValue Src = N->getOperand(0);
1951 EVT SrcVT = Src.getValueType();
1952 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1953 Subtarget.hasBasicF()) {
1954 SDValue Dst =
1955 DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
1956 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1957 }
1958 break;
1959 }
1960 case ISD::FP_TO_UINT: {
1961 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1962 "Unexpected custom legalisation");
1963 auto &TLI = DAG.getTargetLoweringInfo();
1964 SDValue Tmp1, Tmp2;
1965 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1966 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1967 break;
1968 }
1969 case ISD::BSWAP: {
1970 SDValue Src = N->getOperand(0);
1971 assert((VT == MVT::i16 || VT == MVT::i32) &&
1972 "Unexpected custom legalization");
1973 MVT GRLenVT = Subtarget.getGRLenVT();
1974 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1975 SDValue Tmp;
1976 switch (VT.getSizeInBits()) {
1977 default:
1978 llvm_unreachable("Unexpected operand width");
1979 case 16:
1980 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1981 break;
1982 case 32:
1983 // Only LA64 will get to here due to the size mismatch between VT and
1984 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1985 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1986 break;
1987 }
1988 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1989 break;
1990 }
1991 case ISD::BITREVERSE: {
1992 SDValue Src = N->getOperand(0);
1993 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
1994 "Unexpected custom legalization");
1995 MVT GRLenVT = Subtarget.getGRLenVT();
1996 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1997 SDValue Tmp;
1998 switch (VT.getSizeInBits()) {
1999 default:
2000 llvm_unreachable("Unexpected operand width");
2001 case 8:
2002 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
2003 break;
2004 case 32:
2005 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
2006 break;
2007 }
2008 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
2009 break;
2010 }
2011 case ISD::CTLZ:
2012 case ISD::CTTZ: {
2013 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
2014 "Unexpected custom legalisation");
2015 Results.push_back(customLegalizeToWOp(N, DAG, 1));
2016 break;
2017 }
2019 SDValue Chain = N->getOperand(0);
2020 SDValue Op2 = N->getOperand(2);
2021 MVT GRLenVT = Subtarget.getGRLenVT();
2022 const StringRef ErrorMsgOOR = "argument out of range";
2023 const StringRef ErrorMsgReqLA64 = "requires loongarch64";
2024 const StringRef ErrorMsgReqF = "requires basic 'f' target feature";
2025
2026 switch (N->getConstantOperandVal(1)) {
2027 default:
2028 llvm_unreachable("Unexpected Intrinsic.");
2029 case Intrinsic::loongarch_movfcsr2gr: {
2030 if (!Subtarget.hasBasicF()) {
2031 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqF);
2032 return;
2033 }
2034 unsigned Imm = Op2->getAsZExtVal();
2035 if (!isUInt<2>(Imm)) {
2036 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
2037 return;
2038 }
2039 SDValue MOVFCSR2GRResults = DAG.getNode(
2040 LoongArchISD::MOVFCSR2GR, SDLoc(N), {MVT::i64, MVT::Other},
2041 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
2042 Results.push_back(
2043 DAG.getNode(ISD::TRUNCATE, DL, VT, MOVFCSR2GRResults.getValue(0)));
2044 Results.push_back(MOVFCSR2GRResults.getValue(1));
2045 break;
2046 }
2047#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
2048 case Intrinsic::loongarch_##NAME: { \
2049 SDValue NODE = DAG.getNode( \
2050 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
2051 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
2052 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
2053 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
2054 Results.push_back(NODE.getValue(1)); \
2055 break; \
2056 }
2057 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
2058 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
2059 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
2060 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
2061 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
2062 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
2063#undef CRC_CASE_EXT_BINARYOP
2064
2065#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
2066 case Intrinsic::loongarch_##NAME: { \
2067 SDValue NODE = DAG.getNode( \
2068 LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
2069 {Chain, Op2, \
2070 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))}); \
2071 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, NODE.getValue(0))); \
2072 Results.push_back(NODE.getValue(1)); \
2073 break; \
2074 }
2075 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
2076 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
2077#undef CRC_CASE_EXT_UNARYOP
2078#define CSR_CASE(ID) \
2079 case Intrinsic::loongarch_##ID: { \
2080 if (!Subtarget.is64Bit()) \
2081 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64); \
2082 break; \
2083 }
2084 CSR_CASE(csrrd_d);
2085 CSR_CASE(csrwr_d);
2086 CSR_CASE(csrxchg_d);
2087 CSR_CASE(iocsrrd_d);
2088#undef CSR_CASE
2089 case Intrinsic::loongarch_csrrd_w: {
2090 unsigned Imm = Op2->getAsZExtVal();
2091 if (!isUInt<14>(Imm)) {
2092 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
2093 return;
2094 }
2095 SDValue CSRRDResults =
2096 DAG.getNode(LoongArchISD::CSRRD, DL, {GRLenVT, MVT::Other},
2097 {Chain, DAG.getConstant(Imm, DL, GRLenVT)});
2098 Results.push_back(
2099 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRRDResults.getValue(0)));
2100 Results.push_back(CSRRDResults.getValue(1));
2101 break;
2102 }
2103 case Intrinsic::loongarch_csrwr_w: {
2104 unsigned Imm = N->getConstantOperandVal(3);
2105 if (!isUInt<14>(Imm)) {
2106 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
2107 return;
2108 }
2109 SDValue CSRWRResults =
2110 DAG.getNode(LoongArchISD::CSRWR, DL, {GRLenVT, MVT::Other},
2111 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
2112 DAG.getConstant(Imm, DL, GRLenVT)});
2113 Results.push_back(
2114 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRWRResults.getValue(0)));
2115 Results.push_back(CSRWRResults.getValue(1));
2116 break;
2117 }
2118 case Intrinsic::loongarch_csrxchg_w: {
2119 unsigned Imm = N->getConstantOperandVal(4);
2120 if (!isUInt<14>(Imm)) {
2121 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgOOR);
2122 return;
2123 }
2124 SDValue CSRXCHGResults = DAG.getNode(
2125 LoongArchISD::CSRXCHG, DL, {GRLenVT, MVT::Other},
2126 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
2127 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
2128 DAG.getConstant(Imm, DL, GRLenVT)});
2129 Results.push_back(
2130 DAG.getNode(ISD::TRUNCATE, DL, VT, CSRXCHGResults.getValue(0)));
2131 Results.push_back(CSRXCHGResults.getValue(1));
2132 break;
2133 }
2134#define IOCSRRD_CASE(NAME, NODE) \
2135 case Intrinsic::loongarch_##NAME: { \
2136 SDValue IOCSRRDResults = \
2137 DAG.getNode(LoongArchISD::NODE, DL, {MVT::i64, MVT::Other}, \
2138 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)}); \
2139 Results.push_back( \
2140 DAG.getNode(ISD::TRUNCATE, DL, VT, IOCSRRDResults.getValue(0))); \
2141 Results.push_back(IOCSRRDResults.getValue(1)); \
2142 break; \
2143 }
2144 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
2145 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
2146 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
2147#undef IOCSRRD_CASE
2148 case Intrinsic::loongarch_cpucfg: {
2149 SDValue CPUCFGResults =
2150 DAG.getNode(LoongArchISD::CPUCFG, DL, {GRLenVT, MVT::Other},
2151 {Chain, DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)});
2152 Results.push_back(
2153 DAG.getNode(ISD::TRUNCATE, DL, VT, CPUCFGResults.getValue(0)));
2154 Results.push_back(CPUCFGResults.getValue(1));
2155 break;
2156 }
2157 case Intrinsic::loongarch_lddir_d: {
2158 if (!Subtarget.is64Bit()) {
2159 emitErrorAndReplaceIntrinsicResults(N, Results, DAG, ErrorMsgReqLA64);
2160 return;
2161 }
2162 break;
2163 }
2164 }
2165 break;
2166 }
2167 case ISD::READ_REGISTER: {
2168 if (Subtarget.is64Bit())
2169 DAG.getContext()->emitError(
2170 "On LA64, only 64-bit registers can be read.");
2171 else
2172 DAG.getContext()->emitError(
2173 "On LA32, only 32-bit registers can be read.");
2174 Results.push_back(DAG.getUNDEF(VT));
2175 Results.push_back(N->getOperand(0));
2176 break;
2177 }
2179 replaceINTRINSIC_WO_CHAINResults(N, Results, DAG, Subtarget);
2180 break;
2181 }
2182 }
2183}
2184
2187 const LoongArchSubtarget &Subtarget) {
2188 if (DCI.isBeforeLegalizeOps())
2189 return SDValue();
2190
2191 SDValue FirstOperand = N->getOperand(0);
2192 SDValue SecondOperand = N->getOperand(1);
2193 unsigned FirstOperandOpc = FirstOperand.getOpcode();
2194 EVT ValTy = N->getValueType(0);
2195 SDLoc DL(N);
2196 uint64_t lsb, msb;
2197 unsigned SMIdx, SMLen;
2198 ConstantSDNode *CN;
2199 SDValue NewOperand;
2200 MVT GRLenVT = Subtarget.getGRLenVT();
2201
2202 // Op's second operand must be a shifted mask.
2203 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
2204 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
2205 return SDValue();
2206
2207 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
2208 // Pattern match BSTRPICK.
2209 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
2210 // => BSTRPICK $dst, $src, msb, lsb
2211 // where msb = lsb + len - 1
2212
2213 // The second operand of the shift must be an immediate.
2214 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
2215 return SDValue();
2216
2217 lsb = CN->getZExtValue();
2218
2219 // Return if the shifted mask does not start at bit 0 or the sum of its
2220 // length and lsb exceeds the word's size.
2221 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
2222 return SDValue();
2223
2224 NewOperand = FirstOperand.getOperand(0);
2225 } else {
2226 // Pattern match BSTRPICK.
2227 // $dst = and $src, (2**len- 1) , if len > 12
2228 // => BSTRPICK $dst, $src, msb, lsb
2229 // where lsb = 0 and msb = len - 1
2230
2231 // If the mask is <= 0xfff, andi can be used instead.
2232 if (CN->getZExtValue() <= 0xfff)
2233 return SDValue();
2234
2235 // Return if the MSB exceeds.
2236 if (SMIdx + SMLen > ValTy.getSizeInBits())
2237 return SDValue();
2238
2239 if (SMIdx > 0) {
2240 // Omit if the constant has more than 2 uses. This a conservative
2241 // decision. Whether it is a win depends on the HW microarchitecture.
2242 // However it should always be better for 1 and 2 uses.
2243 if (CN->use_size() > 2)
2244 return SDValue();
2245 // Return if the constant can be composed by a single LU12I.W.
2246 if ((CN->getZExtValue() & 0xfff) == 0)
2247 return SDValue();
2248 // Return if the constand can be composed by a single ADDI with
2249 // the zero register.
2250 if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
2251 return SDValue();
2252 }
2253
2254 lsb = SMIdx;
2255 NewOperand = FirstOperand;
2256 }
2257
2258 msb = lsb + SMLen - 1;
2259 SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
2260 DAG.getConstant(msb, DL, GRLenVT),
2261 DAG.getConstant(lsb, DL, GRLenVT));
2262 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
2263 return NR0;
2264 // Try to optimize to
2265 // bstrpick $Rd, $Rs, msb, lsb
2266 // slli $Rd, $Rd, lsb
2267 return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
2268 DAG.getConstant(lsb, DL, GRLenVT));
2269}
2270
2273 const LoongArchSubtarget &Subtarget) {
2274 if (DCI.isBeforeLegalizeOps())
2275 return SDValue();
2276
2277 // $dst = srl (and $src, Mask), Shamt
2278 // =>
2279 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
2280 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
2281 //
2282
2283 SDValue FirstOperand = N->getOperand(0);
2284 ConstantSDNode *CN;
2285 EVT ValTy = N->getValueType(0);
2286 SDLoc DL(N);
2287 MVT GRLenVT = Subtarget.getGRLenVT();
2288 unsigned MaskIdx, MaskLen;
2289 uint64_t Shamt;
2290
2291 // The first operand must be an AND and the second operand of the AND must be
2292 // a shifted mask.
2293 if (FirstOperand.getOpcode() != ISD::AND ||
2294 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
2295 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
2296 return SDValue();
2297
2298 // The second operand (shift amount) must be an immediate.
2299 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
2300 return SDValue();
2301
2302 Shamt = CN->getZExtValue();
2303 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
2304 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
2305 FirstOperand->getOperand(0),
2306 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
2307 DAG.getConstant(Shamt, DL, GRLenVT));
2308
2309 return SDValue();
2310}
2311
2314 const LoongArchSubtarget &Subtarget) {
2315 MVT GRLenVT = Subtarget.getGRLenVT();
2316 EVT ValTy = N->getValueType(0);
2317 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
2318 ConstantSDNode *CN0, *CN1;
2319 SDLoc DL(N);
2320 unsigned ValBits = ValTy.getSizeInBits();
2321 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
2322 unsigned Shamt;
2323 bool SwapAndRetried = false;
2324
2325 if (DCI.isBeforeLegalizeOps())
2326 return SDValue();
2327
2328 if (ValBits != 32 && ValBits != 64)
2329 return SDValue();
2330
2331Retry:
2332 // 1st pattern to match BSTRINS:
2333 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
2334 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
2335 // =>
2336 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
2337 if (N0.getOpcode() == ISD::AND &&
2338 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2339 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2340 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
2341 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2342 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
2343 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
2344 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2345 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
2346 (MaskIdx0 + MaskLen0 <= ValBits)) {
2347 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
2348 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2349 N1.getOperand(0).getOperand(0),
2350 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
2351 DAG.getConstant(MaskIdx0, DL, GRLenVT));
2352 }
2353
2354 // 2nd pattern to match BSTRINS:
2355 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
2356 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
2357 // =>
2358 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
2359 if (N0.getOpcode() == ISD::AND &&
2360 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2361 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2362 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
2363 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2364 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
2365 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2366 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
2367 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
2368 (MaskIdx0 + MaskLen0 <= ValBits)) {
2369 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
2370 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2371 N1.getOperand(0).getOperand(0),
2372 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
2373 DAG.getConstant(MaskIdx0, DL, GRLenVT));
2374 }
2375
2376 // 3rd pattern to match BSTRINS:
2377 // R = or (and X, mask0), (and Y, mask1)
2378 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
2379 // =>
2380 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
2381 // where msb = lsb + size - 1
2382 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
2383 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2384 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2385 (MaskIdx0 + MaskLen0 <= 64) &&
2386 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
2387 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
2388 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
2389 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2390 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
2391 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
2392 DAG.getConstant(ValBits == 32
2393 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
2394 : (MaskIdx0 + MaskLen0 - 1),
2395 DL, GRLenVT),
2396 DAG.getConstant(MaskIdx0, DL, GRLenVT));
2397 }
2398
2399 // 4th pattern to match BSTRINS:
2400 // R = or (and X, mask), (shl Y, shamt)
2401 // where mask = (2**shamt - 1)
2402 // =>
2403 // R = BSTRINS X, Y, ValBits - 1, shamt
2404 // where ValBits = 32 or 64
2405 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
2406 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2407 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
2408 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2409 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
2410 (MaskIdx0 + MaskLen0 <= ValBits)) {
2411 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
2412 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2413 N1.getOperand(0),
2414 DAG.getConstant((ValBits - 1), DL, GRLenVT),
2415 DAG.getConstant(Shamt, DL, GRLenVT));
2416 }
2417
2418 // 5th pattern to match BSTRINS:
2419 // R = or (and X, mask), const
2420 // where ~mask = (2**size - 1) << lsb, mask & const = 0
2421 // =>
2422 // R = BSTRINS X, (const >> lsb), msb, lsb
2423 // where msb = lsb + size - 1
2424 if (N0.getOpcode() == ISD::AND &&
2425 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
2426 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
2427 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
2428 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
2429 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
2430 return DAG.getNode(
2431 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
2432 DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
2433 DAG.getConstant(ValBits == 32 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
2434 : (MaskIdx0 + MaskLen0 - 1),
2435 DL, GRLenVT),
2436 DAG.getConstant(MaskIdx0, DL, GRLenVT));
2437 }
2438
2439 // 6th pattern.
2440 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
2441 // by the incoming bits are known to be zero.
2442 // =>
2443 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
2444 //
2445 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
2446 // pattern is more common than the 1st. So we put the 1st before the 6th in
2447 // order to match as many nodes as possible.
2448 ConstantSDNode *CNMask, *CNShamt;
2449 unsigned MaskIdx, MaskLen;
2450 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
2451 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2452 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
2453 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2454 CNShamt->getZExtValue() + MaskLen <= ValBits) {
2455 Shamt = CNShamt->getZExtValue();
2456 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
2457 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2458 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
2459 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2460 N1.getOperand(0).getOperand(0),
2461 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
2462 DAG.getConstant(Shamt, DL, GRLenVT));
2463 }
2464 }
2465
2466 // 7th pattern.
2467 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
2468 // overwritten by the incoming bits are known to be zero.
2469 // =>
2470 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
2471 //
2472 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
2473 // before the 7th in order to match as many nodes as possible.
2474 if (N1.getOpcode() == ISD::AND &&
2475 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2476 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
2477 N1.getOperand(0).getOpcode() == ISD::SHL &&
2478 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
2479 CNShamt->getZExtValue() == MaskIdx) {
2480 APInt ShMask(ValBits, CNMask->getZExtValue());
2481 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2482 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
2483 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2484 N1.getOperand(0).getOperand(0),
2485 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
2486 DAG.getConstant(MaskIdx, DL, GRLenVT));
2487 }
2488 }
2489
2490 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
2491 if (!SwapAndRetried) {
2492 std::swap(N0, N1);
2493 SwapAndRetried = true;
2494 goto Retry;
2495 }
2496
2497 SwapAndRetried = false;
2498Retry2:
2499 // 8th pattern.
2500 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
2501 // the incoming bits are known to be zero.
2502 // =>
2503 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
2504 //
2505 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
2506 // we put it here in order to match as many nodes as possible or generate less
2507 // instructions.
2508 if (N1.getOpcode() == ISD::AND &&
2509 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
2510 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
2511 APInt ShMask(ValBits, CNMask->getZExtValue());
2512 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
2513 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
2514 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
2515 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
2516 N1->getOperand(0),
2517 DAG.getConstant(MaskIdx, DL, GRLenVT)),
2518 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
2519 DAG.getConstant(MaskIdx, DL, GRLenVT));
2520 }
2521 }
2522 // Swap N0/N1 and retry.
2523 if (!SwapAndRetried) {
2524 std::swap(N0, N1);
2525 SwapAndRetried = true;
2526 goto Retry2;
2527 }
2528
2529 return SDValue();
2530}
2531
2532static bool checkValueWidth(SDValue V, ISD::LoadExtType &ExtType) {
2533 ExtType = ISD::NON_EXTLOAD;
2534
2535 switch (V.getNode()->getOpcode()) {
2536 case ISD::LOAD: {
2537 LoadSDNode *LoadNode = cast<LoadSDNode>(V.getNode());
2538 if ((LoadNode->getMemoryVT() == MVT::i8) ||
2539 (LoadNode->getMemoryVT() == MVT::i16)) {
2540 ExtType = LoadNode->getExtensionType();
2541 return true;
2542 }
2543 return false;
2544 }
2545 case ISD::AssertSext: {
2546 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
2547 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
2548 ExtType = ISD::SEXTLOAD;
2549 return true;
2550 }
2551 return false;
2552 }
2553 case ISD::AssertZext: {
2554 VTSDNode *TypeNode = cast<VTSDNode>(V.getNode()->getOperand(1));
2555 if ((TypeNode->getVT() == MVT::i8) || (TypeNode->getVT() == MVT::i16)) {
2556 ExtType = ISD::ZEXTLOAD;
2557 return true;
2558 }
2559 return false;
2560 }
2561 default:
2562 return false;
2563 }
2564
2565 return false;
2566}
2567
2568// Eliminate redundant truncation and zero-extension nodes.
2569// * Case 1:
2570// +------------+ +------------+ +------------+
2571// | Input1 | | Input2 | | CC |
2572// +------------+ +------------+ +------------+
2573// | | |
2574// V V +----+
2575// +------------+ +------------+ |
2576// | TRUNCATE | | TRUNCATE | |
2577// +------------+ +------------+ |
2578// | | |
2579// V V |
2580// +------------+ +------------+ |
2581// | ZERO_EXT | | ZERO_EXT | |
2582// +------------+ +------------+ |
2583// | | |
2584// | +-------------+ |
2585// V V | |
2586// +----------------+ | |
2587// | AND | | |
2588// +----------------+ | |
2589// | | |
2590// +---------------+ | |
2591// | | |
2592// V V V
2593// +-------------+
2594// | CMP |
2595// +-------------+
2596// * Case 2:
2597// +------------+ +------------+ +-------------+ +------------+ +------------+
2598// | Input1 | | Input2 | | Constant -1 | | Constant 0 | | CC |
2599// +------------+ +------------+ +-------------+ +------------+ +------------+
2600// | | | | |
2601// V | | | |
2602// +------------+ | | | |
2603// | XOR |<---------------------+ | |
2604// +------------+ | | |
2605// | | | |
2606// V V +---------------+ |
2607// +------------+ +------------+ | |
2608// | TRUNCATE | | TRUNCATE | | +-------------------------+
2609// +------------+ +------------+ | |
2610// | | | |
2611// V V | |
2612// +------------+ +------------+ | |
2613// | ZERO_EXT | | ZERO_EXT | | |
2614// +------------+ +------------+ | |
2615// | | | |
2616// V V | |
2617// +----------------+ | |
2618// | AND | | |
2619// +----------------+ | |
2620// | | |
2621// +---------------+ | |
2622// | | |
2623// V V V
2624// +-------------+
2625// | CMP |
2626// +-------------+
2629 const LoongArchSubtarget &Subtarget) {
2630 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
2631
2632 SDNode *AndNode = N->getOperand(0).getNode();
2633 if (AndNode->getOpcode() != ISD::AND)
2634 return SDValue();
2635
2636 SDValue AndInputValue2 = AndNode->getOperand(1);
2637 if (AndInputValue2.getOpcode() != ISD::ZERO_EXTEND)
2638 return SDValue();
2639
2640 SDValue CmpInputValue = N->getOperand(1);
2641 SDValue AndInputValue1 = AndNode->getOperand(0);
2642 if (AndInputValue1.getOpcode() == ISD::XOR) {
2643 if (CC != ISD::SETEQ && CC != ISD::SETNE)
2644 return SDValue();
2645 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(AndInputValue1.getOperand(1));
2646 if (!CN || CN->getSExtValue() != -1)
2647 return SDValue();
2648 CN = dyn_cast<ConstantSDNode>(CmpInputValue);
2649 if (!CN || CN->getSExtValue() != 0)
2650 return SDValue();
2651 AndInputValue1 = AndInputValue1.getOperand(0);
2652 if (AndInputValue1.getOpcode() != ISD::ZERO_EXTEND)
2653 return SDValue();
2654 } else if (AndInputValue1.getOpcode() == ISD::ZERO_EXTEND) {
2655 if (AndInputValue2 != CmpInputValue)
2656 return SDValue();
2657 } else {
2658 return SDValue();
2659 }
2660
2661 SDValue TruncValue1 = AndInputValue1.getNode()->getOperand(0);
2662 if (TruncValue1.getOpcode() != ISD::TRUNCATE)
2663 return SDValue();
2664
2665 SDValue TruncValue2 = AndInputValue2.getNode()->getOperand(0);
2666 if (TruncValue2.getOpcode() != ISD::TRUNCATE)
2667 return SDValue();
2668
2669 SDValue TruncInputValue1 = TruncValue1.getNode()->getOperand(0);
2670 SDValue TruncInputValue2 = TruncValue2.getNode()->getOperand(0);
2671 ISD::LoadExtType ExtType1;
2672 ISD::LoadExtType ExtType2;
2673
2674 if (!checkValueWidth(TruncInputValue1, ExtType1) ||
2675 !checkValueWidth(TruncInputValue2, ExtType2))
2676 return SDValue();
2677
2678 if ((ExtType2 != ISD::ZEXTLOAD) &&
2679 ((ExtType2 != ISD::SEXTLOAD) && (ExtType1 != ISD::SEXTLOAD)))
2680 return SDValue();
2681
2682 // These truncation and zero-extension nodes are not necessary, remove them.
2683 SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N), AndNode->getValueType(0),
2684 TruncInputValue1, TruncInputValue2);
2685 SDValue NewSetCC =
2686 DAG.getSetCC(SDLoc(N), N->getValueType(0), NewAnd, TruncInputValue2, CC);
2687 DAG.ReplaceAllUsesWith(N, NewSetCC.getNode());
2688 return SDValue(N, 0);
2689}
2690
2691// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
2694 const LoongArchSubtarget &Subtarget) {
2695 if (DCI.isBeforeLegalizeOps())
2696 return SDValue();
2697
2698 SDValue Src = N->getOperand(0);
2699 if (Src.getOpcode() != LoongArchISD::REVB_2W)
2700 return SDValue();
2701
2702 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
2703 Src.getOperand(0));
2704}
2705
2706template <unsigned N>
2708 SelectionDAG &DAG,
2709 const LoongArchSubtarget &Subtarget,
2710 bool IsSigned = false) {
2711 SDLoc DL(Node);
2712 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
2713 // Check the ImmArg.
2714 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
2715 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
2716 DAG.getContext()->emitError(Node->getOperationName(0) +
2717 ": argument out of range.");
2718 return DAG.getNode(ISD::UNDEF, DL, Subtarget.getGRLenVT());
2719 }
2720 return DAG.getConstant(CImm->getZExtValue(), DL, Subtarget.getGRLenVT());
2721}
2722
2723template <unsigned N>
2724static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp,
2725 SelectionDAG &DAG, bool IsSigned = false) {
2726 SDLoc DL(Node);
2727 EVT ResTy = Node->getValueType(0);
2728 auto *CImm = cast<ConstantSDNode>(Node->getOperand(ImmOp));
2729
2730 // Check the ImmArg.
2731 if ((IsSigned && !isInt<N>(CImm->getSExtValue())) ||
2732 (!IsSigned && !isUInt<N>(CImm->getZExtValue()))) {
2733 DAG.getContext()->emitError(Node->getOperationName(0) +
2734 ": argument out of range.");
2735 return DAG.getNode(ISD::UNDEF, DL, ResTy);
2736 }
2737 return DAG.getConstant(
2739 IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
2740 DL, ResTy);
2741}
2742
2744 SDLoc DL(Node);
2745 EVT ResTy = Node->getValueType(0);
2746 SDValue Vec = Node->getOperand(2);
2747 SDValue Mask = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1, DL, ResTy);
2748 return DAG.getNode(ISD::AND, DL, ResTy, Vec, Mask);
2749}
2750
2752 SDLoc DL(Node);
2753 EVT ResTy = Node->getValueType(0);
2754 SDValue One = DAG.getConstant(1, DL, ResTy);
2755 SDValue Bit =
2756 DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Node, DAG));
2757
2758 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1),
2759 DAG.getNOT(DL, Bit, ResTy));
2760}
2761
2762template <unsigned N>
2764 SDLoc DL(Node);
2765 EVT ResTy = Node->getValueType(0);
2766 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2767 // Check the unsigned ImmArg.
2768 if (!isUInt<N>(CImm->getZExtValue())) {
2769 DAG.getContext()->emitError(Node->getOperationName(0) +
2770 ": argument out of range.");
2771 return DAG.getNode(ISD::UNDEF, DL, ResTy);
2772 }
2773
2774 APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2775 SDValue Mask = DAG.getConstant(~BitImm, DL, ResTy);
2776
2777 return DAG.getNode(ISD::AND, DL, ResTy, Node->getOperand(1), Mask);
2778}
2779
2780template <unsigned N>
2782 SDLoc DL(Node);
2783 EVT ResTy = Node->getValueType(0);
2784 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2785 // Check the unsigned ImmArg.
2786 if (!isUInt<N>(CImm->getZExtValue())) {
2787 DAG.getContext()->emitError(Node->getOperationName(0) +
2788 ": argument out of range.");
2789 return DAG.getNode(ISD::UNDEF, DL, ResTy);
2790 }
2791
2792 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2793 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
2794 return DAG.getNode(ISD::OR, DL, ResTy, Node->getOperand(1), BitImm);
2795}
2796
2797template <unsigned N>
2799 SDLoc DL(Node);
2800 EVT ResTy = Node->getValueType(0);
2801 auto *CImm = cast<ConstantSDNode>(Node->getOperand(2));
2802 // Check the unsigned ImmArg.
2803 if (!isUInt<N>(CImm->getZExtValue())) {
2804 DAG.getContext()->emitError(Node->getOperationName(0) +
2805 ": argument out of range.");
2806 return DAG.getNode(ISD::UNDEF, DL, ResTy);
2807 }
2808
2809 APInt Imm = APInt(ResTy.getScalarSizeInBits(), 1) << CImm->getAPIntValue();
2810 SDValue BitImm = DAG.getConstant(Imm, DL, ResTy);
2811 return DAG.getNode(ISD::XOR, DL, ResTy, Node->getOperand(1), BitImm);
2812}
2813
2814static SDValue
2817 const LoongArchSubtarget &Subtarget) {
2818 SDLoc DL(N);
2819 switch (N->getConstantOperandVal(0)) {
2820 default:
2821 break;
2822 case Intrinsic::loongarch_lsx_vadd_b:
2823 case Intrinsic::loongarch_lsx_vadd_h:
2824 case Intrinsic::loongarch_lsx_vadd_w:
2825 case Intrinsic::loongarch_lsx_vadd_d:
2826 case Intrinsic::loongarch_lasx_xvadd_b:
2827 case Intrinsic::loongarch_lasx_xvadd_h:
2828 case Intrinsic::loongarch_lasx_xvadd_w:
2829 case Intrinsic::loongarch_lasx_xvadd_d:
2830 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
2831 N->getOperand(2));
2832 case Intrinsic::loongarch_lsx_vaddi_bu:
2833 case Intrinsic::loongarch_lsx_vaddi_hu:
2834 case Intrinsic::loongarch_lsx_vaddi_wu:
2835 case Intrinsic::loongarch_lsx_vaddi_du:
2836 case Intrinsic::loongarch_lasx_xvaddi_bu:
2837 case Intrinsic::loongarch_lasx_xvaddi_hu:
2838 case Intrinsic::loongarch_lasx_xvaddi_wu:
2839 case Intrinsic::loongarch_lasx_xvaddi_du:
2840 return DAG.getNode(ISD::ADD, DL, N->getValueType(0), N->getOperand(1),
2841 lowerVectorSplatImm<5>(N, 2, DAG));
2842 case Intrinsic::loongarch_lsx_vsub_b:
2843 case Intrinsic::loongarch_lsx_vsub_h:
2844 case Intrinsic::loongarch_lsx_vsub_w:
2845 case Intrinsic::loongarch_lsx_vsub_d:
2846 case Intrinsic::loongarch_lasx_xvsub_b:
2847 case Intrinsic::loongarch_lasx_xvsub_h:
2848 case Intrinsic::loongarch_lasx_xvsub_w:
2849 case Intrinsic::loongarch_lasx_xvsub_d:
2850 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
2851 N->getOperand(2));
2852 case Intrinsic::loongarch_lsx_vsubi_bu:
2853 case Intrinsic::loongarch_lsx_vsubi_hu:
2854 case Intrinsic::loongarch_lsx_vsubi_wu:
2855 case Intrinsic::loongarch_lsx_vsubi_du:
2856 case Intrinsic::loongarch_lasx_xvsubi_bu:
2857 case Intrinsic::loongarch_lasx_xvsubi_hu:
2858 case Intrinsic::loongarch_lasx_xvsubi_wu:
2859 case Intrinsic::loongarch_lasx_xvsubi_du:
2860 return DAG.getNode(ISD::SUB, DL, N->getValueType(0), N->getOperand(1),
2861 lowerVectorSplatImm<5>(N, 2, DAG));
2862 case Intrinsic::loongarch_lsx_vneg_b:
2863 case Intrinsic::loongarch_lsx_vneg_h:
2864 case Intrinsic::loongarch_lsx_vneg_w:
2865 case Intrinsic::loongarch_lsx_vneg_d:
2866 case Intrinsic::loongarch_lasx_xvneg_b:
2867 case Intrinsic::loongarch_lasx_xvneg_h:
2868 case Intrinsic::loongarch_lasx_xvneg_w:
2869 case Intrinsic::loongarch_lasx_xvneg_d:
2870 return DAG.getNode(
2871 ISD::SUB, DL, N->getValueType(0),
2872 DAG.getConstant(
2873 APInt(N->getValueType(0).getScalarType().getSizeInBits(), 0,
2874 /*isSigned=*/true),
2875 SDLoc(N), N->getValueType(0)),
2876 N->getOperand(1));
2877 case Intrinsic::loongarch_lsx_vmax_b:
2878 case Intrinsic::loongarch_lsx_vmax_h:
2879 case Intrinsic::loongarch_lsx_vmax_w:
2880 case Intrinsic::loongarch_lsx_vmax_d:
2881 case Intrinsic::loongarch_lasx_xvmax_b:
2882 case Intrinsic::loongarch_lasx_xvmax_h:
2883 case Intrinsic::loongarch_lasx_xvmax_w:
2884 case Intrinsic::loongarch_lasx_xvmax_d:
2885 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
2886 N->getOperand(2));
2887 case Intrinsic::loongarch_lsx_vmax_bu:
2888 case Intrinsic::loongarch_lsx_vmax_hu:
2889 case Intrinsic::loongarch_lsx_vmax_wu:
2890 case Intrinsic::loongarch_lsx_vmax_du:
2891 case Intrinsic::loongarch_lasx_xvmax_bu:
2892 case Intrinsic::loongarch_lasx_xvmax_hu:
2893 case Intrinsic::loongarch_lasx_xvmax_wu:
2894 case Intrinsic::loongarch_lasx_xvmax_du:
2895 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
2896 N->getOperand(2));
2897 case Intrinsic::loongarch_lsx_vmaxi_b:
2898 case Intrinsic::loongarch_lsx_vmaxi_h:
2899 case Intrinsic::loongarch_lsx_vmaxi_w:
2900 case Intrinsic::loongarch_lsx_vmaxi_d:
2901 case Intrinsic::loongarch_lasx_xvmaxi_b:
2902 case Intrinsic::loongarch_lasx_xvmaxi_h:
2903 case Intrinsic::loongarch_lasx_xvmaxi_w:
2904 case Intrinsic::loongarch_lasx_xvmaxi_d:
2905 return DAG.getNode(ISD::SMAX, DL, N->getValueType(0), N->getOperand(1),
2906 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
2907 case Intrinsic::loongarch_lsx_vmaxi_bu:
2908 case Intrinsic::loongarch_lsx_vmaxi_hu:
2909 case Intrinsic::loongarch_lsx_vmaxi_wu:
2910 case Intrinsic::loongarch_lsx_vmaxi_du:
2911 case Intrinsic::loongarch_lasx_xvmaxi_bu:
2912 case Intrinsic::loongarch_lasx_xvmaxi_hu:
2913 case Intrinsic::loongarch_lasx_xvmaxi_wu:
2914 case Intrinsic::loongarch_lasx_xvmaxi_du:
2915 return DAG.getNode(ISD::UMAX, DL, N->getValueType(0), N->getOperand(1),
2916 lowerVectorSplatImm<5>(N, 2, DAG));
2917 case Intrinsic::loongarch_lsx_vmin_b:
2918 case Intrinsic::loongarch_lsx_vmin_h:
2919 case Intrinsic::loongarch_lsx_vmin_w:
2920 case Intrinsic::loongarch_lsx_vmin_d:
2921 case Intrinsic::loongarch_lasx_xvmin_b:
2922 case Intrinsic::loongarch_lasx_xvmin_h:
2923 case Intrinsic::loongarch_lasx_xvmin_w:
2924 case Intrinsic::loongarch_lasx_xvmin_d:
2925 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
2926 N->getOperand(2));
2927 case Intrinsic::loongarch_lsx_vmin_bu:
2928 case Intrinsic::loongarch_lsx_vmin_hu:
2929 case Intrinsic::loongarch_lsx_vmin_wu:
2930 case Intrinsic::loongarch_lsx_vmin_du:
2931 case Intrinsic::loongarch_lasx_xvmin_bu:
2932 case Intrinsic::loongarch_lasx_xvmin_hu:
2933 case Intrinsic::loongarch_lasx_xvmin_wu:
2934 case Intrinsic::loongarch_lasx_xvmin_du:
2935 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
2936 N->getOperand(2));
2937 case Intrinsic::loongarch_lsx_vmini_b:
2938 case Intrinsic::loongarch_lsx_vmini_h:
2939 case Intrinsic::loongarch_lsx_vmini_w:
2940 case Intrinsic::loongarch_lsx_vmini_d:
2941 case Intrinsic::loongarch_lasx_xvmini_b:
2942 case Intrinsic::loongarch_lasx_xvmini_h:
2943 case Intrinsic::loongarch_lasx_xvmini_w:
2944 case Intrinsic::loongarch_lasx_xvmini_d:
2945 return DAG.getNode(ISD::SMIN, DL, N->getValueType(0), N->getOperand(1),
2946 lowerVectorSplatImm<5>(N, 2, DAG, /*IsSigned=*/true));
2947 case Intrinsic::loongarch_lsx_vmini_bu:
2948 case Intrinsic::loongarch_lsx_vmini_hu:
2949 case Intrinsic::loongarch_lsx_vmini_wu:
2950 case Intrinsic::loongarch_lsx_vmini_du:
2951 case Intrinsic::loongarch_lasx_xvmini_bu:
2952 case Intrinsic::loongarch_lasx_xvmini_hu:
2953 case Intrinsic::loongarch_lasx_xvmini_wu:
2954 case Intrinsic::loongarch_lasx_xvmini_du:
2955 return DAG.getNode(ISD::UMIN, DL, N->getValueType(0), N->getOperand(1),
2956 lowerVectorSplatImm<5>(N, 2, DAG));
2957 case Intrinsic::loongarch_lsx_vmul_b:
2958 case Intrinsic::loongarch_lsx_vmul_h:
2959 case Intrinsic::loongarch_lsx_vmul_w:
2960 case Intrinsic::loongarch_lsx_vmul_d:
2961 case Intrinsic::loongarch_lasx_xvmul_b:
2962 case Intrinsic::loongarch_lasx_xvmul_h:
2963 case Intrinsic::loongarch_lasx_xvmul_w:
2964 case Intrinsic::loongarch_lasx_xvmul_d:
2965 return DAG.getNode(ISD::MUL, DL, N->getValueType(0), N->getOperand(1),
2966 N->getOperand(2));
2967 case Intrinsic::loongarch_lsx_vmadd_b:
2968 case Intrinsic::loongarch_lsx_vmadd_h:
2969 case Intrinsic::loongarch_lsx_vmadd_w:
2970 case Intrinsic::loongarch_lsx_vmadd_d:
2971 case Intrinsic::loongarch_lasx_xvmadd_b:
2972 case Intrinsic::loongarch_lasx_xvmadd_h:
2973 case Intrinsic::loongarch_lasx_xvmadd_w:
2974 case Intrinsic::loongarch_lasx_xvmadd_d: {
2975 EVT ResTy = N->getValueType(0);
2976 return DAG.getNode(ISD::ADD, SDLoc(N), ResTy, N->getOperand(1),
2977 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
2978 N->getOperand(3)));
2979 }
2980 case Intrinsic::loongarch_lsx_vmsub_b:
2981 case Intrinsic::loongarch_lsx_vmsub_h:
2982 case Intrinsic::loongarch_lsx_vmsub_w:
2983 case Intrinsic::loongarch_lsx_vmsub_d:
2984 case Intrinsic::loongarch_lasx_xvmsub_b:
2985 case Intrinsic::loongarch_lasx_xvmsub_h:
2986 case Intrinsic::loongarch_lasx_xvmsub_w:
2987 case Intrinsic::loongarch_lasx_xvmsub_d: {
2988 EVT ResTy = N->getValueType(0);
2989 return DAG.getNode(ISD::SUB, SDLoc(N), ResTy, N->getOperand(1),
2990 DAG.getNode(ISD::MUL, SDLoc(N), ResTy, N->getOperand(2),
2991 N->getOperand(3)));
2992 }
2993 case Intrinsic::loongarch_lsx_vdiv_b:
2994 case Intrinsic::loongarch_lsx_vdiv_h:
2995 case Intrinsic::loongarch_lsx_vdiv_w:
2996 case Intrinsic::loongarch_lsx_vdiv_d:
2997 case Intrinsic::loongarch_lasx_xvdiv_b:
2998 case Intrinsic::loongarch_lasx_xvdiv_h:
2999 case Intrinsic::loongarch_lasx_xvdiv_w:
3000 case Intrinsic::loongarch_lasx_xvdiv_d:
3001 return DAG.getNode(ISD::SDIV, DL, N->getValueType(0), N->getOperand(1),
3002 N->getOperand(2));
3003 case Intrinsic::loongarch_lsx_vdiv_bu:
3004 case Intrinsic::loongarch_lsx_vdiv_hu:
3005 case Intrinsic::loongarch_lsx_vdiv_wu:
3006 case Intrinsic::loongarch_lsx_vdiv_du:
3007 case Intrinsic::loongarch_lasx_xvdiv_bu:
3008 case Intrinsic::loongarch_lasx_xvdiv_hu:
3009 case Intrinsic::loongarch_lasx_xvdiv_wu:
3010 case Intrinsic::loongarch_lasx_xvdiv_du:
3011 return DAG.getNode(ISD::UDIV, DL, N->getValueType(0), N->getOperand(1),
3012 N->getOperand(2));
3013 case Intrinsic::loongarch_lsx_vmod_b:
3014 case Intrinsic::loongarch_lsx_vmod_h:
3015 case Intrinsic::loongarch_lsx_vmod_w:
3016 case Intrinsic::loongarch_lsx_vmod_d:
3017 case Intrinsic::loongarch_lasx_xvmod_b:
3018 case Intrinsic::loongarch_lasx_xvmod_h:
3019 case Intrinsic::loongarch_lasx_xvmod_w:
3020 case Intrinsic::loongarch_lasx_xvmod_d:
3021 return DAG.getNode(ISD::SREM, DL, N->getValueType(0), N->getOperand(1),
3022 N->getOperand(2));
3023 case Intrinsic::loongarch_lsx_vmod_bu:
3024 case Intrinsic::loongarch_lsx_vmod_hu:
3025 case Intrinsic::loongarch_lsx_vmod_wu:
3026 case Intrinsic::loongarch_lsx_vmod_du:
3027 case Intrinsic::loongarch_lasx_xvmod_bu:
3028 case Intrinsic::loongarch_lasx_xvmod_hu:
3029 case Intrinsic::loongarch_lasx_xvmod_wu:
3030 case Intrinsic::loongarch_lasx_xvmod_du:
3031 return DAG.getNode(ISD::UREM, DL, N->getValueType(0), N->getOperand(1),
3032 N->getOperand(2));
3033 case Intrinsic::loongarch_lsx_vand_v:
3034 case Intrinsic::loongarch_lasx_xvand_v:
3035 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
3036 N->getOperand(2));
3037 case Intrinsic::loongarch_lsx_vor_v:
3038 case Intrinsic::loongarch_lasx_xvor_v:
3039 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
3040 N->getOperand(2));
3041 case Intrinsic::loongarch_lsx_vxor_v:
3042 case Intrinsic::loongarch_lasx_xvxor_v:
3043 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
3044 N->getOperand(2));
3045 case Intrinsic::loongarch_lsx_vnor_v:
3046 case Intrinsic::loongarch_lasx_xvnor_v: {
3047 SDValue Res = DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
3048 N->getOperand(2));
3049 return DAG.getNOT(DL, Res, Res->getValueType(0));
3050 }
3051 case Intrinsic::loongarch_lsx_vandi_b:
3052 case Intrinsic::loongarch_lasx_xvandi_b:
3053 return DAG.getNode(ISD::AND, DL, N->getValueType(0), N->getOperand(1),
3054 lowerVectorSplatImm<8>(N, 2, DAG));
3055 case Intrinsic::loongarch_lsx_vori_b:
3056 case Intrinsic::loongarch_lasx_xvori_b:
3057 return DAG.getNode(ISD::OR, DL, N->getValueType(0), N->getOperand(1),
3058 lowerVectorSplatImm<8>(N, 2, DAG));
3059 case Intrinsic::loongarch_lsx_vxori_b:
3060 case Intrinsic::loongarch_lasx_xvxori_b:
3061 return DAG.getNode(ISD::XOR, DL, N->getValueType(0), N->getOperand(1),
3062 lowerVectorSplatImm<8>(N, 2, DAG));
3063 case Intrinsic::loongarch_lsx_vsll_b:
3064 case Intrinsic::loongarch_lsx_vsll_h:
3065 case Intrinsic::loongarch_lsx_vsll_w:
3066 case Intrinsic::loongarch_lsx_vsll_d:
3067 case Intrinsic::loongarch_lasx_xvsll_b:
3068 case Intrinsic::loongarch_lasx_xvsll_h:
3069 case Intrinsic::loongarch_lasx_xvsll_w:
3070 case Intrinsic::loongarch_lasx_xvsll_d:
3071 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
3072 truncateVecElts(N, DAG));
3073 case Intrinsic::loongarch_lsx_vslli_b:
3074 case Intrinsic::loongarch_lasx_xvslli_b:
3075 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
3076 lowerVectorSplatImm<3>(N, 2, DAG));
3077 case Intrinsic::loongarch_lsx_vslli_h:
3078 case Intrinsic::loongarch_lasx_xvslli_h:
3079 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
3080 lowerVectorSplatImm<4>(N, 2, DAG));
3081 case Intrinsic::loongarch_lsx_vslli_w:
3082 case Intrinsic::loongarch_lasx_xvslli_w:
3083 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
3084 lowerVectorSplatImm<5>(N, 2, DAG));
3085 case Intrinsic::loongarch_lsx_vslli_d:
3086 case Intrinsic::loongarch_lasx_xvslli_d:
3087 return DAG.getNode(ISD::SHL, DL, N->getValueType(0), N->getOperand(1),
3088 lowerVectorSplatImm<6>(N, 2, DAG));
3089 case Intrinsic::loongarch_lsx_vsrl_b:
3090 case Intrinsic::loongarch_lsx_vsrl_h:
3091 case Intrinsic::loongarch_lsx_vsrl_w:
3092 case Intrinsic::loongarch_lsx_vsrl_d:
3093 case Intrinsic::loongarch_lasx_xvsrl_b:
3094 case Intrinsic::loongarch_lasx_xvsrl_h:
3095 case Intrinsic::loongarch_lasx_xvsrl_w:
3096 case Intrinsic::loongarch_lasx_xvsrl_d:
3097 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
3098 truncateVecElts(N, DAG));
3099 case Intrinsic::loongarch_lsx_vsrli_b:
3100 case Intrinsic::loongarch_lasx_xvsrli_b:
3101 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
3102 lowerVectorSplatImm<3>(N, 2, DAG));
3103 case Intrinsic::loongarch_lsx_vsrli_h:
3104 case Intrinsic::loongarch_lasx_xvsrli_h:
3105 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
3106 lowerVectorSplatImm<4>(N, 2, DAG));
3107 case Intrinsic::loongarch_lsx_vsrli_w:
3108 case Intrinsic::loongarch_lasx_xvsrli_w:
3109 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
3110 lowerVectorSplatImm<5>(N, 2, DAG));
3111 case Intrinsic::loongarch_lsx_vsrli_d:
3112 case Intrinsic::loongarch_lasx_xvsrli_d:
3113 return DAG.getNode(ISD::SRL, DL, N->getValueType(0), N->getOperand(1),
3114 lowerVectorSplatImm<6>(N, 2, DAG));
3115 case Intrinsic::loongarch_lsx_vsra_b:
3116 case Intrinsic::loongarch_lsx_vsra_h:
3117 case Intrinsic::loongarch_lsx_vsra_w:
3118 case Intrinsic::loongarch_lsx_vsra_d:
3119 case Intrinsic::loongarch_lasx_xvsra_b:
3120 case Intrinsic::loongarch_lasx_xvsra_h:
3121 case Intrinsic::loongarch_lasx_xvsra_w:
3122 case Intrinsic::loongarch_lasx_xvsra_d:
3123 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
3124 truncateVecElts(N, DAG));
3125 case Intrinsic::loongarch_lsx_vsrai_b:
3126 case Intrinsic::loongarch_lasx_xvsrai_b:
3127 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
3128 lowerVectorSplatImm<3>(N, 2, DAG));
3129 case Intrinsic::loongarch_lsx_vsrai_h:
3130 case Intrinsic::loongarch_lasx_xvsrai_h:
3131 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
3132 lowerVectorSplatImm<4>(N, 2, DAG));
3133 case Intrinsic::loongarch_lsx_vsrai_w:
3134 case Intrinsic::loongarch_lasx_xvsrai_w:
3135 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
3136 lowerVectorSplatImm<5>(N, 2, DAG));
3137 case Intrinsic::loongarch_lsx_vsrai_d:
3138 case Intrinsic::loongarch_lasx_xvsrai_d:
3139 return DAG.getNode(ISD::SRA, DL, N->getValueType(0), N->getOperand(1),
3140 lowerVectorSplatImm<6>(N, 2, DAG));
3141 case Intrinsic::loongarch_lsx_vclz_b:
3142 case Intrinsic::loongarch_lsx_vclz_h:
3143 case Intrinsic::loongarch_lsx_vclz_w:
3144 case Intrinsic::loongarch_lsx_vclz_d:
3145 case Intrinsic::loongarch_lasx_xvclz_b:
3146 case Intrinsic::loongarch_lasx_xvclz_h:
3147 case Intrinsic::loongarch_lasx_xvclz_w:
3148 case Intrinsic::loongarch_lasx_xvclz_d:
3149 return DAG.getNode(ISD::CTLZ, DL, N->getValueType(0), N->getOperand(1));
3150 case Intrinsic::loongarch_lsx_vpcnt_b:
3151 case Intrinsic::loongarch_lsx_vpcnt_h:
3152 case Intrinsic::loongarch_lsx_vpcnt_w:
3153 case Intrinsic::loongarch_lsx_vpcnt_d:
3154 case Intrinsic::loongarch_lasx_xvpcnt_b:
3155 case Intrinsic::loongarch_lasx_xvpcnt_h:
3156 case Intrinsic::loongarch_lasx_xvpcnt_w:
3157 case Intrinsic::loongarch_lasx_xvpcnt_d:
3158 return DAG.getNode(ISD::CTPOP, DL, N->getValueType(0), N->getOperand(1));
3159 case Intrinsic::loongarch_lsx_vbitclr_b:
3160 case Intrinsic::loongarch_lsx_vbitclr_h:
3161 case Intrinsic::loongarch_lsx_vbitclr_w:
3162 case Intrinsic::loongarch_lsx_vbitclr_d:
3163 case Intrinsic::loongarch_lasx_xvbitclr_b:
3164 case Intrinsic::loongarch_lasx_xvbitclr_h:
3165 case Intrinsic::loongarch_lasx_xvbitclr_w:
3166 case Intrinsic::loongarch_lasx_xvbitclr_d:
3167 return lowerVectorBitClear(N, DAG);
3168 case Intrinsic::loongarch_lsx_vbitclri_b:
3169 case Intrinsic::loongarch_lasx_xvbitclri_b:
3170 return lowerVectorBitClearImm<3>(N, DAG);
3171 case Intrinsic::loongarch_lsx_vbitclri_h:
3172 case Intrinsic::loongarch_lasx_xvbitclri_h:
3173 return lowerVectorBitClearImm<4>(N, DAG);
3174 case Intrinsic::loongarch_lsx_vbitclri_w:
3175 case Intrinsic::loongarch_lasx_xvbitclri_w:
3176 return lowerVectorBitClearImm<5>(N, DAG);
3177 case Intrinsic::loongarch_lsx_vbitclri_d:
3178 case Intrinsic::loongarch_lasx_xvbitclri_d:
3179 return lowerVectorBitClearImm<6>(N, DAG);
3180 case Intrinsic::loongarch_lsx_vbitset_b:
3181 case Intrinsic::loongarch_lsx_vbitset_h:
3182 case Intrinsic::loongarch_lsx_vbitset_w:
3183 case Intrinsic::loongarch_lsx_vbitset_d:
3184 case Intrinsic::loongarch_lasx_xvbitset_b:
3185 case Intrinsic::loongarch_lasx_xvbitset_h:
3186 case Intrinsic::loongarch_lasx_xvbitset_w:
3187 case Intrinsic::loongarch_lasx_xvbitset_d: {
3188 EVT VecTy = N->getValueType(0);
3189 SDValue One = DAG.getConstant(1, DL, VecTy);
3190 return DAG.getNode(
3191 ISD::OR, DL, VecTy, N->getOperand(1),
3192 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
3193 }
3194 case Intrinsic::loongarch_lsx_vbitseti_b:
3195 case Intrinsic::loongarch_lasx_xvbitseti_b:
3196 return lowerVectorBitSetImm<3>(N, DAG);
3197 case Intrinsic::loongarch_lsx_vbitseti_h:
3198 case Intrinsic::loongarch_lasx_xvbitseti_h:
3199 return lowerVectorBitSetImm<4>(N, DAG);
3200 case Intrinsic::loongarch_lsx_vbitseti_w:
3201 case Intrinsic::loongarch_lasx_xvbitseti_w:
3202 return lowerVectorBitSetImm<5>(N, DAG);
3203 case Intrinsic::loongarch_lsx_vbitseti_d:
3204 case Intrinsic::loongarch_lasx_xvbitseti_d:
3205 return lowerVectorBitSetImm<6>(N, DAG);
3206 case Intrinsic::loongarch_lsx_vbitrev_b:
3207 case Intrinsic::loongarch_lsx_vbitrev_h:
3208 case Intrinsic::loongarch_lsx_vbitrev_w:
3209 case Intrinsic::loongarch_lsx_vbitrev_d:
3210 case Intrinsic::loongarch_lasx_xvbitrev_b:
3211 case Intrinsic::loongarch_lasx_xvbitrev_h:
3212 case Intrinsic::loongarch_lasx_xvbitrev_w:
3213 case Intrinsic::loongarch_lasx_xvbitrev_d: {
3214 EVT VecTy = N->getValueType(0);
3215 SDValue One = DAG.getConstant(1, DL, VecTy);
3216 return DAG.getNode(
3217 ISD::XOR, DL, VecTy, N->getOperand(1),
3218 DAG.getNode(ISD::SHL, DL, VecTy, One, truncateVecElts(N, DAG)));
3219 }
3220 case Intrinsic::loongarch_lsx_vbitrevi_b:
3221 case Intrinsic::loongarch_lasx_xvbitrevi_b:
3222 return lowerVectorBitRevImm<3>(N, DAG);
3223 case Intrinsic::loongarch_lsx_vbitrevi_h:
3224 case Intrinsic::loongarch_lasx_xvbitrevi_h:
3225 return lowerVectorBitRevImm<4>(N, DAG);
3226 case Intrinsic::loongarch_lsx_vbitrevi_w:
3227 case Intrinsic::loongarch_lasx_xvbitrevi_w:
3228 return lowerVectorBitRevImm<5>(N, DAG);
3229 case Intrinsic::loongarch_lsx_vbitrevi_d:
3230 case Intrinsic::loongarch_lasx_xvbitrevi_d:
3231 return lowerVectorBitRevImm<6>(N, DAG);
3232 case Intrinsic::loongarch_lsx_vfadd_s:
3233 case Intrinsic::loongarch_lsx_vfadd_d:
3234 case Intrinsic::loongarch_lasx_xvfadd_s:
3235 case Intrinsic::loongarch_lasx_xvfadd_d:
3236 return DAG.getNode(ISD::FADD, DL, N->getValueType(0), N->getOperand(1),
3237 N->getOperand(2));
3238 case Intrinsic::loongarch_lsx_vfsub_s:
3239 case Intrinsic::loongarch_lsx_vfsub_d:
3240 case Intrinsic::loongarch_lasx_xvfsub_s:
3241 case Intrinsic::loongarch_lasx_xvfsub_d:
3242 return DAG.getNode(ISD::FSUB, DL, N->getValueType(0), N->getOperand(1),
3243 N->getOperand(2));
3244 case Intrinsic::loongarch_lsx_vfmul_s:
3245 case Intrinsic::loongarch_lsx_vfmul_d:
3246 case Intrinsic::loongarch_lasx_xvfmul_s:
3247 case Intrinsic::loongarch_lasx_xvfmul_d:
3248 return DAG.getNode(ISD::FMUL, DL, N->getValueType(0), N->getOperand(1),
3249 N->getOperand(2));
3250 case Intrinsic::loongarch_lsx_vfdiv_s:
3251 case Intrinsic::loongarch_lsx_vfdiv_d:
3252 case Intrinsic::loongarch_lasx_xvfdiv_s:
3253 case Intrinsic::loongarch_lasx_xvfdiv_d:
3254 return DAG.getNode(ISD::FDIV, DL, N->getValueType(0), N->getOperand(1),
3255 N->getOperand(2));
3256 case Intrinsic::loongarch_lsx_vfmadd_s:
3257 case Intrinsic::loongarch_lsx_vfmadd_d:
3258 case Intrinsic::loongarch_lasx_xvfmadd_s:
3259 case Intrinsic::loongarch_lasx_xvfmadd_d:
3260 return DAG.getNode(ISD::FMA, DL, N->getValueType(0), N->getOperand(1),
3261 N->getOperand(2), N->getOperand(3));
3262 case Intrinsic::loongarch_lsx_vinsgr2vr_b:
3263 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
3264 N->getOperand(1), N->getOperand(2),
3265 legalizeIntrinsicImmArg<4>(N, 3, DAG, Subtarget));
3266 case Intrinsic::loongarch_lsx_vinsgr2vr_h:
3267 case Intrinsic::loongarch_lasx_xvinsgr2vr_w:
3268 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
3269 N->getOperand(1), N->getOperand(2),
3270 legalizeIntrinsicImmArg<3>(N, 3, DAG, Subtarget));
3271 case Intrinsic::loongarch_lsx_vinsgr2vr_w:
3272 case Intrinsic::loongarch_lasx_xvinsgr2vr_d:
3273 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
3274 N->getOperand(1), N->getOperand(2),
3275 legalizeIntrinsicImmArg<2>(N, 3, DAG, Subtarget));
3276 case Intrinsic::loongarch_lsx_vinsgr2vr_d:
3277 return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), N->getValueType(0),
3278 N->getOperand(1), N->getOperand(2),
3279 legalizeIntrinsicImmArg<1>(N, 3, DAG, Subtarget));
3280 case Intrinsic::loongarch_lsx_vreplgr2vr_b:
3281 case Intrinsic::loongarch_lsx_vreplgr2vr_h:
3282 case Intrinsic::loongarch_lsx_vreplgr2vr_w:
3283 case Intrinsic::loongarch_lsx_vreplgr2vr_d:
3284 case Intrinsic::loongarch_lasx_xvreplgr2vr_b:
3285 case Intrinsic::loongarch_lasx_xvreplgr2vr_h:
3286 case Intrinsic::loongarch_lasx_xvreplgr2vr_w:
3287 case Intrinsic::loongarch_lasx_xvreplgr2vr_d: {
3288 EVT ResTy = N->getValueType(0);
3289 SmallVector<SDValue> Ops(ResTy.getVectorNumElements(), N->getOperand(1));
3290 return DAG.getBuildVector(ResTy, DL, Ops);
3291 }
3292 case Intrinsic::loongarch_lsx_vreplve_b:
3293 case Intrinsic::loongarch_lsx_vreplve_h:
3294 case Intrinsic::loongarch_lsx_vreplve_w:
3295 case Intrinsic::loongarch_lsx_vreplve_d:
3296 case Intrinsic::loongarch_lasx_xvreplve_b:
3297 case Intrinsic::loongarch_lasx_xvreplve_h:
3298 case Intrinsic::loongarch_lasx_xvreplve_w:
3299 case Intrinsic::loongarch_lasx_xvreplve_d:
3300 return DAG.getNode(LoongArchISD::VREPLVE, DL, N->getValueType(0),
3301 N->getOperand(1),
3302 DAG.getNode(ISD::ANY_EXTEND, DL, Subtarget.getGRLenVT(),
3303 N->getOperand(2)));
3304 }
3305 return SDValue();
3306}
3307
3309 DAGCombinerInfo &DCI) const {
3310 SelectionDAG &DAG = DCI.DAG;
3311 switch (N->getOpcode()) {
3312 default:
3313 break;
3314 case ISD::AND:
3315 return performANDCombine(N, DAG, DCI, Subtarget);
3316 case ISD::OR:
3317 return performORCombine(N, DAG, DCI, Subtarget);
3318 case ISD::SETCC:
3319 return performSETCCCombine(N, DAG, DCI, Subtarget);
3320 case ISD::SRL:
3321 return performSRLCombine(N, DAG, DCI, Subtarget);
3323 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
3325 return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
3326 }
3327 return SDValue();
3328}
3329
3332 if (!ZeroDivCheck)
3333 return MBB;
3334
3335 // Build instructions:
3336 // MBB:
3337 // div(or mod) $dst, $dividend, $divisor
3338 // bnez $divisor, SinkMBB
3339 // BreakMBB:
3340 // break 7 // BRK_DIVZERO
3341 // SinkMBB:
3342 // fallthrough
3343 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
3345 MachineFunction *MF = MBB->getParent();
3346 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
3347 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
3348 MF->insert(It, BreakMBB);
3349 MF->insert(It, SinkMBB);
3350
3351 // Transfer the remainder of MBB and its successor edges to SinkMBB.
3352 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
3353 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
3354
3355 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
3356 DebugLoc DL = MI.getDebugLoc();
3357 MachineOperand &Divisor = MI.getOperand(2);
3358 Register DivisorReg = Divisor.getReg();
3359
3360 // MBB:
3361 BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
3362 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
3363 .addMBB(SinkMBB);
3364 MBB->addSuccessor(BreakMBB);
3365 MBB->addSuccessor(SinkMBB);
3366
3367 // BreakMBB:
3368 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
3369 // definition of BRK_DIVZERO.
3370 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
3371 BreakMBB->addSuccessor(SinkMBB);
3372
3373 // Clear Divisor's kill flag.
3374 Divisor.setIsKill(false);
3375
3376 return SinkMBB;
3377}
3378
3379static MachineBasicBlock *
3381 const LoongArchSubtarget &Subtarget) {
3382 unsigned CondOpc;
3383 switch (MI.getOpcode()) {
3384 default:
3385 llvm_unreachable("Unexpected opcode");
3386 case LoongArch::PseudoVBZ:
3387 CondOpc = LoongArch::VSETEQZ_V;
3388 break;
3389 case LoongArch::PseudoVBZ_B:
3390 CondOpc = LoongArch::VSETANYEQZ_B;
3391 break;
3392 case LoongArch::PseudoVBZ_H:
3393 CondOpc = LoongArch::VSETANYEQZ_H;
3394 break;
3395 case LoongArch::PseudoVBZ_W:
3396 CondOpc = LoongArch::VSETANYEQZ_W;
3397 break;
3398 case LoongArch::PseudoVBZ_D:
3399 CondOpc = LoongArch::VSETANYEQZ_D;
3400 break;
3401 case LoongArch::PseudoVBNZ:
3402 CondOpc = LoongArch::VSETNEZ_V;
3403 break;
3404 case LoongArch::PseudoVBNZ_B:
3405 CondOpc = LoongArch::VSETALLNEZ_B;
3406 break;
3407 case LoongArch::PseudoVBNZ_H:
3408 CondOpc = LoongArch::VSETALLNEZ_H;
3409 break;
3410 case LoongArch::PseudoVBNZ_W:
3411 CondOpc = LoongArch::VSETALLNEZ_W;
3412 break;
3413 case LoongArch::PseudoVBNZ_D:
3414 CondOpc = LoongArch::VSETALLNEZ_D;
3415 break;
3416 case LoongArch::PseudoXVBZ:
3417 CondOpc = LoongArch::XVSETEQZ_V;
3418 break;
3419 case LoongArch::PseudoXVBZ_B:
3420 CondOpc = LoongArch::XVSETANYEQZ_B;
3421 break;
3422 case LoongArch::PseudoXVBZ_H:
3423 CondOpc = LoongArch::XVSETANYEQZ_H;
3424 break;
3425 case LoongArch::PseudoXVBZ_W:
3426 CondOpc = LoongArch::XVSETANYEQZ_W;
3427 break;
3428 case LoongArch::PseudoXVBZ_D:
3429 CondOpc = LoongArch::XVSETANYEQZ_D;
3430 break;
3431 case LoongArch::PseudoXVBNZ:
3432 CondOpc = LoongArch::XVSETNEZ_V;
3433 break;
3434 case LoongArch::PseudoXVBNZ_B:
3435 CondOpc = LoongArch::XVSETALLNEZ_B;
3436 break;
3437 case LoongArch::PseudoXVBNZ_H:
3438 CondOpc = LoongArch::XVSETALLNEZ_H;
3439 break;
3440 case LoongArch::PseudoXVBNZ_W:
3441 CondOpc = LoongArch::XVSETALLNEZ_W;
3442 break;
3443 case LoongArch::PseudoXVBNZ_D:
3444 CondOpc = LoongArch::XVSETALLNEZ_D;
3445 break;
3446 }
3447
3448 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3449 const BasicBlock *LLVM_BB = BB->getBasicBlock();
3450 DebugLoc DL = MI.getDebugLoc();
3453
3454 MachineFunction *F = BB->getParent();
3455 MachineBasicBlock *FalseBB = F->CreateMachineBasicBlock(LLVM_BB);
3456 MachineBasicBlock *TrueBB = F->CreateMachineBasicBlock(LLVM_BB);
3457 MachineBasicBlock *SinkBB = F->CreateMachineBasicBlock(LLVM_BB);
3458
3459 F->insert(It, FalseBB);
3460 F->insert(It, TrueBB);
3461 F->insert(It, SinkBB);
3462
3463 // Transfer the remainder of MBB and its successor edges to Sink.
3464 SinkBB->splice(SinkBB->end(), BB, std::next(MI.getIterator()), BB->end());
3466
3467 // Insert the real instruction to BB.
3468 Register FCC = MRI.createVirtualRegister(&LoongArch::CFRRegClass);
3469 BuildMI(BB, DL, TII->get(CondOpc), FCC).addReg(MI.getOperand(1).getReg());
3470
3471 // Insert branch.
3472 BuildMI(BB, DL, TII->get(LoongArch::BCNEZ)).addReg(FCC).addMBB(TrueBB);
3473 BB->addSuccessor(FalseBB);
3474 BB->addSuccessor(TrueBB);
3475
3476 // FalseBB.
3477 Register RD1 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
3478 BuildMI(FalseBB, DL, TII->get(LoongArch::ADDI_W), RD1)
3479 .addReg(LoongArch::R0)
3480 .addImm(0);
3481 BuildMI(FalseBB, DL, TII->get(LoongArch::PseudoBR)).addMBB(SinkBB);
3482 FalseBB->addSuccessor(SinkBB);
3483
3484 // TrueBB.
3485 Register RD2 = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
3486 BuildMI(TrueBB, DL, TII->get(LoongArch::ADDI_W), RD2)
3487 .addReg(LoongArch::R0)
3488 .addImm(1);
3489 TrueBB->addSuccessor(SinkBB);
3490
3491 // SinkBB: merge the results.
3492 BuildMI(*SinkBB, SinkBB->begin(), DL, TII->get(LoongArch::PHI),
3493 MI.getOperand(0).getReg())
3494 .addReg(RD1)
3495 .addMBB(FalseBB)
3496 .addReg(RD2)
3497 .addMBB(TrueBB);
3498
3499 // The pseudo instruction is gone now.
3500 MI.eraseFromParent();
3501 return SinkBB;
3502}
3503
3504static MachineBasicBlock *
3506 const LoongArchSubtarget &Subtarget) {
3507 unsigned InsOp;
3508 unsigned HalfSize;
3509 switch (MI.getOpcode()) {
3510 default:
3511 llvm_unreachable("Unexpected opcode");
3512 case LoongArch::PseudoXVINSGR2VR_B:
3513 HalfSize = 16;
3514 InsOp = LoongArch::VINSGR2VR_B;
3515 break;
3516 case LoongArch::PseudoXVINSGR2VR_H:
3517 HalfSize = 8;
3518 InsOp = LoongArch::VINSGR2VR_H;
3519 break;
3520 }
3521 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3522 const TargetRegisterClass *RC = &LoongArch::LASX256RegClass;
3523 const TargetRegisterClass *SubRC = &LoongArch::LSX128RegClass;
3524 DebugLoc DL = MI.getDebugLoc();
3526 // XDst = vector_insert XSrc, Elt, Idx
3527 Register XDst = MI.getOperand(0).getReg();
3528 Register XSrc = MI.getOperand(1).getReg();
3529 Register Elt = MI.getOperand(2).getReg();
3530 unsigned Idx = MI.getOperand(3).getImm();
3531
3532 Register ScratchReg1 = XSrc;
3533 if (Idx >= HalfSize) {
3534 ScratchReg1 = MRI.createVirtualRegister(RC);
3535 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), ScratchReg1)
3536 .addReg(XSrc)
3537 .addReg(XSrc)
3538 .addImm(1);
3539 }
3540
3541 Register ScratchSubReg1 = MRI.createVirtualRegister(SubRC);
3542 Register ScratchSubReg2 = MRI.createVirtualRegister(SubRC);
3543 BuildMI(*BB, MI, DL, TII->get(LoongArch::COPY), ScratchSubReg1)
3544 .addReg(ScratchReg1, 0, LoongArch::sub_128);
3545 BuildMI(*BB, MI, DL, TII->get(InsOp), ScratchSubReg2)
3546 .addReg(ScratchSubReg1)
3547 .addReg(Elt)
3548 .addImm(Idx >= HalfSize ? Idx - HalfSize : Idx);
3549
3550 Register ScratchReg2 = XDst;
3551 if (Idx >= HalfSize)
3552 ScratchReg2 = MRI.createVirtualRegister(RC);
3553
3554 BuildMI(*BB, MI, DL, TII->get(LoongArch::SUBREG_TO_REG), ScratchReg2)
3555 .addImm(0)
3556 .addReg(ScratchSubReg2)
3557 .addImm(LoongArch::sub_128);
3558
3559 if (Idx >= HalfSize)
3560 BuildMI(*BB, MI, DL, TII->get(LoongArch::XVPERMI_Q), XDst)
3561 .addReg(XSrc)
3562 .addReg(ScratchReg2)
3563 .addImm(2);
3564
3565 MI.eraseFromParent();
3566 return BB;
3567}
3568
3569MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
3570 MachineInstr &MI, MachineBasicBlock *BB) const {
3571 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
3572 DebugLoc DL = MI.getDebugLoc();
3573
3574 switch (MI.getOpcode()) {
3575 default:
3576 llvm_unreachable("Unexpected instr type to insert");
3577 case LoongArch::DIV_W:
3578 case LoongArch::DIV_WU:
3579 case LoongArch::MOD_W:
3580 case LoongArch::MOD_WU:
3581 case LoongArch::DIV_D:
3582 case LoongArch::DIV_DU:
3583 case LoongArch::MOD_D:
3584 case LoongArch::MOD_DU:
3585 return insertDivByZeroTrap(MI, BB);
3586 break;
3587 case LoongArch::WRFCSR: {
3588 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
3589 LoongArch::FCSR0 + MI.getOperand(0).getImm())
3590 .addReg(MI.getOperand(1).getReg());
3591 MI.eraseFromParent();
3592 return BB;
3593 }
3594 case LoongArch::RDFCSR: {
3595 MachineInstr *ReadFCSR =
3596 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
3597 MI.getOperand(0).getReg())
3598 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
3599 ReadFCSR->getOperand(1).setIsUndef();
3600 MI.eraseFromParent();
3601 return BB;
3602 }
3603 case LoongArch::PseudoVBZ:
3604 case LoongArch::PseudoVBZ_B:
3605 case LoongArch::PseudoVBZ_H:
3606 case LoongArch::PseudoVBZ_W:
3607 case LoongArch::PseudoVBZ_D:
3608 case LoongArch::PseudoVBNZ:
3609 case LoongArch::PseudoVBNZ_B:
3610 case LoongArch::PseudoVBNZ_H:
3611 case LoongArch::PseudoVBNZ_W:
3612 case LoongArch::PseudoVBNZ_D:
3613 case LoongArch::PseudoXVBZ:
3614 case LoongArch::PseudoXVBZ_B:
3615 case LoongArch::PseudoXVBZ_H:
3616 case LoongArch::PseudoXVBZ_W:
3617 case LoongArch::PseudoXVBZ_D:
3618 case LoongArch::PseudoXVBNZ:
3619 case LoongArch::PseudoXVBNZ_B:
3620 case LoongArch::PseudoXVBNZ_H:
3621 case LoongArch::PseudoXVBNZ_W:
3622 case LoongArch::PseudoXVBNZ_D:
3623 return emitVecCondBranchPseudo(MI, BB, Subtarget);
3624 case LoongArch::PseudoXVINSGR2VR_B:
3625 case LoongArch::PseudoXVINSGR2VR_H:
3626 return emitPseudoXVINSGR2VR(MI, BB, Subtarget);
3627 }
3628}
3629
3631 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
3632 unsigned *Fast) const {
3633 if (!Subtarget.hasUAL())
3634 return false;
3635
3636 // TODO: set reasonable speed number.
3637 if (Fast)
3638 *Fast = 1;
3639 return true;
3640}
3641
3642const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
3643 switch ((LoongArchISD::NodeType)Opcode) {
3645 break;
3646
3647#define NODE_NAME_CASE(node) \
3648 case LoongArchISD::node: \
3649 return "LoongArchISD::" #node;
3650
3651 // TODO: Add more target-dependent nodes later.
3652 NODE_NAME_CASE(CALL)
3653 NODE_NAME_CASE(CALL_MEDIUM)
3654 NODE_NAME_CASE(CALL_LARGE)
3655 NODE_NAME_CASE(RET)
3656 NODE_NAME_CASE(TAIL)
3657 NODE_NAME_CASE(TAIL_MEDIUM)
3658 NODE_NAME_CASE(TAIL_LARGE)
3659 NODE_NAME_CASE(SLL_W)
3660 NODE_NAME_CASE(SRA_W)
3661 NODE_NAME_CASE(SRL_W)
3662 NODE_NAME_CASE(BSTRINS)
3663 NODE_NAME_CASE(BSTRPICK)
3664 NODE_NAME_CASE(MOVGR2FR_W_LA64)
3665 NODE_NAME_CASE(MOVFR2GR_S_LA64)
3666 NODE_NAME_CASE(FTINT)
3667 NODE_NAME_CASE(REVB_2H)
3668 NODE_NAME_CASE(REVB_2W)
3669 NODE_NAME_CASE(BITREV_4B)
3670 NODE_NAME_CASE(BITREV_W)
3671 NODE_NAME_CASE(ROTR_W)
3672 NODE_NAME_CASE(ROTL_W)
3673 NODE_NAME_CASE(DIV_WU)
3674 NODE_NAME_CASE(MOD_WU)
3675 NODE_NAME_CASE(CLZ_W)
3676 NODE_NAME_CASE(CTZ_W)
3677 NODE_NAME_CASE(DBAR)
3678 NODE_NAME_CASE(IBAR)
3679 NODE_NAME_CASE(BREAK)
3680 NODE_NAME_CASE(SYSCALL)
3681 NODE_NAME_CASE(CRC_W_B_W)
3682 NODE_NAME_CASE(CRC_W_H_W)
3683 NODE_NAME_CASE(CRC_W_W_W)
3684 NODE_NAME_CASE(CRC_W_D_W)
3685 NODE_NAME_CASE(CRCC_W_B_W)
3686 NODE_NAME_CASE(CRCC_W_H_W)
3687 NODE_NAME_CASE(CRCC_W_W_W)
3688 NODE_NAME_CASE(CRCC_W_D_W)
3689 NODE_NAME_CASE(CSRRD)
3690 NODE_NAME_CASE(CSRWR)
3691 NODE_NAME_CASE(CSRXCHG)
3692 NODE_NAME_CASE(IOCSRRD_B)
3693 NODE_NAME_CASE(IOCSRRD_H)
3694 NODE_NAME_CASE(IOCSRRD_W)
3695 NODE_NAME_CASE(IOCSRRD_D)
3696 NODE_NAME_CASE(IOCSRWR_B)
3697 NODE_NAME_CASE(IOCSRWR_H)
3698 NODE_NAME_CASE(IOCSRWR_W)
3699 NODE_NAME_CASE(IOCSRWR_D)
3700 NODE_NAME_CASE(CPUCFG)
3701 NODE_NAME_CASE(MOVGR2FCSR)
3702 NODE_NAME_CASE(MOVFCSR2GR)
3703 NODE_NAME_CASE(CACOP_D)
3704 NODE_NAME_CASE(CACOP_W)
3705 NODE_NAME_CASE(VPICK_SEXT_ELT)
3706 NODE_NAME_CASE(VPICK_ZEXT_ELT)
3707 NODE_NAME_CASE(VREPLVE)
3708 NODE_NAME_CASE(VALL_ZERO)
3709 NODE_NAME_CASE(VANY_ZERO)
3710 NODE_NAME_CASE(VALL_NONZERO)
3711 NODE_NAME_CASE(VANY_NONZERO)
3712 }
3713#undef NODE_NAME_CASE
3714 return nullptr;
3715}
3716
3717//===----------------------------------------------------------------------===//
3718// Calling Convention Implementation
3719//===----------------------------------------------------------------------===//
3720
3721// Eight general-purpose registers a0-a7 used for passing integer arguments,
3722// with a0-a1 reused to return values. Generally, the GPRs are used to pass
3723// fixed-point arguments, and floating-point arguments when no FPR is available
3724// or with soft float ABI.
3725const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
3726 LoongArch::R7, LoongArch::R8, LoongArch::R9,
3727 LoongArch::R10, LoongArch::R11};
3728// Eight floating-point registers fa0-fa7 used for passing floating-point
3729// arguments, and fa0-fa1 are also used to return values.
3730const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
3731 LoongArch::F3, LoongArch::F4, LoongArch::F5,
3732 LoongArch::F6, LoongArch::F7};
3733// FPR32 and FPR64 alias each other.
3735 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
3736 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
3737
3738const MCPhysReg ArgVRs[] = {LoongArch::VR0, LoongArch::VR1, LoongArch::VR2,
3739 LoongArch::VR3, LoongArch::VR4, LoongArch::VR5,
3740 LoongArch::VR6, LoongArch::VR7};
3741
3742const MCPhysReg ArgXRs[] = {LoongArch::XR0, LoongArch::XR1, LoongArch::XR2,
3743 LoongArch::XR3, LoongArch::XR4, LoongArch::XR5,
3744 LoongArch::XR6, LoongArch::XR7};
3745
3746// Pass a 2*GRLen argument that has been split into two GRLen values through
3747// registers or the stack as necessary.
3748static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
3749 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
3750 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
3751 ISD::ArgFlagsTy ArgFlags2) {
3752 unsigned GRLenInBytes = GRLen / 8;
3753 if (Register Reg = State.AllocateReg(ArgGPRs)) {
3754 // At least one half can be passed via register.
3755 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
3756 VA1.getLocVT(), CCValAssign::Full));
3757 } else {
3758 // Both halves must be passed on the stack, with proper alignment.
3759 Align StackAlign =
3760 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
3761 State.addLoc(
3763 State.AllocateStack(GRLenInBytes, StackAlign),
3764 VA1.getLocVT(), CCValAssign::Full));
3766 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
3767 LocVT2, CCValAssign::Full));
3768 return false;
3769 }
3770 if (Register Reg = State.AllocateReg(ArgGPRs)) {
3771 // The second half can also be passed via register.
3772 State.addLoc(
3773 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
3774 } else {
3775 // The second half is passed via the stack, without additional alignment.
3777 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
3778 LocVT2, CCValAssign::Full));
3779 }
3780 return false;
3781}
3782
3783// Implements the LoongArch calling convention. Returns true upon failure.
3785 unsigned ValNo, MVT ValVT,
3786 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
3787 CCState &State, bool IsFixed, bool IsRet,
3788 Type *OrigTy) {
3789 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
3790 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
3791 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
3792 MVT LocVT = ValVT;
3793
3794 // Any return value split into more than two values can't be returned
3795 // directly.
3796 if (IsRet && ValNo > 1)
3797 return true;
3798
3799 // If passing a variadic argument, or if no FPR is available.
3800 bool UseGPRForFloat = true;
3801
3802 switch (ABI) {
3803 default:
3804 llvm_unreachable("Unexpected ABI");
3805 break;
3810 UseGPRForFloat = !IsFixed;
3811 break;
3814 break;
3815 }
3816
3817 // FPR32 and FPR64 alias each other.
3818 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
3819 UseGPRForFloat = true;
3820
3821 if (UseGPRForFloat && ValVT == MVT::f32) {
3822 LocVT = GRLenVT;
3823 LocInfo = CCValAssign::BCvt;
3824 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
3825 LocVT = MVT::i64;
3826 LocInfo = CCValAssign::BCvt;
3827 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
3828 // TODO: Handle passing f64 on LA32 with D feature.
3829 report_fatal_error("Passing f64 with GPR on LA32 is undefined");
3830 }
3831
3832 // If this is a variadic argument, the LoongArch calling convention requires
3833 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
3834 // byte alignment. An aligned register should be used regardless of whether
3835 // the original argument was split during legalisation or not. The argument
3836 // will not be passed by registers if the original type is larger than
3837 // 2*GRLen, so the register alignment rule does not apply.
3838 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
3839 if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
3840 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
3841 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
3842 // Skip 'odd' register if necessary.
3843 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
3844 State.AllocateReg(ArgGPRs);
3845 }
3846
3847 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
3848 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
3849 State.getPendingArgFlags();
3850
3851 assert(PendingLocs.size() == PendingArgFlags.size() &&
3852 "PendingLocs and PendingArgFlags out of sync");
3853
3854 // Split arguments might be passed indirectly, so keep track of the pending
3855 // values.
3856 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
3857 LocVT = GRLenVT;
3858 LocInfo = CCValAssign::Indirect;
3859 PendingLocs.push_back(
3860 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
3861 PendingArgFlags.push_back(ArgFlags);
3862 if (!ArgFlags.isSplitEnd()) {
3863 return false;
3864 }
3865 }
3866
3867 // If the split argument only had two elements, it should be passed directly
3868 // in registers or on the stack.
3869 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
3870 PendingLocs.size() <= 2) {
3871 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
3872 // Apply the normal calling convention rules to the first half of the
3873 // split argument.
3874 CCValAssign VA = PendingLocs[0];
3875 ISD::ArgFlagsTy AF = PendingArgFlags[0];
3876 PendingLocs.clear();
3877 PendingArgFlags.clear();
3878 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
3879 ArgFlags);
3880 }
3881
3882 // Allocate to a register if possible, or else a stack slot.
3883 Register Reg;
3884 unsigned StoreSizeBytes = GRLen / 8;
3885 Align StackAlign = Align(GRLen / 8);
3886
3887 if (ValVT == MVT::f32 && !UseGPRForFloat)
3888 Reg = State.AllocateReg(ArgFPR32s);
3889 else if (ValVT == MVT::f64 && !UseGPRForFloat)
3890 Reg = State.AllocateReg(ArgFPR64s);
3891 else if (ValVT.is128BitVector())
3892 Reg = State.AllocateReg(ArgVRs);
3893 else if (ValVT.is256BitVector())
3894 Reg = State.AllocateReg(ArgXRs);
3895 else
3896 Reg = State.AllocateReg(ArgGPRs);
3897
3898 unsigned StackOffset =
3899 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
3900
3901 // If we reach this point and PendingLocs is non-empty, we must be at the
3902 // end of a split argument that must be passed indirectly.
3903 if (!PendingLocs.empty()) {
3904 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
3905 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
3906 for (auto &It : PendingLocs) {
3907 if (Reg)
3908 It.convertToReg(Reg);
3909 else
3910 It.convertToMem(StackOffset);
3911 State.addLoc(It);
3912 }
3913 PendingLocs.clear();
3914 PendingArgFlags.clear();
3915 return false;
3916 }
3917 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
3918 "Expected an GRLenVT at this stage");
3919
3920 if (Reg) {
3921 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
3922 return false;
3923 }
3924
3925 // When a floating-point value is passed on the stack, no bit-cast is needed.
3926 if (ValVT.isFloatingPoint()) {
3927 LocVT = ValVT;
3928 LocInfo = CCValAssign::Full;
3929 }
3930
3931 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
3932 return false;
3933}
3934
3935void LoongArchTargetLowering::analyzeInputArgs(
3936 MachineFunction &MF, CCState &CCInfo,
3937 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
3938 LoongArchCCAssignFn Fn) const {
3940 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
3941 MVT ArgVT = Ins[i].VT;
3942 Type *ArgTy = nullptr;
3943 if (IsRet)
3944 ArgTy = FType->getReturnType();
3945 else if (Ins[i].isOrigArg())
3946 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
3949 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
3950 CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
3951 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << ArgVT
3952 << '\n');
3953 llvm_unreachable("");
3954 }
3955 }
3956}
3957
3958void LoongArchTargetLowering::analyzeOutputArgs(
3959 MachineFunction &MF, CCState &CCInfo,
3960 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
3961 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
3962 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
3963 MVT ArgVT = Outs[i].VT;
3964 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
3967 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
3968 CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
3969 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << ArgVT
3970 << "\n");
3971 llvm_unreachable("");
3972 }
3973 }
3974}
3975
3976// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
3977// values.
3979 const CCValAssign &VA, const SDLoc &DL) {
3980 switch (VA.getLocInfo()) {
3981 default:
3982 llvm_unreachable("Unexpected CCValAssign::LocInfo");
3983 case CCValAssign::Full:
3985 break;
3986 case CCValAssign::BCvt:
3987 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
3988 Val = DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, Val);
3989 else
3990 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
3991 break;
3992 }
3993 return Val;
3994}
3995
3997 const CCValAssign &VA, const SDLoc &DL,
3998 const ISD::InputArg &In,
3999 const LoongArchTargetLowering &TLI) {
4002 EVT LocVT = VA.getLocVT();
4003 SDValue Val;
4004 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
4005 Register VReg = RegInfo.createVirtualRegister(RC);
4006 RegInfo.addLiveIn(VA.getLocReg(), VReg);
4007 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
4008
4009 // If input is sign extended from 32 bits, note it for the OptW pass.
4010 if (In.isOrigArg()) {
4011 Argument *OrigArg = MF.getFunction().getArg(In.getOrigArgIndex());
4012 if (OrigArg->getType()->isIntegerTy()) {
4013 unsigned BitWidth = OrigArg->getType()->getIntegerBitWidth();
4014 // An input zero extended from i31 can also be considered sign extended.
4015 if ((BitWidth <= 32 && In.Flags.isSExt()) ||
4016 (BitWidth < 32 && In.Flags.isZExt())) {
4019 LAFI->addSExt32Register(VReg);
4020 }
4021 }
4022 }
4023
4024 return convertLocVTToValVT(DAG, Val, VA, DL);
4025}
4026
4027// The caller is responsible for loading the full value if the argument is
4028// passed with CCValAssign::Indirect.
4030 const CCValAssign &VA, const SDLoc &DL) {
4032 MachineFrameInfo &MFI = MF.getFrameInfo();
4033 EVT ValVT = VA.getValVT();
4034 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
4035 /*IsImmutable=*/true);
4036 SDValue FIN = DAG.getFrameIndex(
4038
4039 ISD::LoadExtType ExtType;
4040 switch (VA.getLocInfo()) {
4041 default:
4042 llvm_unreachable("Unexpected CCValAssign::LocInfo");
4043 case CCValAssign::Full:
4045 case CCValAssign::BCvt:
4046 ExtType = ISD::NON_EXTLOAD;
4047 break;
4048 }
4049 return DAG.getExtLoad(
4050 ExtType, DL, VA.getLocVT(), Chain, FIN,
4052}
4053
4055 const CCValAssign &VA, const SDLoc &DL) {
4056 EVT LocVT = VA.getLocVT();
4057
4058 switch (VA.getLocInfo()) {
4059 default:
4060 llvm_unreachable("Unexpected CCValAssign::LocInfo");
4061 case CCValAssign::Full:
4062 break;
4063 case CCValAssign::BCvt:
4064 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
4065 Val = DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Val);
4066 else
4067 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
4068 break;
4069 }
4070 return Val;
4071}
4072
4073static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
4074 CCValAssign::LocInfo LocInfo,
4075 ISD::ArgFlagsTy ArgFlags, CCState &State) {
4076 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
4077 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
4078 // s0 s1 s2 s3 s4 s5 s6 s7 s8
4079 static const MCPhysReg GPRList[] = {
4080 LoongArch::R23, LoongArch::R24, LoongArch::R25,
4081 LoongArch::R26, LoongArch::R27, LoongArch::R28,
4082 LoongArch::R29, LoongArch::R30, LoongArch::R31};
4083 if (unsigned Reg = State.AllocateReg(GPRList)) {
4084 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
4085 return false;
4086 }
4087 }
4088
4089 if (LocVT == MVT::f32) {
4090 // Pass in STG registers: F1, F2, F3, F4
4091 // fs0,fs1,fs2,fs3
4092 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
4093 LoongArch::F26, LoongArch::F27};
4094 if (unsigned Reg = State.AllocateReg(FPR32List)) {
4095 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
4096 return false;
4097 }
4098 }
4099
4100 if (LocVT == MVT::f64) {
4101 // Pass in STG registers: D1, D2, D3, D4
4102 // fs4,fs5,fs6,fs7
4103 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
4104 LoongArch::F30_64, LoongArch::F31_64};
4105 if (unsigned Reg = State.AllocateReg(FPR64List)) {
4106 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
4107 return false;
4108 }
4109 }
4110
4111 report_fatal_error("No registers left in GHC calling convention");
4112 return true;
4113}
4114
4115// Transform physical registers into virtual registers.
4117 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
4118 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
4119 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
4120
4122
4123 switch (CallConv) {
4124 default:
4125 llvm_unreachable("Unsupported calling convention");
4126 case CallingConv::C:
4127 case CallingConv::Fast:
4128 break;
4129 case CallingConv::GHC:
4130 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
4131 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
4133 "GHC calling convention requires the F and D extensions");
4134 }
4135
4136 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4137 MVT GRLenVT = Subtarget.getGRLenVT();
4138 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
4139 // Used with varargs to acumulate store chains.
4140 std::vector<SDValue> OutChains;
4141
4142 // Assign locations to all of the incoming arguments.
4144 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
4145
4146 if (CallConv == CallingConv::GHC)
4148 else
4149 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
4150
4151 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
4152 CCValAssign &VA = ArgLocs[i];
4153 SDValue ArgValue;
4154 if (VA.isRegLoc())
4155 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, Ins[i], *this);
4156 else
4157 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
4158 if (VA.getLocInfo() == CCValAssign::Indirect) {
4159 // If the original argument was split and passed by reference, we need to
4160 // load all parts of it here (using the same address).
4161 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
4163 unsigned ArgIndex = Ins[i].OrigArgIndex;
4164 unsigned ArgPartOffset = Ins[i].PartOffset;
4165 assert(ArgPartOffset == 0);
4166 while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
4167 CCValAssign &PartVA = ArgLocs[i + 1];
4168 unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
4169 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
4170 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
4171 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
4173 ++i;
4174 }
4175 continue;
4176 }
4177 InVals.push_back(ArgValue);
4178 }
4179
4180 if (IsVarArg) {
4182 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
4183 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
4184 MachineFrameInfo &MFI = MF.getFrameInfo();
4185 MachineRegisterInfo &RegInfo = MF.getRegInfo();
4186 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
4187
4188 // Offset of the first variable argument from stack pointer, and size of
4189 // the vararg save area. For now, the varargs save area is either zero or
4190 // large enough to hold a0-a7.
4191 int VaArgOffset, VarArgsSaveSize;
4192
4193 // If all registers are allocated, then all varargs must be passed on the
4194 // stack and we don't need to save any argregs.
4195 if (ArgRegs.size() == Idx) {
4196 VaArgOffset = CCInfo.getStackSize();
4197 VarArgsSaveSize = 0;
4198 } else {
4199 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
4200 VaArgOffset = -VarArgsSaveSize;
4201 }
4202
4203 // Record the frame index of the first variable argument
4204 // which is a value necessary to VASTART.
4205 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
4206 LoongArchFI->setVarArgsFrameIndex(FI);
4207
4208 // If saving an odd number of registers then create an extra stack slot to
4209 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
4210 // offsets to even-numbered registered remain 2*GRLen-aligned.
4211 if (Idx % 2) {
4212 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
4213 true);
4214 VarArgsSaveSize += GRLenInBytes;
4215 }
4216
4217 // Copy the integer registers that may have been used for passing varargs
4218 // to the vararg save area.
4219 for (unsigned I = Idx; I < ArgRegs.size();
4220 ++I, VaArgOffset += GRLenInBytes) {
4221 const Register Reg = RegInfo.createVirtualRegister(RC);
4222 RegInfo.addLiveIn(ArgRegs[I], Reg);
4223 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
4224 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
4225 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4226 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
4228 cast<StoreSDNode>(Store.getNode())
4229 ->getMemOperand()
4230 ->setValue((Value *)nullptr);
4231 OutChains.push_back(Store);
4232 }
4233 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
4234 }
4235
4236 // All stores are grouped in one node to allow the matching between
4237 // the size of Ins and InVals. This only happens for vararg functions.
4238 if (!OutChains.empty()) {
4239 OutChains.push_back(Chain);
4240 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
4241 }
4242
4243 return Chain;
4244}
4245
4247 return CI->isTailCall();
4248}
4249
4250// Check if the return value is used as only a return value, as otherwise
4251// we can't perform a tail-call.
4253 SDValue &Chain) const {
4254 if (N->getNumValues() != 1)
4255 return false;
4256 if (!N->hasNUsesOfValue(1, 0))
4257 return false;
4258
4259 SDNode *Copy = *N->use_begin();
4260 if (Copy->getOpcode() != ISD::CopyToReg)
4261 return false;
4262
4263 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
4264 // isn't safe to perform a tail call.
4265 if (Copy->getGluedNode())
4266 return false;
4267
4268 // The copy must be used by a LoongArchISD::RET, and nothing else.
4269 bool HasRet = false;
4270 for (SDNode *Node : Copy->uses()) {
4271 if (Node->getOpcode() != LoongArchISD::RET)
4272 return false;
4273 HasRet = true;
4274 }
4275
4276 if (!HasRet)
4277 return false;
4278
4279 Chain = Copy->getOperand(0);
4280 return true;
4281}
4282
4283// Check whether the call is eligible for tail call optimization.
4284bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
4285 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
4286 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
4287
4288 auto CalleeCC = CLI.CallConv;
4289 auto &Outs = CLI.Outs;
4290 auto &Caller = MF.getFunction();
4291 auto CallerCC = Caller.getCallingConv();
4292
4293 // Do not tail call opt if the stack is used to pass parameters.
4294 if (CCInfo.getStackSize() != 0)
4295 return false;
4296
4297 // Do not tail call opt if any parameters need to be passed indirectly.
4298 for (auto &VA : ArgLocs)
4299 if (VA.getLocInfo() == CCValAssign::Indirect)
4300 return false;
4301
4302 // Do not tail call opt if either caller or callee uses struct return
4303 // semantics.
4304 auto IsCallerStructRet = Caller.hasStructRetAttr();
4305 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
4306 if (IsCallerStructRet || IsCalleeStructRet)
4307 return false;
4308
4309 // Do not tail call opt if either the callee or caller has a byval argument.
4310 for (auto &Arg : Outs)
4311 if (Arg.Flags.isByVal())
4312 return false;
4313
4314 // The callee has to preserve all registers the caller needs to preserve.
4315 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
4316 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
4317 if (CalleeCC != CallerCC) {
4318 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
4319 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
4320 return false;
4321 }
4322 return true;
4323}
4324
4326 return DAG.getDataLayout().getPrefTypeAlign(
4327 VT.getTypeForEVT(*DAG.getContext()));
4328}
4329
4330// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
4331// and output parameter nodes.
4332SDValue
4334 SmallVectorImpl<SDValue> &InVals) const {
4335 SelectionDAG &DAG = CLI.DAG;
4336 SDLoc &DL = CLI.DL;
4338 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
4340 SDValue Chain = CLI.Chain;
4341 SDValue Callee = CLI.Callee;
4342 CallingConv::ID CallConv = CLI.CallConv;
4343 bool IsVarArg = CLI.IsVarArg;
4344 EVT PtrVT = getPointerTy(DAG.getDataLayout());
4345 MVT GRLenVT = Subtarget.getGRLenVT();
4346 bool &IsTailCall = CLI.IsTailCall;
4347
4349
4350 // Analyze the operands of the call, assigning locations to each operand.
4352 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
4353
4354 if (CallConv == CallingConv::GHC)
4355 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
4356 else
4357 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
4358
4359 // Check if it's really possible to do a tail call.
4360 if (IsTailCall)
4361 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
4362
4363 if (IsTailCall)
4364 ++NumTailCalls;
4365 else if (CLI.CB && CLI.CB->isMustTailCall())
4366 report_fatal_error("failed to perform tail call elimination on a call "
4367 "site marked musttail");
4368
4369 // Get a count of how many bytes are to be pushed on the stack.
4370 unsigned NumBytes = ArgCCInfo.getStackSize();
4371
4372 // Create local copies for byval args.
4373 SmallVector<SDValue> ByValArgs;
4374 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
4375 ISD::ArgFlagsTy Flags = Outs[i].Flags;
4376 if (!Flags.isByVal())
4377 continue;
4378
4379 SDValue Arg = OutVals[i];
4380 unsigned Size = Flags.getByValSize();
4381 Align Alignment = Flags.getNonZeroByValAlign();
4382
4383 int FI =
4384 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
4385 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
4386 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
4387
4388 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
4389 /*IsVolatile=*/false,
4390 /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
4392 ByValArgs.push_back(FIPtr);
4393 }
4394
4395 if (!IsTailCall)
4396 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
4397
4398 // Copy argument values to their designated locations.
4400 SmallVector<SDValue> MemOpChains;
4401 SDValue StackPtr;
4402 for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
4403 CCValAssign &VA = ArgLocs[i];
4404 SDValue ArgValue = OutVals[i];
4405 ISD::ArgFlagsTy Flags = Outs[i].Flags;
4406
4407 // Promote the value if needed.
4408 // For now, only handle fully promoted and indirect arguments.
4409 if (VA.getLocInfo() == CCValAssign::Indirect) {
4410 // Store the argument in a stack slot and pass its address.
4411 Align StackAlign =
4412 std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
4413 getPrefTypeAlign(ArgValue.getValueType(), DAG));
4414 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
4415 // If the original argument was split and passed by reference, we need to
4416 // store the required parts of it here (and pass just one address).
4417 unsigned ArgIndex = Outs[i].OrigArgIndex;
4418 unsigned ArgPartOffset = Outs[i].PartOffset;
4419 assert(ArgPartOffset == 0);
4420 // Calculate the total size to store. We don't have access to what we're
4421 // actually storing other than performing the loop and collecting the
4422 // info.
4424 while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
4425 SDValue PartValue = OutVals[i + 1];
4426 unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
4427 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
4428 EVT PartVT = PartValue.getValueType();
4429
4430 StoredSize += PartVT.getStoreSize();
4431 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
4432 Parts.push_back(std::make_pair(PartValue, Offset));
4433 ++i;
4434 }
4435 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
4436 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
4437 MemOpChains.push_back(
4438 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
4440 for (const auto &Part : Parts) {
4441 SDValue PartValue = Part.first;
4442 SDValue PartOffset = Part.second;
4444 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
4445 MemOpChains.push_back(
4446 DAG.getStore(Chain, DL, PartValue, Address,
4448 }
4449 ArgValue = SpillSlot;
4450 } else {
4451 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
4452 }
4453
4454 // Use local copy if it is a byval arg.
4455 if (Flags.isByVal())
4456 ArgValue = ByValArgs[j++];
4457
4458 if (VA.isRegLoc()) {
4459 // Queue up the argument copies and emit them at the end.
4460 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
4461 } else {
4462 assert(VA.isMemLoc() && "Argument not register or memory");
4463 assert(!IsTailCall && "Tail call not allowed if stack is used "
4464 "for passing parameters");
4465
4466 // Work out the address of the stack slot.
4467 if (!StackPtr.getNode())
4468 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
4470 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
4472
4473 // Emit the store.
4474 MemOpChains.push_back(
4475 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
4476 }
4477 }
4478
4479 // Join the stores, which are independent of one another.
4480 if (!MemOpChains.empty())
4481 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
4482
4483 SDValue Glue;
4484
4485 // Build a sequence of copy-to-reg nodes, chained and glued together.
4486 for (auto &Reg : RegsToPass) {
4487 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
4488 Glue = Chain.getValue(1);
4489 }
4490
4491 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
4492 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
4493 // split it and then direct call can be matched by PseudoCALL.
4494 if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
4495 const GlobalValue *GV = S->getGlobal();
4496 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(GV)
4499 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
4500 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
4501 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(nullptr)
4504 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
4505 }
4506
4507 // The first call operand is the chain and the second is the target address.
4509 Ops.push_back(Chain);
4510 Ops.push_back(Callee);
4511
4512 // Add argument registers to the end of the list so that they are
4513 // known live into the call.
4514 for (auto &Reg : RegsToPass)
4515 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
4516
4517 if (!IsTailCall) {
4518 // Add a register mask operand representing the call-preserved registers.
4519 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
4520 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
4521 assert(Mask && "Missing call preserved mask for calling convention");
4522 Ops.push_back(DAG.getRegisterMask(Mask));
4523 }
4524
4525 // Glue the call to the argument copies, if any.
4526 if (Glue.getNode())
4527 Ops.push_back(Glue);
4528
4529 // Emit the call.
4530 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
4531 unsigned Op;
4532 switch (DAG.getTarget().getCodeModel()) {
4533 default:
4534 report_fatal_error("Unsupported code model");
4535 case CodeModel::Small:
4536 Op = IsTailCall ? LoongArchISD::TAIL : LoongArchISD::CALL;
4537 break;
4538 case CodeModel::Medium:
4539 assert(Subtarget.is64Bit() && "Medium code model requires LA64");
4541 break;
4542 case CodeModel::Large:
4543 assert(Subtarget.is64Bit() && "Large code model requires LA64");
4545 break;
4546 }
4547
4548 if (IsTailCall) {
4550 SDValue Ret = DAG.getNode(Op, DL, NodeTys, Ops);
4551 DAG.addNoMergeSiteInfo(Ret.getNode(), CLI.NoMerge);
4552 return Ret;
4553 }
4554
4555 Chain = DAG.getNode(Op, DL, NodeTys, Ops);
4556 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
4557 Glue = Chain.getValue(1);
4558
4559 // Mark the end of the call, which is glued to the call itself.
4560 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
4561 Glue = Chain.getValue(1);
4562
4563 // Assign locations to each value returned by this call.
4565 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
4566 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
4567
4568 // Copy all of the result registers out of their specified physreg.
4569 for (auto &VA : RVLocs) {
4570 // Copy the value out.
4571 SDValue RetValue =
4572 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
4573 // Glue the RetValue to the end of the call sequence.
4574 Chain = RetValue.getValue(1);
4575 Glue = RetValue.getValue(2);
4576
4577 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
4578
4579 InVals.push_back(RetValue);
4580 }
4581
4582 return Chain;
4583}
4584
4586 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
4587 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
4589 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
4590
4591 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
4592 LoongArchABI::ABI ABI =
4593 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
4594 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
4595 Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
4596 nullptr))
4597 return false;
4598 }
4599 return true;
4600}
4601
4603 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
4605 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
4606 SelectionDAG &DAG) const {
4607 // Stores the assignment of the return value to a location.
4609
4610 // Info about the registers and stack slot.
4611 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
4612 *DAG.getContext());
4613
4614 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
4615 nullptr, CC_LoongArch);
4616 if (CallConv == CallingConv::GHC && !RVLocs.empty())
4617 report_fatal_error("GHC functions return void only");
4618 SDValue Glue;
4619 SmallVector<SDValue, 4> RetOps(1, Chain);
4620
4621 // Copy the result values into the output registers.
4622 for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
4623 CCValAssign &VA = RVLocs[i];
4624 assert(VA.isRegLoc() && "Can only return in registers!");
4625
4626 // Handle a 'normal' return.
4627 SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
4628 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
4629
4630 // Guarantee that all emitted copies are stuck together.
4631 Glue = Chain.getValue(1);
4632 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
4633 }
4634
4635 RetOps[0] = Chain; // Update chain.
4636
4637 // Add the glue node if we have it.
4638 if (Glue.getNode())
4639 RetOps.push_back(Glue);
4640
4641 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
4642}
4643
4644bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
4645 bool ForCodeSize) const {
4646 // TODO: Maybe need more checks here after vector extension is supported.
4647 if (VT == MVT::f32 && !Subtarget.hasBasicF())
4648 return false;
4649 if (VT == MVT::f64 && !Subtarget.hasBasicD())
4650 return false;
4651 return (Imm.isZero() || Imm.isExactlyValue(+1.0));
4652}
4653
4655 return true;
4656}
4657
4659 return true;
4660}
4661
4662bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
4663 const Instruction *I) const {
4664 if (!Subtarget.is64Bit())
4665 return isa<LoadInst>(I) || isa<StoreInst>(I);
4666
4667 if (isa<LoadInst>(I))
4668 return true;
4669
4670 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
4671 // require fences beacuse we can use amswap_db.[w/d].
4672 if (isa<StoreInst>(I)) {
4673 unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
4674 return (Size == 8 || Size == 16);
4675 }
4676
4677 return false;
4678}
4679
4681 LLVMContext &Context,
4682 EVT VT) const {
4683 if (!VT.isVector())
4684 return getPointerTy(DL);
4686}
4687
4689 // TODO: Support vectors.
4690 return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
4691}
4692
4694 const CallInst &I,
4695 MachineFunction &MF,
4696 unsigned Intrinsic) const {
4697 switch (Intrinsic) {
4698 default:
4699 return false;
4700 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
4701 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
4702 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
4703 case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
4705 Info.memVT = MVT::i32;
4706 Info.ptrVal = I.getArgOperand(0);
4707 Info.offset = 0;
4708 Info.align = Align(4);
4711 return true;
4712 // TODO: Add more Intrinsics later.
4713 }
4714}
4715
4718 // TODO: Add more AtomicRMWInst that needs to be extended.
4719
4720 // Since floating-point operation requires a non-trivial set of data
4721 // operations, use CmpXChg to expand.
4722 if (AI->isFloatingPointOperation() ||
4726
4727 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
4728 if (Size == 8 || Size == 16)
4731}
4732
4733static Intrinsic::ID
4735 AtomicRMWInst::BinOp BinOp) {
4736 if (GRLen == 64) {
4737 switch (BinOp) {
4738 default:
4739 llvm_unreachable("Unexpected AtomicRMW BinOp");
4741 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
4742 case AtomicRMWInst::Add:
4743 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
4744 case AtomicRMWInst::Sub:
4745 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
4747 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
4749 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
4751 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
4752 case AtomicRMWInst::Max:
4753 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
4754 case AtomicRMWInst::Min:
4755 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
4756 // TODO: support other AtomicRMWInst.
4757 }
4758 }
4759
4760 if (GRLen == 32) {
4761 switch (BinOp) {
4762 default:
4763 llvm_unreachable("Unexpected AtomicRMW BinOp");
4765 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
4766 case AtomicRMWInst::Add:
4767 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
4768 case AtomicRMWInst::Sub:
4769 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
4771 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
4772 // TODO: support other AtomicRMWInst.
4773 }
4774 }
4775
4776 llvm_unreachable("Unexpected GRLen\n");
4777}
4778
4781 AtomicCmpXchgInst *CI) const {
4783 if (Size == 8 || Size == 16)
4786}
4787
4789 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
4790 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
4791 AtomicOrdering FailOrd = CI->getFailureOrdering();
4792 Value *FailureOrdering =
4793 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(FailOrd));
4794
4795 // TODO: Support cmpxchg on LA32.
4796 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
4797 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
4798 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
4799 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
4800 Type *Tys[] = {AlignedAddr->getType()};
4801 Function *MaskedCmpXchg =
4802 Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
4803 Value *Result = Builder.CreateCall(
4804 MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, FailureOrdering});
4805 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
4806 return Result;
4807}
4808
4810 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
4811 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
4812 // In the case of an atomicrmw xchg with a constant 0/-1 operand, replace
4813 // the atomic instruction with an AtomicRMWInst::And/Or with appropriate
4814 // mask, as this produces better code than the LL/SC loop emitted by
4815 // int_loongarch_masked_atomicrmw_xchg.
4816 if (AI->getOperation() == AtomicRMWInst::Xchg &&
4817 isa<ConstantInt>(AI->getValOperand())) {
4818 ConstantInt *CVal = cast<ConstantInt>(AI->getValOperand());
4819 if (CVal->isZero())
4820 return Builder.CreateAtomicRMW(AtomicRMWInst::And, AlignedAddr,
4821 Builder.CreateNot(Mask, "Inv_Mask"),
4822 AI->getAlign(), Ord);
4823 if (CVal->isMinusOne())
4824 return Builder.CreateAtomicRMW(AtomicRMWInst::Or, AlignedAddr, Mask,
4825 AI->getAlign(), Ord);
4826 }
4827
4828 unsigned GRLen = Subtarget.getGRLen();
4829 Value *Ordering =
4830 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
4831 Type *Tys[] = {AlignedAddr->getType()};
4832 Function *LlwOpScwLoop = Intrinsic::getDeclaration(
4833 AI->getModule(),
4835
4836 if (GRLen == 64) {
4837 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
4838 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
4839 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
4840 }
4841
4842 Value *Result;
4843
4844 // Must pass the shift amount needed to sign extend the loaded value prior
4845 // to performing a signed comparison for min/max. ShiftAmt is the number of
4846 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
4847 // is the number of bits to left+right shift the value in order to
4848 // sign-extend.
4849 if (AI->getOperation() == AtomicRMWInst::Min ||
4851 const DataLayout &DL = AI->getDataLayout();
4852 unsigned ValWidth =
4853 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
4854 Value *SextShamt =
4855 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
4856 Result = Builder.CreateCall(LlwOpScwLoop,
4857 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
4858 } else {
4859 Result =
4860 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
4861 }
4862
4863 if (GRLen == 64)
4864 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
4865 return Result;
4866}
4867
4869 const MachineFunction &MF, EVT VT) const {
4870 VT = VT.getScalarType();
4871
4872 if (!VT.isSimple())
4873 return false;
4874
4875 switch (VT.getSimpleVT().SimpleTy) {
4876 case MVT::f32:
4877 case MVT::f64:
4878 return true;
4879 default:
4880 break;
4881 }
4882
4883 return false;
4884}
4885
4887 const Constant *PersonalityFn) const {
4888 return LoongArch::R4;
4889}
4890
4892 const Constant *PersonalityFn) const {
4893 return LoongArch::R5;
4894}
4895
4896//===----------------------------------------------------------------------===//
4897// LoongArch Inline Assembly Support
4898//===----------------------------------------------------------------------===//
4899
4901LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
4902 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
4903 //
4904 // 'f': A floating-point register (if available).
4905 // 'k': A memory operand whose address is formed by a base register and
4906 // (optionally scaled) index register.
4907 // 'l': A signed 16-bit constant.
4908 // 'm': A memory operand whose address is formed by a base register and
4909 // offset that is suitable for use in instructions with the same
4910 // addressing mode as st.w and ld.w.
4911 // 'I': A signed 12-bit constant (for arithmetic instructions).
4912 // 'J': Integer zero.
4913 // 'K': An unsigned 12-bit constant (for logic instructions).
4914 // "ZB": An address that is held in a general-purpose register. The offset is
4915 // zero.
4916 // "ZC": A memory operand whose address is formed by a base register and
4917 // offset that is suitable for use in instructions with the same
4918 // addressing mode as ll.w and sc.w.
4919 if (Constraint.size() == 1) {
4920 switch (Constraint[0]) {
4921 default:
4922 break;
4923 case 'f':
4924 return C_RegisterClass;
4925 case 'l':
4926 case 'I':
4927 case 'J':
4928 case 'K':
4929 return C_Immediate;
4930 case 'k':
4931 return C_Memory;
4932 }
4933 }
4934
4935 if (Constraint == "ZC" || Constraint == "ZB")
4936 return C_Memory;
4937
4938 // 'm' is handled here.
4939 return TargetLowering::getConstraintType(Constraint);
4940}
4941
4942InlineAsm::ConstraintCode LoongArchTargetLowering::getInlineAsmMemConstraint(
4943 StringRef ConstraintCode) const {
4944 return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
4949}
4950
4951std::pair<unsigned, const TargetRegisterClass *>
4952LoongArchTargetLowering::getRegForInlineAsmConstraint(
4953 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
4954 // First, see if this is a constraint that directly corresponds to a LoongArch
4955 // register class.
4956 if (Constraint.size() == 1) {
4957 switch (Constraint[0]) {
4958 case 'r':
4959 // TODO: Support fixed vectors up to GRLen?
4960 if (VT.isVector())
4961 break;
4962 return std::make_pair(0U, &LoongArch::GPRRegClass);
4963 case 'f':
4964 if (Subtarget.hasBasicF() && VT == MVT::f32)
4965 return std::make_pair(0U, &LoongArch::FPR32RegClass);
4966 if (Subtarget.hasBasicD() && VT == MVT::f64)
4967 return std::make_pair(0U, &LoongArch::FPR64RegClass);
4968 if (Subtarget.hasExtLSX() &&
4969 TRI->isTypeLegalForClass(LoongArch::LSX128RegClass, VT))
4970 return std::make_pair(0U, &LoongArch::LSX128RegClass);
4971 if (Subtarget.hasExtLASX() &&
4972 TRI->isTypeLegalForClass(LoongArch::LASX256RegClass, VT))
4973 return std::make_pair(0U, &LoongArch::LASX256RegClass);
4974 break;
4975 default:
4976 break;
4977 }
4978 }
4979
4980 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
4981 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
4982 // constraints while the official register name is prefixed with a '$'. So we
4983 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
4984 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
4985 // case insensitive, so no need to convert the constraint to upper case here.
4986 //
4987 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
4988 // decode the usage of register name aliases into their official names. And
4989 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
4990 // official register names.
4991 if (Constraint.starts_with("{$r") || Constraint.starts_with("{$f") ||
4992 Constraint.starts_with("{$vr") || Constraint.starts_with("{$xr")) {
4993 bool IsFP = Constraint[2] == 'f';
4994 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
4995 std::pair<unsigned, const TargetRegisterClass *> R;
4997 TRI, join_items("", Temp.first, Temp.second), VT);
4998 // Match those names to the widest floating point register type available.
4999 if (IsFP) {
5000 unsigned RegNo = R.first;
5001 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
5002 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
5003 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
5004 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
5005 }
5006 }
5007 }
5008 return R;
5009 }
5010
5011 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
5012}
5013
5014void LoongArchTargetLowering::LowerAsmOperandForConstraint(
5015 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
5016 SelectionDAG &DAG) const {
5017 // Currently only support length 1 constraints.
5018 if (Constraint.size() == 1) {
5019 switch (Constraint[0]) {
5020 case 'l':
5021 // Validate & create a 16-bit signed immediate operand.
5022 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5023 uint64_t CVal = C->getSExtValue();
5024 if (isInt<16>(CVal))
5025 Ops.push_back(
5026 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5027 }
5028 return;
5029 case 'I':
5030 // Validate & create a 12-bit signed immediate operand.
5031 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5032 uint64_t CVal = C->getSExtValue();
5033 if (isInt<12>(CVal))
5034 Ops.push_back(
5035 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5036 }
5037 return;
5038 case 'J':
5039 // Validate & create an integer zero operand.
5040 if (auto *C = dyn_cast<ConstantSDNode>(Op))
5041 if (C->getZExtValue() == 0)
5042 Ops.push_back(
5043 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
5044 return;
5045 case 'K':
5046 // Validate & create a 12-bit unsigned immediate operand.
5047 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
5048 uint64_t CVal = C->getZExtValue();
5049 if (isUInt<12>(CVal))
5050 Ops.push_back(
5051 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
5052 }
5053 return;
5054 default:
5055 break;
5056 }
5057 }
5058 TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
5059}
5060
5061#define GET_REGISTER_MATCHER
5062#include "LoongArchGenAsmMatcher.inc"
5063
5066 const MachineFunction &MF) const {
5067 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
5068 std::string NewRegName = Name.second.str();
5069 Register Reg = MatchRegisterAltName(NewRegName);
5070 if (Reg == LoongArch::NoRegister)
5071 Reg = MatchRegisterName(NewRegName);
5072 if (Reg == LoongArch::NoRegister)
5074 Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
5075 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
5076 if (!ReservedRegs.test(Reg))
5077 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
5078 StringRef(RegName) + "\"."));
5079 return Reg;
5080}
5081
5083 EVT VT, SDValue C) const {
5084 // TODO: Support vectors.
5085 if (!VT.isScalarInteger())
5086 return false;
5087
5088 // Omit the optimization if the data size exceeds GRLen.
5089 if (VT.getSizeInBits() > Subtarget.getGRLen())
5090 return false;
5091
5092 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
5093 const APInt &Imm = ConstNode->getAPIntValue();
5094 // Break MUL into (SLLI + ADD/SUB) or ALSL.
5095 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
5096 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
5097 return true;
5098 // Break MUL into (ALSL x, (SLLI x, imm0), imm1).
5099 if (ConstNode->hasOneUse() &&
5100 ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() ||
5101 (Imm - 8).isPowerOf2() || (Imm - 16).isPowerOf2()))
5102 return true;
5103 // Break (MUL x, imm) into (ADD (SLLI x, s0), (SLLI x, s1)),
5104 // in which the immediate has two set bits. Or Break (MUL x, imm)
5105 // into (SUB (SLLI x, s0), (SLLI x, s1)), in which the immediate
5106 // equals to (1 << s0) - (1 << s1).
5107 if (ConstNode->hasOneUse() && !(Imm.sge(-2048) && Imm.sle(4095))) {
5108 unsigned Shifts = Imm.countr_zero();
5109 // Reject immediates which can be composed via a single LUI.
5110 if (Shifts >= 12)
5111 return false;
5112 // Reject multiplications can be optimized to
5113 // (SLLI (ALSL x, x, 1/2/3/4), s).
5114 APInt ImmPop = Imm.ashr(Shifts);
5115 if (ImmPop == 3 || ImmPop == 5 || ImmPop == 9 || ImmPop == 17)
5116 return false;
5117 // We do not consider the case `(-Imm - ImmSmall).isPowerOf2()`,
5118 // since it needs one more instruction than other 3 cases.
5119 APInt ImmSmall = APInt(Imm.getBitWidth(), 1ULL << Shifts, true);
5120 if ((Imm - ImmSmall).isPowerOf2() || (Imm + ImmSmall).isPowerOf2() ||
5121 (ImmSmall - Imm).isPowerOf2())
5122 return true;
5123 }
5124 }
5125
5126 return false;
5127}
5128
5130 const AddrMode &AM,
5131 Type *Ty, unsigned AS,
5132 Instruction *I) const {
5133 // LoongArch has four basic addressing modes:
5134 // 1. reg
5135 // 2. reg + 12-bit signed offset
5136 // 3. reg + 14-bit signed offset left-shifted by 2
5137 // 4. reg1 + reg2
5138 // TODO: Add more checks after support vector extension.
5139
5140 // No global is ever allowed as a base.
5141 if (AM.BaseGV)
5142 return false;
5143
5144 // Require a 12-bit signed offset or 14-bit signed offset left-shifted by 2
5145 // with `UAL` feature.
5146 if (!isInt<12>(AM.BaseOffs) &&
5147 !(isShiftedInt<14, 2>(AM.BaseOffs) && Subtarget.hasUAL()))
5148 return false;
5149
5150 switch (AM.Scale) {
5151 case 0:
5152 // "r+i" or just "i", depending on HasBaseReg.
5153 break;
5154 case 1:
5155 // "r+r+i" is not allowed.
5156 if (AM.HasBaseReg && AM.BaseOffs)
5157 return false;
5158 // Otherwise we have "r+r" or "r+i".
5159 break;
5160 case 2:
5161 // "2*r+r" or "2*r+i" is not allowed.
5162 if (AM.HasBaseReg || AM.BaseOffs)
5163 return false;
5164 // Allow "2*r" as "r+r".
5165 break;
5166 default:
5167 return false;
5168 }
5169
5170 return true;
5171}
5172
5174 return isInt<12>(Imm);
5175}
5176
5178 return isInt<12>(Imm);
5179}
5180
5182 // Zexts are free if they can be combined with a load.
5183 // Don't advertise i32->i64 zextload as being free for LA64. It interacts
5184 // poorly with type legalization of compares preferring sext.
5185 if (auto *LD = dyn_cast<LoadSDNode>(Val)) {
5186 EVT MemVT = LD->getMemoryVT();
5187 if ((MemVT == MVT::i8 || MemVT == MVT::i16) &&
5188 (LD->getExtensionType() == ISD::NON_EXTLOAD ||
5189 LD->getExtensionType() == ISD::ZEXTLOAD))
5190 return true;
5191 }
5192
5193 return TargetLowering::isZExtFree(Val, VT2);
5194}
5195
5197 EVT DstVT) const {
5198 return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64;
5199}
5200
5202 return Subtarget.is64Bit() && CI->getType()->isIntegerTy(32);
5203}
5204
5206 // TODO: Support vectors.
5207 if (Y.getValueType().isVector())
5208 return false;
5209
5210 return !isa<ConstantSDNode>(Y);
5211}
5212
5214 // TODO: LAMCAS will use amcas{_DB,}.[bhwd] which does not require extension.
5215 return ISD::SIGN_EXTEND;
5216}
5217
5219 EVT Type, bool IsSigned) const {
5220 if (Subtarget.is64Bit() && Type == MVT::i32)
5221 return true;
5222
5223 return IsSigned;
5224}
5225
5227 // Return false to suppress the unnecessary extensions if the LibCall
5228 // arguments or return value is a float narrower than GRLEN on a soft FP ABI.
5229 if (Subtarget.isSoftFPABI() && (Type.isFloatingPoint() && !Type.isVector() &&
5230 Type.getSizeInBits() < Subtarget.getGRLen()))
5231 return false;
5232 return true;
5233}
unsigned const MachineRegisterInfo * MRI
static MCRegister MatchRegisterName(StringRef Name)
static bool checkValueWidth(SDValue V, unsigned width, ISD::LoadExtType &ExtType)
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const AArch64Subtarget *Subtarget, const AArch64TargetLowering &TLI)
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SDValue performSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG)
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
#define NODE_NAME_CASE(node)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG, unsigned Flags)
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
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 SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Addr
std::string Name
uint64_t Size
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define RegName(no)
static SDValue performINTRINSIC_WO_CHAINCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
const MCPhysReg ArgFPR32s[]
const MCPhysReg ArgVRs[]
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static void emitErrorAndReplaceIntrinsicResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, StringRef ErrorMsg, bool WithChain=true)
static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorBitSetImm(SDNode *Node, SelectionDAG &DAG)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static SDValue lowerVectorBitRevImm(SDNode *Node, SelectionDAG &DAG)
static SDValue truncateVecElts(SDNode *Node, SelectionDAG &DAG)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG)
static SDValue lowerVectorBitClear(SDNode *Node, SelectionDAG &DAG)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
static void replaceVPICKVE2GRResults(SDNode *Node, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, unsigned ResOp)
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget, bool IsSigned=false)
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)
const MCPhysReg ArgFPR64s[]
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
static MachineBasicBlock * emitPseudoXVINSGR2VR(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue lowerVectorSplatImm(SDNode *Node, unsigned ImmOp, SelectionDAG &DAG, bool IsSigned=false)
const MCPhysReg ArgGPRs[]
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 bool isConstantOrUndef(const SDValue Op)
static MachineBasicBlock * emitVecCondBranchPseudo(MachineInstr &MI, MachineBasicBlock *BB, const LoongArchSubtarget &Subtarget)
static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRRD_CASE(NAME, NODE)
static SDValue lowerVectorBitClearImm(SDNode *Node, SelectionDAG &DAG)
static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op)
static void replaceINTRINSIC_WO_CHAINResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG, const LoongArchSubtarget &Subtarget)
#define CSR_CASE(ID)
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode)
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO)
const char LLVMTargetMachineRef TM
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:167
This file contains some functions that are useful when dealing with strings.
Class for arbitrary precision integers.
Definition: APInt.h:78
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition: APInt.h:1237
This class represents an incoming formal argument to a Function.
Definition: Argument.h:31
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
An instruction that atomically checks whether a specified value is in a memory location,...
Definition: Instructions.h:495
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
Definition: Instructions.h:586
an instruction that atomically reads a memory location, combines it with another value,...
Definition: Instructions.h:696
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
Definition: Instructions.h:809
BinOp
This enumeration lists the possible modifications atomicrmw can make.
Definition: Instructions.h:708
@ Add
*p = old + v
Definition: Instructions.h:712
@ Min
*p = old <signed v ? old : v
Definition: Instructions.h:726
@ Or
*p = old | v
Definition: Instructions.h:720
@ Sub
*p = old - v
Definition: Instructions.h:714
@ And
*p = old & v
Definition: Instructions.h:716
@ UIncWrap
Increment one up to a maximum value.
Definition: Instructions.h:748
@ Max
*p = old >signed v ? old : v
Definition: Instructions.h:724
@ UMin
*p = old <unsigned v ? old : v
Definition: Instructions.h:730
@ UMax
*p = old >unsigned v ? old : v
Definition: Instructions.h:728
@ UDecWrap
Decrement one until a minimum value or zero.
Definition: Instructions.h:752
@ Nand
*p = ~(old & v)
Definition: Instructions.h:718
bool isFloatingPointOperation() const
Definition: Instructions.h:864
BinOp getOperation() const
Definition: Instructions.h:787
Value * getValOperand()
Definition: Instructions.h:856
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
Definition: Instructions.h:829
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
bool test(unsigned Idx) const
Definition: BitVector.h:461
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,...
SmallVectorImpl< ISD::ArgFlagsTy > & getPendingArgFlags()
MCRegister AllocateReg(MCPhysReg Reg)
AllocateReg - Attempt to allocate one register.
int64_t AllocateStack(unsigned Size, Align Alignment)
AllocateStack - Allocate a chunk of stack space with the specified size and alignment.
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.
SmallVectorImpl< CCValAssign > & getPendingLocs()
void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
void addLoc(const CCValAssign &V)
CCValAssign - Represent assignment of one arg/retval to a location.
bool isRegLoc() const
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getMem(unsigned ValNo, MVT ValVT, int64_t Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
static CCValAssign getReg(unsigned ValNo, MVT ValVT, unsigned RegNo, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool isMemLoc() const
int64_t getLocMemOffset() const
unsigned getValNo() const
bool isMustTailCall() const
Tests if this call site must be tail call optimized.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
This is the shared class of boolean and integer constants.
Definition: Constants.h:81
bool isMinusOne() const
This function will return true iff every bit in this constant is set to true.
Definition: Constants.h:218
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition: Constants.h:206
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition: Constant.h:42
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:110
unsigned getPointerSizeInBits(unsigned AS=0) const
Layout pointer size, in bits FIXME: The defaults need to be removed once all of the backends/clients ...
Definition: DataLayout.h:410
Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
Definition: DataLayout.cpp:874
A debug info location.
Definition: DebugLoc.h:33
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:207
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition: Function.h:274
Argument * getArg(unsigned i) const
Definition: Function.h:849
bool isDSOLocal() const
Definition: GlobalValue.h:305
Common base class shared among various IRBuilders.
Definition: IRBuilder.h:91
Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:2038
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition: IRBuilder.h:523
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
Definition: IRBuilder.h:528
Value * CreateNot(Value *V, const Twine &Name="")
Definition: IRBuilder.h:1754
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1349
ConstantInt * getIntN(unsigned N, uint64_t C)
Get a constant N-bit value, zero extended or truncated from a 64-bit value.
Definition: IRBuilder.h:494
AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)
Definition: IRBuilder.h:1859
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
Definition: IRBuilder.h:2012
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2417
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Definition: Instruction.cpp:66
const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Definition: Instruction.cpp:74
Class to represent integer types.
Definition: DerivedTypes.h:40
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void emitError(uint64_t LocCookie, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
This class is used to represent ISD::LOAD nodes.
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...
const LoongArchRegisterInfo * getRegisterInfo() const override
const LoongArchInstrInfo * getInstrInfo() const override
unsigned getMaxBytesForAlignment() const
Align getPrefFunctionAlignment() const
bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override
Return true if result of the specified node is used by a return node only.
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override
This method will be invoked for all target nodes and for any target-independent nodes that the target...
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(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.
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.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override
Return true if sign-extension from FromTy to ToTy is cheaper than zero-extension.
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
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 shouldSignExtendTypeInLibCall(EVT Type, bool IsSigned) const override
Returns true if arguments should be sign-extended in lib calls.
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...
Register getExceptionPointerRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
bool signExtendConstant(const ConstantInt *CI) const override
Return true if this constant should be sign extended when promoting to a larger type.
const char * getTargetNodeName(unsigned Opcode) const override
This method returns the name of a target specific DAG node.
bool getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &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 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...
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.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
Register getExceptionSelectorRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
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 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.
bool hasFeature(unsigned Feature) const
Machine Value Type.
bool is128BitVector() const
Return true if this is a 128-bit vector type.
SimpleValueType SimpleTy
bool isVector() const
Return true if this is a vector value type.
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.
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *FromMBB)
Transfers all the successors, as in transferSuccessors, and update PHI operands in the successor bloc...
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
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 '...
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
Definition: MachineInstr.h:69
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:579
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.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void addLiveIn(MCRegister Reg, Register vreg=Register())
addLiveIn - Add the specified register as a live-in.
EVT getMemoryVT() const
Return the type of the in-memory value.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
size_t use_size() const
Return the number of uses of this node.
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
const SDValue & getOperand(unsigned Num) const
EVT getValueType(unsigned ResNo) const
Return the type of a specified result.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
Definition: SelectionDAG.h:227
SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:734
SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
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),...
SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, std::optional< bool > OverrideTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), AAResults *AA=nullptr)
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false)
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr)
Loads are not normal binary operators: their result type is not determined by their operands,...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
const TargetLowering & getTargetLoweringInfo() const
Definition: SelectionDAG.h:492
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
Definition: SelectionDAG.h:744
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.
Definition: SelectionDAG.h:840
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.
void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
const DataLayout & getDataLayout() const
Definition: SelectionDAG.h:486
SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
void ReplaceAllUsesWith(SDValue From, SDValue To)
Modify anything using 'From' to use 'To' instead.
SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
Helper function to build ISD::STORE nodes.
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 ...
SDValue getRegister(unsigned Reg, EVT VT)
SDValue getExternalSymbol(const char *Sym, EVT VT)
const TargetMachine & getTarget() const
Definition: SelectionDAG.h:487
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, SDValue N)
Definition: SelectionDAG.h:785
SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
SDValue getValueType(EVT)
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)
Definition: SelectionDAG.h:688
SDValue getTargetBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:780
MachineFunction & getMachineFunction() const
Definition: SelectionDAG.h:481
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT)
Definition: SelectionDAG.h:811
SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
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.
SDValue getRegisterMask(const uint32_t *RegMask)
LLVMContext * getContext() const
Definition: SelectionDAG.h:499
SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
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)
Definition: SelectionDAG.h:751
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
Definition: SelectionDAG.h:568
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StackOffset holds a fixed and a scalable offset in bytes.
Definition: TypeSize.h:33
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:685
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:250
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
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...
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 bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
void setMaxBytesForAlignment(unsigned MaxBytes)
void setPrefLoopAlignment(Align Alignment)
Set the target's preferred loop alignment.
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
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.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setPrefFunctionAlignment(Align Alignment)
Set the target's preferred function alignment.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
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
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const
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 verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:77
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:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
unsigned getIntegerBitWidth() const
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:228
TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
This class is used to represent EVT's, which are used to parameterize some operations.
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
self_iterator getIterator()
Definition: ilist_node.h:132
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ Entry
Definition: COFF.h:811
@ 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
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition: ISDOpcodes.h:40
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition: ISDOpcodes.h:778
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
Definition: ISDOpcodes.h:1167
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
Definition: ISDOpcodes.h:1163
@ STRICT_FSETCC
STRICT_FSETCC/STRICT_FSETCCS - Constrained versions of SETCC, used for floating-point operands only.
Definition: ISDOpcodes.h:490
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition: ISDOpcodes.h:257
@ BSWAP
Byte Swap and Counting operators.
Definition: ISDOpcodes.h:742
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
Definition: ISDOpcodes.h:1196
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:246
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
Definition: ISDOpcodes.h:1072
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition: ISDOpcodes.h:811
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition: ISDOpcodes.h:497
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition: ISDOpcodes.h:205
@ GlobalAddress
Definition: ISDOpcodes.h:78
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition: ISDOpcodes.h:818
@ FADD
Simple binary floating point operators.
Definition: ISDOpcodes.h:397
@ MEMBARRIER
MEMBARRIER - Compiler barrier only; generate a no-op.
Definition: ISDOpcodes.h:1269
@ ATOMIC_FENCE
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
Definition: ISDOpcodes.h:1274
@ STRICT_FSETCCS
Definition: ISDOpcodes.h:491
@ FP16_TO_FP
FP16_TO_FP, FP_TO_FP16 - These operators are used to perform promotions and truncation for half-preci...
Definition: ISDOpcodes.h:941
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
Definition: ISDOpcodes.h:931
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
Definition: ISDOpcodes.h:1451
@ GlobalTLSAddress
Definition: ISDOpcodes.h:79
@ SIGN_EXTEND
Conversion operators.
Definition: ISDOpcodes.h:802
@ WRITE_REGISTER
Definition: ISDOpcodes.h:125
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
Definition: ISDOpcodes.h:1029
@ FNEG
Perform various unary floating-point operations inspired by libm.
Definition: ISDOpcodes.h:958
@ BR_CC
BR_CC - Conditional branch.
Definition: ISDOpcodes.h:1118
@ BR_JT
BR_JT - Jumptable branch.
Definition: ISDOpcodes.h:1097
@ IS_FPCLASS
Performs a check of floating point class property, defined by IEEE-754.
Definition: ISDOpcodes.h:521
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition: ISDOpcodes.h:755
@ UNDEF
UNDEF - An undefined node.
Definition: ISDOpcodes.h:218
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
Definition: ISDOpcodes.h:1192
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition: ISDOpcodes.h:673
@ SHL
Shift and rotation operations.
Definition: ISDOpcodes.h:733
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition: ISDOpcodes.h:614
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Perform floating-point minimumNumber or maximumNumber on two values,...
Definition: ISDOpcodes.h:1019
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition: ISDOpcodes.h:124
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition: ISDOpcodes.h:549
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition: ISDOpcodes.h:209
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition: ISDOpcodes.h:808
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
Definition: ISDOpcodes.h:1252
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition: ISDOpcodes.h:770
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
Definition: ISDOpcodes.h:1082
@ ConstantPool
Definition: ISDOpcodes.h:82
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition: ISDOpcodes.h:826
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition: ISDOpcodes.h:696
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition: ISDOpcodes.h:764
@ EH_DWARF_CFA
EH_DWARF_CFA - This node represents the pointer to the DWARF Canonical Frame Address (CFA),...
Definition: ISDOpcodes.h:135
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition: ISDOpcodes.h:100
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition: ISDOpcodes.h:864
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:708
@ TRAP
TRAP - Trapping instruction.
Definition: ISDOpcodes.h:1249
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition: ISDOpcodes.h:190
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition: ISDOpcodes.h:538
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition: ISDOpcodes.h:52
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition: ISDOpcodes.h:814
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
Definition: ISDOpcodes.h:1187
@ BlockAddress
Definition: ISDOpcodes.h:84
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition: ISDOpcodes.h:791
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition: ISDOpcodes.h:61
@ AssertZext
Definition: ISDOpcodes.h:62
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:198
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition: ISDOpcodes.h:529
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
Definition: ISDOpcodes.h:1574
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
Definition: ISDOpcodes.h:1554
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1513
ABI getTargetABI(StringRef ABIName)
Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Libcall
RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.
Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* 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:54
@ GeneralDynamic
Definition: CodeGen.h:46
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
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:285
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition: MathExtras.h:193
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Other
Any other memory.
unsigned getKillRegState(bool B)
DWARFExpression::Operation Op
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:191
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Extended Value Type.
Definition: ValueTypes.h:34
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition: ValueTypes.h:93
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition: ValueTypes.h:380
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition: ValueTypes.h:136
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition: ValueTypes.h:358
uint64_t getScalarSizeInBits() const
Definition: ValueTypes.h:370
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:306
bool is128BitVector() const
Return true if this is a 128-bit vector type.
Definition: ValueTypes.h:203
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition: ValueTypes.h:366
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition: ValueTypes.h:58
bool isVector() const
Return true if this is a vector value type.
Definition: ValueTypes.h:167
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition: ValueTypes.h:313
bool is256BitVector() const
Return true if this is a 256-bit vector type.
Definition: ValueTypes.h:208
Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
Definition: ValueTypes.cpp:203
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition: ValueTypes.h:318
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition: ValueTypes.h:156
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition: ValueTypes.h:326
Align getNonZeroOrigAlign() const
InputArg - This struct carries flags and type information about a single incoming (formal) argument o...
Register getFrameRegister(const MachineFunction &MF) const override
BitVector getReservedRegs(const MachineFunction &MF) const override
This class contains a discriminated union of information about pointers in memory operands,...
static MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
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
SmallVector< SDValue, 32 > OutVals
This structure is used to pass arguments to makeLibCall function.
MakeLibCallOptions & setTypeListBeforeSoften(ArrayRef< EVT > OpsVT, EVT RetVT, bool Value=true)