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