xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
10b57cec5SDimitry Andric //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines an instruction selector for the RISCV target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
135ffd83dbSDimitry Andric #include "RISCVISelDAGToDAG.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h"
15e8d8bef9SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h"
16fe6060f1SDimitry Andric #include "RISCVISelLowering.h"
17fe6060f1SDimitry Andric #include "RISCVMachineFunctionInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
19e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h"
205ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h"
210b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
22fe6060f1SDimitry Andric #include "llvm/Support/KnownBits.h"
230b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
255ffd83dbSDimitry Andric 
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel"
290b57cec5SDimitry Andric 
30fe6060f1SDimitry Andric namespace llvm {
31fe6060f1SDimitry Andric namespace RISCV {
32fe6060f1SDimitry Andric #define GET_RISCVVSSEGTable_IMPL
33fe6060f1SDimitry Andric #define GET_RISCVVLSEGTable_IMPL
34fe6060f1SDimitry Andric #define GET_RISCVVLXSEGTable_IMPL
35fe6060f1SDimitry Andric #define GET_RISCVVSXSEGTable_IMPL
36fe6060f1SDimitry Andric #define GET_RISCVVLETable_IMPL
37fe6060f1SDimitry Andric #define GET_RISCVVSETable_IMPL
38fe6060f1SDimitry Andric #define GET_RISCVVLXTable_IMPL
39fe6060f1SDimitry Andric #define GET_RISCVVSXTable_IMPL
40fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc"
41fe6060f1SDimitry Andric } // namespace RISCV
42fe6060f1SDimitry Andric } // namespace llvm
43fe6060f1SDimitry Andric 
44fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() {
45fe6060f1SDimitry Andric   for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
46fe6060f1SDimitry Andric                                        E = CurDAG->allnodes_end();
47fe6060f1SDimitry Andric        I != E;) {
48fe6060f1SDimitry Andric     SDNode *N = &*I++; // Preincrement iterator to avoid invalidation issues.
49fe6060f1SDimitry Andric 
50fe6060f1SDimitry Andric     // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector
51fe6060f1SDimitry Andric     // load. Done after lowering and combining so that we have a chance to
52fe6060f1SDimitry Andric     // optimize this to VMV_V_X_VL when the upper bits aren't needed.
53fe6060f1SDimitry Andric     if (N->getOpcode() != RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL)
54fe6060f1SDimitry Andric       continue;
55fe6060f1SDimitry Andric 
56fe6060f1SDimitry Andric     assert(N->getNumOperands() == 3 && "Unexpected number of operands");
57fe6060f1SDimitry Andric     MVT VT = N->getSimpleValueType(0);
58fe6060f1SDimitry Andric     SDValue Lo = N->getOperand(0);
59fe6060f1SDimitry Andric     SDValue Hi = N->getOperand(1);
60fe6060f1SDimitry Andric     SDValue VL = N->getOperand(2);
61fe6060f1SDimitry Andric     assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() &&
62fe6060f1SDimitry Andric            Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 &&
63fe6060f1SDimitry Andric            "Unexpected VTs!");
64fe6060f1SDimitry Andric     MachineFunction &MF = CurDAG->getMachineFunction();
65fe6060f1SDimitry Andric     RISCVMachineFunctionInfo *FuncInfo = MF.getInfo<RISCVMachineFunctionInfo>();
66fe6060f1SDimitry Andric     SDLoc DL(N);
67fe6060f1SDimitry Andric 
68fe6060f1SDimitry Andric     // We use the same frame index we use for moving two i32s into 64-bit FPR.
69fe6060f1SDimitry Andric     // This is an analogous operation.
70fe6060f1SDimitry Andric     int FI = FuncInfo->getMoveF64FrameIndex(MF);
71fe6060f1SDimitry Andric     MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI);
72fe6060f1SDimitry Andric     const TargetLowering &TLI = CurDAG->getTargetLoweringInfo();
73fe6060f1SDimitry Andric     SDValue StackSlot =
74fe6060f1SDimitry Andric         CurDAG->getFrameIndex(FI, TLI.getPointerTy(CurDAG->getDataLayout()));
75fe6060f1SDimitry Andric 
76fe6060f1SDimitry Andric     SDValue Chain = CurDAG->getEntryNode();
77fe6060f1SDimitry Andric     Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8));
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric     SDValue OffsetSlot =
80fe6060f1SDimitry Andric         CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::Fixed(4), DL);
81fe6060f1SDimitry Andric     Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4),
82fe6060f1SDimitry Andric                           Align(8));
83fe6060f1SDimitry Andric 
84fe6060f1SDimitry Andric     Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi);
85fe6060f1SDimitry Andric 
86fe6060f1SDimitry Andric     SDVTList VTs = CurDAG->getVTList({VT, MVT::Other});
87fe6060f1SDimitry Andric     SDValue IntID =
88fe6060f1SDimitry Andric         CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64);
89*04eeddc0SDimitry Andric     SDValue Ops[] = {Chain,
90*04eeddc0SDimitry Andric                      IntID,
91*04eeddc0SDimitry Andric                      CurDAG->getUNDEF(VT),
92*04eeddc0SDimitry Andric                      StackSlot,
93*04eeddc0SDimitry Andric                      CurDAG->getRegister(RISCV::X0, MVT::i64),
94*04eeddc0SDimitry Andric                      VL};
95fe6060f1SDimitry Andric 
96fe6060f1SDimitry Andric     SDValue Result = CurDAG->getMemIntrinsicNode(
97fe6060f1SDimitry Andric         ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, MVT::i64, MPI, Align(8),
98fe6060f1SDimitry Andric         MachineMemOperand::MOLoad);
99fe6060f1SDimitry Andric 
100fe6060f1SDimitry Andric     // We're about to replace all uses of the SPLAT_VECTOR_SPLIT_I64 with the
101fe6060f1SDimitry Andric     // vlse we created.  This will cause general havok on the dag because
102fe6060f1SDimitry Andric     // anything below the conversion could be folded into other existing nodes.
103fe6060f1SDimitry Andric     // To avoid invalidating 'I', back it up to the convert node.
104fe6060f1SDimitry Andric     --I;
105fe6060f1SDimitry Andric     CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result);
106fe6060f1SDimitry Andric 
107fe6060f1SDimitry Andric     // Now that we did that, the node is dead.  Increment the iterator to the
108fe6060f1SDimitry Andric     // next node to process, then delete N.
109fe6060f1SDimitry Andric     ++I;
110fe6060f1SDimitry Andric     CurDAG->DeleteNode(N);
111fe6060f1SDimitry Andric   }
112fe6060f1SDimitry Andric }
113fe6060f1SDimitry Andric 
1140b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() {
115349cc55cSDimitry Andric   SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
116349cc55cSDimitry Andric 
117349cc55cSDimitry Andric   bool MadeChange = false;
118349cc55cSDimitry Andric   while (Position != CurDAG->allnodes_begin()) {
119349cc55cSDimitry Andric     SDNode *N = &*--Position;
120349cc55cSDimitry Andric     // Skip dead nodes and any non-machine opcodes.
121349cc55cSDimitry Andric     if (N->use_empty() || !N->isMachineOpcode())
122349cc55cSDimitry Andric       continue;
123349cc55cSDimitry Andric 
124349cc55cSDimitry Andric     MadeChange |= doPeepholeSExtW(N);
125349cc55cSDimitry Andric     MadeChange |= doPeepholeLoadStoreADDI(N);
126349cc55cSDimitry Andric   }
127349cc55cSDimitry Andric 
128349cc55cSDimitry Andric   if (MadeChange)
129349cc55cSDimitry Andric     CurDAG->RemoveDeadNodes();
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
132*04eeddc0SDimitry Andric static SDNode *selectImmWithConstantPool(SelectionDAG *CurDAG, const SDLoc &DL,
133*04eeddc0SDimitry Andric                                          const MVT VT, int64_t Imm,
134fe6060f1SDimitry Andric                                          const RISCVSubtarget &Subtarget) {
135*04eeddc0SDimitry Andric   assert(VT == MVT::i64 && "Expecting MVT::i64");
136*04eeddc0SDimitry Andric   const RISCVTargetLowering *TLI = Subtarget.getTargetLowering();
137*04eeddc0SDimitry Andric   ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(CurDAG->getConstantPool(
138*04eeddc0SDimitry Andric       ConstantInt::get(EVT(VT).getTypeForEVT(*CurDAG->getContext()), Imm), VT));
139*04eeddc0SDimitry Andric   SDValue Addr = TLI->getAddr(CP, *CurDAG);
140*04eeddc0SDimitry Andric   SDValue Offset = CurDAG->getTargetConstant(0, DL, VT);
141*04eeddc0SDimitry Andric   // Since there is no data race, the chain can be the entry node.
142*04eeddc0SDimitry Andric   SDNode *Load = CurDAG->getMachineNode(RISCV::LD, DL, VT, Addr, Offset,
143*04eeddc0SDimitry Andric                                         CurDAG->getEntryNode());
144*04eeddc0SDimitry Andric   MachineFunction &MF = CurDAG->getMachineFunction();
145*04eeddc0SDimitry Andric   MachineMemOperand *MemOp = MF.getMachineMemOperand(
146*04eeddc0SDimitry Andric       MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad,
147*04eeddc0SDimitry Andric       LLT(VT), CP->getAlign());
148*04eeddc0SDimitry Andric   CurDAG->setNodeMemRefs(cast<MachineSDNode>(Load), {MemOp});
149*04eeddc0SDimitry Andric   return Load;
150*04eeddc0SDimitry Andric }
151*04eeddc0SDimitry Andric 
152*04eeddc0SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
153*04eeddc0SDimitry Andric                          int64_t Imm, const RISCVSubtarget &Subtarget) {
154fe6060f1SDimitry Andric   MVT XLenVT = Subtarget.getXLenVT();
155fe6060f1SDimitry Andric   RISCVMatInt::InstSeq Seq =
156fe6060f1SDimitry Andric       RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits());
1570b57cec5SDimitry Andric 
158*04eeddc0SDimitry Andric   // If Imm is expensive to build, then we put it into constant pool.
159*04eeddc0SDimitry Andric   if (Subtarget.useConstantPoolForLargeInts() &&
160*04eeddc0SDimitry Andric       Seq.size() > Subtarget.getMaxBuildIntsCost())
161*04eeddc0SDimitry Andric     return selectImmWithConstantPool(CurDAG, DL, VT, Imm, Subtarget);
162*04eeddc0SDimitry Andric 
1638bcb0991SDimitry Andric   SDNode *Result = nullptr;
1640b57cec5SDimitry Andric   SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT);
1650b57cec5SDimitry Andric   for (RISCVMatInt::Inst &Inst : Seq) {
1660b57cec5SDimitry Andric     SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT);
1670b57cec5SDimitry Andric     if (Inst.Opc == RISCV::LUI)
1680b57cec5SDimitry Andric       Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm);
169fe6060f1SDimitry Andric     else if (Inst.Opc == RISCV::ADDUW)
170fe6060f1SDimitry Andric       Result = CurDAG->getMachineNode(RISCV::ADDUW, DL, XLenVT, SrcReg,
171fe6060f1SDimitry Andric                                       CurDAG->getRegister(RISCV::X0, XLenVT));
172349cc55cSDimitry Andric     else if (Inst.Opc == RISCV::SH1ADD || Inst.Opc == RISCV::SH2ADD ||
173349cc55cSDimitry Andric              Inst.Opc == RISCV::SH3ADD)
174349cc55cSDimitry Andric       Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SrcReg);
1750b57cec5SDimitry Andric     else
1760b57cec5SDimitry Andric       Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm);
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric     // Only the first instruction has X0 as its source.
1790b57cec5SDimitry Andric     SrcReg = SDValue(Result, 0);
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   return Result;
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
185e8d8bef9SDimitry Andric static SDValue createTupleImpl(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
186e8d8bef9SDimitry Andric                                unsigned RegClassID, unsigned SubReg0) {
187e8d8bef9SDimitry Andric   assert(Regs.size() >= 2 && Regs.size() <= 8);
188e8d8bef9SDimitry Andric 
189e8d8bef9SDimitry Andric   SDLoc DL(Regs[0]);
190e8d8bef9SDimitry Andric   SmallVector<SDValue, 8> Ops;
191e8d8bef9SDimitry Andric 
192e8d8bef9SDimitry Andric   Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32));
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric   for (unsigned I = 0; I < Regs.size(); ++I) {
195e8d8bef9SDimitry Andric     Ops.push_back(Regs[I]);
196e8d8bef9SDimitry Andric     Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32));
197e8d8bef9SDimitry Andric   }
198e8d8bef9SDimitry Andric   SDNode *N =
199e8d8bef9SDimitry Andric       CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops);
200e8d8bef9SDimitry Andric   return SDValue(N, 0);
201e8d8bef9SDimitry Andric }
202e8d8bef9SDimitry Andric 
203e8d8bef9SDimitry Andric static SDValue createM1Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
204e8d8bef9SDimitry Andric                              unsigned NF) {
205e8d8bef9SDimitry Andric   static const unsigned RegClassIDs[] = {
206e8d8bef9SDimitry Andric       RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID,
207e8d8bef9SDimitry Andric       RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID,
208e8d8bef9SDimitry Andric       RISCV::VRN8M1RegClassID};
209e8d8bef9SDimitry Andric 
210e8d8bef9SDimitry Andric   return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm1_0);
211e8d8bef9SDimitry Andric }
212e8d8bef9SDimitry Andric 
213e8d8bef9SDimitry Andric static SDValue createM2Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
214e8d8bef9SDimitry Andric                              unsigned NF) {
215e8d8bef9SDimitry Andric   static const unsigned RegClassIDs[] = {RISCV::VRN2M2RegClassID,
216e8d8bef9SDimitry Andric                                          RISCV::VRN3M2RegClassID,
217e8d8bef9SDimitry Andric                                          RISCV::VRN4M2RegClassID};
218e8d8bef9SDimitry Andric 
219e8d8bef9SDimitry Andric   return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm2_0);
220e8d8bef9SDimitry Andric }
221e8d8bef9SDimitry Andric 
222e8d8bef9SDimitry Andric static SDValue createM4Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
223e8d8bef9SDimitry Andric                              unsigned NF) {
224e8d8bef9SDimitry Andric   return createTupleImpl(CurDAG, Regs, RISCV::VRN2M4RegClassID,
225e8d8bef9SDimitry Andric                          RISCV::sub_vrm4_0);
226e8d8bef9SDimitry Andric }
227e8d8bef9SDimitry Andric 
228e8d8bef9SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
229fe6060f1SDimitry Andric                            unsigned NF, RISCVII::VLMUL LMUL) {
230e8d8bef9SDimitry Andric   switch (LMUL) {
231e8d8bef9SDimitry Andric   default:
232e8d8bef9SDimitry Andric     llvm_unreachable("Invalid LMUL.");
233fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_F8:
234fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_F4:
235fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_F2:
236fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_1:
237e8d8bef9SDimitry Andric     return createM1Tuple(CurDAG, Regs, NF);
238fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_2:
239e8d8bef9SDimitry Andric     return createM2Tuple(CurDAG, Regs, NF);
240fe6060f1SDimitry Andric   case RISCVII::VLMUL::LMUL_4:
241e8d8bef9SDimitry Andric     return createM4Tuple(CurDAG, Regs, NF);
242e8d8bef9SDimitry Andric   }
243e8d8bef9SDimitry Andric }
244e8d8bef9SDimitry Andric 
245fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands(
246fe6060f1SDimitry Andric     SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp,
247fe6060f1SDimitry Andric     bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands,
248349cc55cSDimitry Andric     bool IsLoad, MVT *IndexVT) {
249fe6060f1SDimitry Andric   SDValue Chain = Node->getOperand(0);
250fe6060f1SDimitry Andric   SDValue Glue;
251fe6060f1SDimitry Andric 
252fe6060f1SDimitry Andric   SDValue Base;
253fe6060f1SDimitry Andric   SelectBaseAddr(Node->getOperand(CurOp++), Base);
254fe6060f1SDimitry Andric   Operands.push_back(Base); // Base pointer.
255fe6060f1SDimitry Andric 
256fe6060f1SDimitry Andric   if (IsStridedOrIndexed) {
257fe6060f1SDimitry Andric     Operands.push_back(Node->getOperand(CurOp++)); // Index.
258fe6060f1SDimitry Andric     if (IndexVT)
259fe6060f1SDimitry Andric       *IndexVT = Operands.back()->getSimpleValueType(0);
260fe6060f1SDimitry Andric   }
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric   if (IsMasked) {
263fe6060f1SDimitry Andric     // Mask needs to be copied to V0.
264fe6060f1SDimitry Andric     SDValue Mask = Node->getOperand(CurOp++);
265fe6060f1SDimitry Andric     Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue());
266fe6060f1SDimitry Andric     Glue = Chain.getValue(1);
267fe6060f1SDimitry Andric     Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType()));
268fe6060f1SDimitry Andric   }
269fe6060f1SDimitry Andric   SDValue VL;
270fe6060f1SDimitry Andric   selectVLOp(Node->getOperand(CurOp++), VL);
271fe6060f1SDimitry Andric   Operands.push_back(VL);
272fe6060f1SDimitry Andric 
273fe6060f1SDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
274fe6060f1SDimitry Andric   SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT);
275fe6060f1SDimitry Andric   Operands.push_back(SEWOp);
276fe6060f1SDimitry Andric 
277349cc55cSDimitry Andric   // Masked load has the tail policy argument.
278349cc55cSDimitry Andric   if (IsMasked && IsLoad) {
279349cc55cSDimitry Andric     // Policy must be a constant.
280349cc55cSDimitry Andric     uint64_t Policy = Node->getConstantOperandVal(CurOp++);
281349cc55cSDimitry Andric     SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT);
282349cc55cSDimitry Andric     Operands.push_back(PolicyOp);
283349cc55cSDimitry Andric   }
284349cc55cSDimitry Andric 
285fe6060f1SDimitry Andric   Operands.push_back(Chain); // Chain.
286fe6060f1SDimitry Andric   if (Glue)
287fe6060f1SDimitry Andric     Operands.push_back(Glue);
288fe6060f1SDimitry Andric }
289fe6060f1SDimitry Andric 
290fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked,
291e8d8bef9SDimitry Andric                                     bool IsStrided) {
292e8d8bef9SDimitry Andric   SDLoc DL(Node);
293e8d8bef9SDimitry Andric   unsigned NF = Node->getNumValues() - 1;
294fe6060f1SDimitry Andric   MVT VT = Node->getSimpleValueType(0);
295fe6060f1SDimitry Andric   unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
296fe6060f1SDimitry Andric   RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
297e8d8bef9SDimitry Andric 
298fe6060f1SDimitry Andric   unsigned CurOp = 2;
299fe6060f1SDimitry Andric   SmallVector<SDValue, 8> Operands;
300fe6060f1SDimitry Andric   if (IsMasked) {
301fe6060f1SDimitry Andric     SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp,
302fe6060f1SDimitry Andric                                  Node->op_begin() + CurOp + NF);
303e8d8bef9SDimitry Andric     SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL);
304e8d8bef9SDimitry Andric     Operands.push_back(MaskedOff);
305fe6060f1SDimitry Andric     CurOp += NF;
306e8d8bef9SDimitry Andric   }
307fe6060f1SDimitry Andric 
308fe6060f1SDimitry Andric   addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided,
309349cc55cSDimitry Andric                              Operands, /*IsLoad=*/true);
310fe6060f1SDimitry Andric 
311fe6060f1SDimitry Andric   const RISCV::VLSEGPseudo *P =
312fe6060f1SDimitry Andric       RISCV::getVLSEGPseudo(NF, IsMasked, IsStrided, /*FF*/ false, Log2SEW,
313fe6060f1SDimitry Andric                             static_cast<unsigned>(LMUL));
314fe6060f1SDimitry Andric   MachineSDNode *Load =
315e8d8bef9SDimitry Andric       CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands);
316fe6060f1SDimitry Andric 
317fe6060f1SDimitry Andric   if (auto *MemOp = dyn_cast<MemSDNode>(Node))
318fe6060f1SDimitry Andric     CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
319fe6060f1SDimitry Andric 
320e8d8bef9SDimitry Andric   SDValue SuperReg = SDValue(Load, 0);
321fe6060f1SDimitry Andric   for (unsigned I = 0; I < NF; ++I) {
322fe6060f1SDimitry Andric     unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I);
323e8d8bef9SDimitry Andric     ReplaceUses(SDValue(Node, I),
324fe6060f1SDimitry Andric                 CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg));
325fe6060f1SDimitry Andric   }
326e8d8bef9SDimitry Andric 
327e8d8bef9SDimitry Andric   ReplaceUses(SDValue(Node, NF), SDValue(Load, 1));
328e8d8bef9SDimitry Andric   CurDAG->RemoveDeadNode(Node);
329e8d8bef9SDimitry Andric }
330e8d8bef9SDimitry Andric 
331fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) {
332e8d8bef9SDimitry Andric   SDLoc DL(Node);
333fe6060f1SDimitry Andric   unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain.
334fe6060f1SDimitry Andric   MVT VT = Node->getSimpleValueType(0);
335e8d8bef9SDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
336fe6060f1SDimitry Andric   unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
337fe6060f1SDimitry Andric   RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
338e8d8bef9SDimitry Andric 
339fe6060f1SDimitry Andric   unsigned CurOp = 2;
340e8d8bef9SDimitry Andric   SmallVector<SDValue, 7> Operands;
341fe6060f1SDimitry Andric   if (IsMasked) {
342fe6060f1SDimitry Andric     SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp,
343fe6060f1SDimitry Andric                                  Node->op_begin() + CurOp + NF);
344e8d8bef9SDimitry Andric     SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL);
345fe6060f1SDimitry Andric     Operands.push_back(MaskedOff);
346fe6060f1SDimitry Andric     CurOp += NF;
347fe6060f1SDimitry Andric   }
348e8d8bef9SDimitry Andric 
349fe6060f1SDimitry Andric   addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
350349cc55cSDimitry Andric                              /*IsStridedOrIndexed*/ false, Operands,
351349cc55cSDimitry Andric                              /*IsLoad=*/true);
352fe6060f1SDimitry Andric 
353fe6060f1SDimitry Andric   const RISCV::VLSEGPseudo *P =
354fe6060f1SDimitry Andric       RISCV::getVLSEGPseudo(NF, IsMasked, /*Strided*/ false, /*FF*/ true,
355fe6060f1SDimitry Andric                             Log2SEW, static_cast<unsigned>(LMUL));
356fe6060f1SDimitry Andric   MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped,
357fe6060f1SDimitry Andric                                                MVT::Other, MVT::Glue, Operands);
358fe6060f1SDimitry Andric   SDNode *ReadVL = CurDAG->getMachineNode(RISCV::PseudoReadVL, DL, XLenVT,
359fe6060f1SDimitry Andric                                           /*Glue*/ SDValue(Load, 2));
360fe6060f1SDimitry Andric 
361fe6060f1SDimitry Andric   if (auto *MemOp = dyn_cast<MemSDNode>(Node))
362fe6060f1SDimitry Andric     CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
363fe6060f1SDimitry Andric 
364e8d8bef9SDimitry Andric   SDValue SuperReg = SDValue(Load, 0);
365fe6060f1SDimitry Andric   for (unsigned I = 0; I < NF; ++I) {
366fe6060f1SDimitry Andric     unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I);
367e8d8bef9SDimitry Andric     ReplaceUses(SDValue(Node, I),
368fe6060f1SDimitry Andric                 CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg));
369fe6060f1SDimitry Andric   }
370fe6060f1SDimitry Andric 
371fe6060f1SDimitry Andric   ReplaceUses(SDValue(Node, NF), SDValue(ReadVL, 0));   // VL
372fe6060f1SDimitry Andric   ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 1)); // Chain
373fe6060f1SDimitry Andric   CurDAG->RemoveDeadNode(Node);
374fe6060f1SDimitry Andric }
375fe6060f1SDimitry Andric 
376fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked,
377fe6060f1SDimitry Andric                                      bool IsOrdered) {
378fe6060f1SDimitry Andric   SDLoc DL(Node);
379fe6060f1SDimitry Andric   unsigned NF = Node->getNumValues() - 1;
380fe6060f1SDimitry Andric   MVT VT = Node->getSimpleValueType(0);
381fe6060f1SDimitry Andric   unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
382fe6060f1SDimitry Andric   RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
383fe6060f1SDimitry Andric 
384fe6060f1SDimitry Andric   unsigned CurOp = 2;
385fe6060f1SDimitry Andric   SmallVector<SDValue, 8> Operands;
386fe6060f1SDimitry Andric   if (IsMasked) {
387fe6060f1SDimitry Andric     SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp,
388fe6060f1SDimitry Andric                                  Node->op_begin() + CurOp + NF);
389fe6060f1SDimitry Andric     SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL);
390fe6060f1SDimitry Andric     Operands.push_back(MaskedOff);
391fe6060f1SDimitry Andric     CurOp += NF;
392fe6060f1SDimitry Andric   }
393fe6060f1SDimitry Andric 
394fe6060f1SDimitry Andric   MVT IndexVT;
395fe6060f1SDimitry Andric   addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
396349cc55cSDimitry Andric                              /*IsStridedOrIndexed*/ true, Operands,
397349cc55cSDimitry Andric                              /*IsLoad=*/true, &IndexVT);
398fe6060f1SDimitry Andric 
399fe6060f1SDimitry Andric   assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() &&
400fe6060f1SDimitry Andric          "Element count mismatch");
401fe6060f1SDimitry Andric 
402fe6060f1SDimitry Andric   RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT);
403fe6060f1SDimitry Andric   unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits());
404*04eeddc0SDimitry Andric   if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) {
405*04eeddc0SDimitry Andric     report_fatal_error("The V extension does not support EEW=64 for index "
406*04eeddc0SDimitry Andric                        "values when XLEN=32");
407*04eeddc0SDimitry Andric   }
408fe6060f1SDimitry Andric   const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo(
409fe6060f1SDimitry Andric       NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL),
410fe6060f1SDimitry Andric       static_cast<unsigned>(IndexLMUL));
411fe6060f1SDimitry Andric   MachineSDNode *Load =
412fe6060f1SDimitry Andric       CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands);
413fe6060f1SDimitry Andric 
414fe6060f1SDimitry Andric   if (auto *MemOp = dyn_cast<MemSDNode>(Node))
415fe6060f1SDimitry Andric     CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
416fe6060f1SDimitry Andric 
417fe6060f1SDimitry Andric   SDValue SuperReg = SDValue(Load, 0);
418fe6060f1SDimitry Andric   for (unsigned I = 0; I < NF; ++I) {
419fe6060f1SDimitry Andric     unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I);
420fe6060f1SDimitry Andric     ReplaceUses(SDValue(Node, I),
421fe6060f1SDimitry Andric                 CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg));
422fe6060f1SDimitry Andric   }
423e8d8bef9SDimitry Andric 
424e8d8bef9SDimitry Andric   ReplaceUses(SDValue(Node, NF), SDValue(Load, 1));
425e8d8bef9SDimitry Andric   CurDAG->RemoveDeadNode(Node);
426e8d8bef9SDimitry Andric }
427e8d8bef9SDimitry Andric 
428fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked,
429e8d8bef9SDimitry Andric                                     bool IsStrided) {
430e8d8bef9SDimitry Andric   SDLoc DL(Node);
431e8d8bef9SDimitry Andric   unsigned NF = Node->getNumOperands() - 4;
432e8d8bef9SDimitry Andric   if (IsStrided)
433e8d8bef9SDimitry Andric     NF--;
434fe6060f1SDimitry Andric   if (IsMasked)
435e8d8bef9SDimitry Andric     NF--;
436fe6060f1SDimitry Andric   MVT VT = Node->getOperand(2)->getSimpleValueType(0);
437fe6060f1SDimitry Andric   unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
438fe6060f1SDimitry Andric   RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
439e8d8bef9SDimitry Andric   SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF);
440e8d8bef9SDimitry Andric   SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL);
441fe6060f1SDimitry Andric 
442fe6060f1SDimitry Andric   SmallVector<SDValue, 8> Operands;
443e8d8bef9SDimitry Andric   Operands.push_back(StoreVal);
444fe6060f1SDimitry Andric   unsigned CurOp = 2 + NF;
445fe6060f1SDimitry Andric 
446fe6060f1SDimitry Andric   addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided,
447fe6060f1SDimitry Andric                              Operands);
448fe6060f1SDimitry Andric 
449fe6060f1SDimitry Andric   const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo(
450fe6060f1SDimitry Andric       NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL));
451fe6060f1SDimitry Andric   MachineSDNode *Store =
452e8d8bef9SDimitry Andric       CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands);
453fe6060f1SDimitry Andric 
454fe6060f1SDimitry Andric   if (auto *MemOp = dyn_cast<MemSDNode>(Node))
455fe6060f1SDimitry Andric     CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()});
456fe6060f1SDimitry Andric 
457e8d8bef9SDimitry Andric   ReplaceNode(Node, Store);
458e8d8bef9SDimitry Andric }
459e8d8bef9SDimitry Andric 
460fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked,
461fe6060f1SDimitry Andric                                      bool IsOrdered) {
462e8d8bef9SDimitry Andric   SDLoc DL(Node);
463e8d8bef9SDimitry Andric   unsigned NF = Node->getNumOperands() - 5;
464fe6060f1SDimitry Andric   if (IsMasked)
465fe6060f1SDimitry Andric     --NF;
466fe6060f1SDimitry Andric   MVT VT = Node->getOperand(2)->getSimpleValueType(0);
467fe6060f1SDimitry Andric   unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
468fe6060f1SDimitry Andric   RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
469e8d8bef9SDimitry Andric   SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF);
470e8d8bef9SDimitry Andric   SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL);
471e8d8bef9SDimitry Andric 
472fe6060f1SDimitry Andric   SmallVector<SDValue, 8> Operands;
473fe6060f1SDimitry Andric   Operands.push_back(StoreVal);
474fe6060f1SDimitry Andric   unsigned CurOp = 2 + NF;
475fe6060f1SDimitry Andric 
476fe6060f1SDimitry Andric   MVT IndexVT;
477fe6060f1SDimitry Andric   addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
478349cc55cSDimitry Andric                              /*IsStridedOrIndexed*/ true, Operands,
479349cc55cSDimitry Andric                              /*IsLoad=*/false, &IndexVT);
480fe6060f1SDimitry Andric 
481fe6060f1SDimitry Andric   assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() &&
482fe6060f1SDimitry Andric          "Element count mismatch");
483fe6060f1SDimitry Andric 
484fe6060f1SDimitry Andric   RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT);
485fe6060f1SDimitry Andric   unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits());
486*04eeddc0SDimitry Andric   if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) {
487*04eeddc0SDimitry Andric     report_fatal_error("The V extension does not support EEW=64 for index "
488*04eeddc0SDimitry Andric                        "values when XLEN=32");
489*04eeddc0SDimitry Andric   }
490fe6060f1SDimitry Andric   const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo(
491fe6060f1SDimitry Andric       NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL),
492e8d8bef9SDimitry Andric       static_cast<unsigned>(IndexLMUL));
493fe6060f1SDimitry Andric   MachineSDNode *Store =
494e8d8bef9SDimitry Andric       CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands);
495fe6060f1SDimitry Andric 
496fe6060f1SDimitry Andric   if (auto *MemOp = dyn_cast<MemSDNode>(Node))
497fe6060f1SDimitry Andric     CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()});
498fe6060f1SDimitry Andric 
499e8d8bef9SDimitry Andric   ReplaceNode(Node, Store);
500e8d8bef9SDimitry Andric }
501e8d8bef9SDimitry Andric 
502*04eeddc0SDimitry Andric void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) {
503*04eeddc0SDimitry Andric   if (!Subtarget->hasVInstructions())
504*04eeddc0SDimitry Andric     return;
505*04eeddc0SDimitry Andric 
506*04eeddc0SDimitry Andric   assert((Node->getOpcode() == ISD::INTRINSIC_W_CHAIN ||
507*04eeddc0SDimitry Andric           Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN) &&
508*04eeddc0SDimitry Andric          "Unexpected opcode");
509*04eeddc0SDimitry Andric 
510*04eeddc0SDimitry Andric   SDLoc DL(Node);
511*04eeddc0SDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
512*04eeddc0SDimitry Andric 
513*04eeddc0SDimitry Andric   bool HasChain = Node->getOpcode() == ISD::INTRINSIC_W_CHAIN;
514*04eeddc0SDimitry Andric   unsigned IntNoOffset = HasChain ? 1 : 0;
515*04eeddc0SDimitry Andric   unsigned IntNo = Node->getConstantOperandVal(IntNoOffset);
516*04eeddc0SDimitry Andric 
517*04eeddc0SDimitry Andric   assert((IntNo == Intrinsic::riscv_vsetvli ||
518*04eeddc0SDimitry Andric           IntNo == Intrinsic::riscv_vsetvlimax ||
519*04eeddc0SDimitry Andric           IntNo == Intrinsic::riscv_vsetvli_opt ||
520*04eeddc0SDimitry Andric           IntNo == Intrinsic::riscv_vsetvlimax_opt) &&
521*04eeddc0SDimitry Andric          "Unexpected vsetvli intrinsic");
522*04eeddc0SDimitry Andric 
523*04eeddc0SDimitry Andric   bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax ||
524*04eeddc0SDimitry Andric                IntNo == Intrinsic::riscv_vsetvlimax_opt;
525*04eeddc0SDimitry Andric   unsigned Offset = IntNoOffset + (VLMax ? 1 : 2);
526*04eeddc0SDimitry Andric 
527*04eeddc0SDimitry Andric   assert(Node->getNumOperands() == Offset + 2 &&
528*04eeddc0SDimitry Andric          "Unexpected number of operands");
529*04eeddc0SDimitry Andric 
530*04eeddc0SDimitry Andric   unsigned SEW =
531*04eeddc0SDimitry Andric       RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7);
532*04eeddc0SDimitry Andric   RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>(
533*04eeddc0SDimitry Andric       Node->getConstantOperandVal(Offset + 1) & 0x7);
534*04eeddc0SDimitry Andric 
535*04eeddc0SDimitry Andric   unsigned VTypeI = RISCVVType::encodeVTYPE(VLMul, SEW, /*TailAgnostic*/ true,
536*04eeddc0SDimitry Andric                                             /*MaskAgnostic*/ false);
537*04eeddc0SDimitry Andric   SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT);
538*04eeddc0SDimitry Andric 
539*04eeddc0SDimitry Andric   SmallVector<EVT, 2> VTs = {XLenVT};
540*04eeddc0SDimitry Andric   if (HasChain)
541*04eeddc0SDimitry Andric     VTs.push_back(MVT::Other);
542*04eeddc0SDimitry Andric 
543*04eeddc0SDimitry Andric   SDValue VLOperand;
544*04eeddc0SDimitry Andric   unsigned Opcode = RISCV::PseudoVSETVLI;
545*04eeddc0SDimitry Andric   if (VLMax) {
546*04eeddc0SDimitry Andric     VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT);
547*04eeddc0SDimitry Andric     Opcode = RISCV::PseudoVSETVLIX0;
548*04eeddc0SDimitry Andric   } else {
549*04eeddc0SDimitry Andric     VLOperand = Node->getOperand(IntNoOffset + 1);
550*04eeddc0SDimitry Andric 
551*04eeddc0SDimitry Andric     if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) {
552*04eeddc0SDimitry Andric       uint64_t AVL = C->getZExtValue();
553*04eeddc0SDimitry Andric       if (isUInt<5>(AVL)) {
554*04eeddc0SDimitry Andric         SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT);
555*04eeddc0SDimitry Andric         SmallVector<SDValue, 3> Ops = {VLImm, VTypeIOp};
556*04eeddc0SDimitry Andric         if (HasChain)
557*04eeddc0SDimitry Andric           Ops.push_back(Node->getOperand(0));
558*04eeddc0SDimitry Andric         ReplaceNode(
559*04eeddc0SDimitry Andric             Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, VTs, Ops));
560*04eeddc0SDimitry Andric         return;
561*04eeddc0SDimitry Andric       }
562*04eeddc0SDimitry Andric     }
563*04eeddc0SDimitry Andric   }
564*04eeddc0SDimitry Andric 
565*04eeddc0SDimitry Andric   SmallVector<SDValue, 3> Ops = {VLOperand, VTypeIOp};
566*04eeddc0SDimitry Andric   if (HasChain)
567*04eeddc0SDimitry Andric     Ops.push_back(Node->getOperand(0));
568*04eeddc0SDimitry Andric 
569*04eeddc0SDimitry Andric   ReplaceNode(Node, CurDAG->getMachineNode(Opcode, DL, VTs, Ops));
570*04eeddc0SDimitry Andric }
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) {
5730b57cec5SDimitry Andric   // If we have a custom node, we have already selected.
5740b57cec5SDimitry Andric   if (Node->isMachineOpcode()) {
5750b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
5760b57cec5SDimitry Andric     Node->setNodeId(-1);
5770b57cec5SDimitry Andric     return;
5780b57cec5SDimitry Andric   }
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric   // Instruction Selection not handled by the auto-generated tablegen selection
5810b57cec5SDimitry Andric   // should be handled here.
5820b57cec5SDimitry Andric   unsigned Opcode = Node->getOpcode();
5830b57cec5SDimitry Andric   MVT XLenVT = Subtarget->getXLenVT();
5840b57cec5SDimitry Andric   SDLoc DL(Node);
585fe6060f1SDimitry Andric   MVT VT = Node->getSimpleValueType(0);
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   switch (Opcode) {
5880b57cec5SDimitry Andric   case ISD::Constant: {
589fe6060f1SDimitry Andric     auto *ConstNode = cast<ConstantSDNode>(Node);
590349cc55cSDimitry Andric     if (VT == XLenVT && ConstNode->isZero()) {
591e8d8bef9SDimitry Andric       SDValue New =
592e8d8bef9SDimitry Andric           CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, XLenVT);
5930b57cec5SDimitry Andric       ReplaceNode(Node, New.getNode());
5940b57cec5SDimitry Andric       return;
5950b57cec5SDimitry Andric     }
596349cc55cSDimitry Andric     int64_t Imm = ConstNode->getSExtValue();
597349cc55cSDimitry Andric     // If the upper XLen-16 bits are not used, try to convert this to a simm12
598349cc55cSDimitry Andric     // by sign extending bit 15.
599349cc55cSDimitry Andric     if (isUInt<16>(Imm) && isInt<12>(SignExtend64(Imm, 16)) &&
600349cc55cSDimitry Andric         hasAllHUsers(Node))
601349cc55cSDimitry Andric       Imm = SignExtend64(Imm, 16);
602349cc55cSDimitry Andric     // If the upper 32-bits are not used try to convert this into a simm32 by
603349cc55cSDimitry Andric     // sign extending bit 32.
604349cc55cSDimitry Andric     if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node))
605349cc55cSDimitry Andric       Imm = SignExtend64(Imm, 32);
606349cc55cSDimitry Andric 
607*04eeddc0SDimitry Andric     ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget));
6080b57cec5SDimitry Andric     return;
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric   case ISD::FrameIndex: {
6110b57cec5SDimitry Andric     SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
6120b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
6130b57cec5SDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
6140b57cec5SDimitry Andric     ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
6150b57cec5SDimitry Andric     return;
6160b57cec5SDimitry Andric   }
617fe6060f1SDimitry Andric   case ISD::SRL: {
618*04eeddc0SDimitry Andric     // Optimize (srl (and X, C2), C) ->
619*04eeddc0SDimitry Andric     //          (srli (slli X, (XLen-C3), (XLen-C3) + C)
620*04eeddc0SDimitry Andric     // Where C2 is a mask with C3 trailing ones.
621*04eeddc0SDimitry Andric     // Taking into account that the C2 may have had lower bits unset by
622*04eeddc0SDimitry Andric     // SimplifyDemandedBits. This avoids materializing the C2 immediate.
623*04eeddc0SDimitry Andric     // This pattern occurs when type legalizing right shifts for types with
624*04eeddc0SDimitry Andric     // less than XLen bits.
625fe6060f1SDimitry Andric     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
626*04eeddc0SDimitry Andric     if (!N1C)
627*04eeddc0SDimitry Andric       break;
628fe6060f1SDimitry Andric     SDValue N0 = Node->getOperand(0);
629*04eeddc0SDimitry Andric     if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() ||
630*04eeddc0SDimitry Andric         !isa<ConstantSDNode>(N0.getOperand(1)))
631*04eeddc0SDimitry Andric       break;
632*04eeddc0SDimitry Andric     unsigned ShAmt = N1C->getZExtValue();
633fe6060f1SDimitry Andric     uint64_t Mask = N0.getConstantOperandVal(1);
634fe6060f1SDimitry Andric     Mask |= maskTrailingOnes<uint64_t>(ShAmt);
635*04eeddc0SDimitry Andric     if (!isMask_64(Mask))
636*04eeddc0SDimitry Andric       break;
637*04eeddc0SDimitry Andric     unsigned TrailingOnes = countTrailingOnes(Mask);
638*04eeddc0SDimitry Andric     // 32 trailing ones should use srliw via tablegen pattern.
639*04eeddc0SDimitry Andric     if (TrailingOnes == 32 || ShAmt >= TrailingOnes)
640*04eeddc0SDimitry Andric       break;
641*04eeddc0SDimitry Andric     unsigned LShAmt = Subtarget->getXLen() - TrailingOnes;
642fe6060f1SDimitry Andric     SDNode *SLLI =
643fe6060f1SDimitry Andric         CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0),
644fe6060f1SDimitry Andric                                CurDAG->getTargetConstant(LShAmt, DL, VT));
645fe6060f1SDimitry Andric     SDNode *SRLI = CurDAG->getMachineNode(
646fe6060f1SDimitry Andric         RISCV::SRLI, DL, VT, SDValue(SLLI, 0),
647fe6060f1SDimitry Andric         CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT));
648fe6060f1SDimitry Andric     ReplaceNode(Node, SRLI);
649fe6060f1SDimitry Andric     return;
650fe6060f1SDimitry Andric   }
651*04eeddc0SDimitry Andric   case ISD::SRA: {
652*04eeddc0SDimitry Andric     // Optimize (sra (sext_inreg X, i16), C) ->
653*04eeddc0SDimitry Andric     //          (srai (slli X, (XLen-16), (XLen-16) + C)
654*04eeddc0SDimitry Andric     // And      (sra (sext_inreg X, i8), C) ->
655*04eeddc0SDimitry Andric     //          (srai (slli X, (XLen-8), (XLen-8) + C)
656*04eeddc0SDimitry Andric     // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal.
657*04eeddc0SDimitry Andric     // This transform matches the code we get without Zbb. The shifts are more
658*04eeddc0SDimitry Andric     // compressible, and this can help expose CSE opportunities in the sdiv by
659*04eeddc0SDimitry Andric     // constant optimization.
660*04eeddc0SDimitry Andric     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
661*04eeddc0SDimitry Andric     if (!N1C)
662fe6060f1SDimitry Andric       break;
663*04eeddc0SDimitry Andric     SDValue N0 = Node->getOperand(0);
664*04eeddc0SDimitry Andric     if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse())
665*04eeddc0SDimitry Andric       break;
666*04eeddc0SDimitry Andric     unsigned ShAmt = N1C->getZExtValue();
667*04eeddc0SDimitry Andric     unsigned ExtSize =
668*04eeddc0SDimitry Andric         cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits();
669*04eeddc0SDimitry Andric     // ExtSize of 32 should use sraiw via tablegen pattern.
670*04eeddc0SDimitry Andric     if (ExtSize >= 32 || ShAmt >= ExtSize)
671*04eeddc0SDimitry Andric       break;
672*04eeddc0SDimitry Andric     unsigned LShAmt = Subtarget->getXLen() - ExtSize;
673*04eeddc0SDimitry Andric     SDNode *SLLI =
674*04eeddc0SDimitry Andric         CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0),
675*04eeddc0SDimitry Andric                                CurDAG->getTargetConstant(LShAmt, DL, VT));
676*04eeddc0SDimitry Andric     SDNode *SRAI = CurDAG->getMachineNode(
677*04eeddc0SDimitry Andric         RISCV::SRAI, DL, VT, SDValue(SLLI, 0),
678*04eeddc0SDimitry Andric         CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT));
679*04eeddc0SDimitry Andric     ReplaceNode(Node, SRAI);
680*04eeddc0SDimitry Andric     return;
681fe6060f1SDimitry Andric   }
682fe6060f1SDimitry Andric   case ISD::AND: {
683fe6060f1SDimitry Andric     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
684fe6060f1SDimitry Andric     if (!N1C)
685fe6060f1SDimitry Andric       break;
686fe6060f1SDimitry Andric 
687fe6060f1SDimitry Andric     SDValue N0 = Node->getOperand(0);
688fe6060f1SDimitry Andric 
689fe6060f1SDimitry Andric     bool LeftShift = N0.getOpcode() == ISD::SHL;
690fe6060f1SDimitry Andric     if (!LeftShift && N0.getOpcode() != ISD::SRL)
691fe6060f1SDimitry Andric       break;
692fe6060f1SDimitry Andric 
693fe6060f1SDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1));
694fe6060f1SDimitry Andric     if (!C)
695fe6060f1SDimitry Andric       break;
696fe6060f1SDimitry Andric     uint64_t C2 = C->getZExtValue();
697fe6060f1SDimitry Andric     unsigned XLen = Subtarget->getXLen();
698fe6060f1SDimitry Andric     if (!C2 || C2 >= XLen)
699fe6060f1SDimitry Andric       break;
700fe6060f1SDimitry Andric 
701fe6060f1SDimitry Andric     uint64_t C1 = N1C->getZExtValue();
702fe6060f1SDimitry Andric 
703fe6060f1SDimitry Andric     // Keep track of whether this is a andi, zext.h, or zext.w.
704fe6060f1SDimitry Andric     bool ZExtOrANDI = isInt<12>(N1C->getSExtValue());
705fe6060f1SDimitry Andric     if (C1 == UINT64_C(0xFFFF) &&
706fe6060f1SDimitry Andric         (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp()))
707fe6060f1SDimitry Andric       ZExtOrANDI = true;
708fe6060f1SDimitry Andric     if (C1 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba())
709fe6060f1SDimitry Andric       ZExtOrANDI = true;
710fe6060f1SDimitry Andric 
711fe6060f1SDimitry Andric     // Clear irrelevant bits in the mask.
712fe6060f1SDimitry Andric     if (LeftShift)
713fe6060f1SDimitry Andric       C1 &= maskTrailingZeros<uint64_t>(C2);
714fe6060f1SDimitry Andric     else
715fe6060f1SDimitry Andric       C1 &= maskTrailingOnes<uint64_t>(XLen - C2);
716fe6060f1SDimitry Andric 
717fe6060f1SDimitry Andric     // Some transforms should only be done if the shift has a single use or
718fe6060f1SDimitry Andric     // the AND would become (srli (slli X, 32), 32)
719fe6060f1SDimitry Andric     bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF);
720fe6060f1SDimitry Andric 
721fe6060f1SDimitry Andric     SDValue X = N0.getOperand(0);
722fe6060f1SDimitry Andric 
723fe6060f1SDimitry Andric     // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask
724fe6060f1SDimitry Andric     // with c3 leading zeros.
725fe6060f1SDimitry Andric     if (!LeftShift && isMask_64(C1)) {
726fe6060f1SDimitry Andric       uint64_t C3 = XLen - (64 - countLeadingZeros(C1));
727fe6060f1SDimitry Andric       if (C2 < C3) {
728fe6060f1SDimitry Andric         // If the number of leading zeros is C2+32 this can be SRLIW.
729fe6060f1SDimitry Andric         if (C2 + 32 == C3) {
730fe6060f1SDimitry Andric           SDNode *SRLIW =
731fe6060f1SDimitry Andric               CurDAG->getMachineNode(RISCV::SRLIW, DL, XLenVT, X,
732fe6060f1SDimitry Andric                                      CurDAG->getTargetConstant(C2, DL, XLenVT));
733fe6060f1SDimitry Andric           ReplaceNode(Node, SRLIW);
734fe6060f1SDimitry Andric           return;
735fe6060f1SDimitry Andric         }
736fe6060f1SDimitry Andric 
737fe6060f1SDimitry Andric         // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) if
738fe6060f1SDimitry Andric         // c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1.
739fe6060f1SDimitry Andric         //
740fe6060f1SDimitry Andric         // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type
741fe6060f1SDimitry Andric         // legalized and goes through DAG combine.
742fe6060f1SDimitry Andric         SDValue Y;
743fe6060f1SDimitry Andric         if (C2 >= 32 && (C3 - C2) == 1 && N0.hasOneUse() &&
744fe6060f1SDimitry Andric             selectSExti32(X, Y)) {
745fe6060f1SDimitry Andric           SDNode *SRAIW =
746fe6060f1SDimitry Andric               CurDAG->getMachineNode(RISCV::SRAIW, DL, XLenVT, Y,
747fe6060f1SDimitry Andric                                      CurDAG->getTargetConstant(31, DL, XLenVT));
748fe6060f1SDimitry Andric           SDNode *SRLIW = CurDAG->getMachineNode(
749fe6060f1SDimitry Andric               RISCV::SRLIW, DL, XLenVT, SDValue(SRAIW, 0),
750fe6060f1SDimitry Andric               CurDAG->getTargetConstant(C3 - 32, DL, XLenVT));
751fe6060f1SDimitry Andric           ReplaceNode(Node, SRLIW);
752fe6060f1SDimitry Andric           return;
753fe6060f1SDimitry Andric         }
754fe6060f1SDimitry Andric 
755fe6060f1SDimitry Andric         // (srli (slli x, c3-c2), c3).
756fe6060f1SDimitry Andric         if (OneUseOrZExtW && !ZExtOrANDI) {
757fe6060f1SDimitry Andric           SDNode *SLLI = CurDAG->getMachineNode(
758fe6060f1SDimitry Andric               RISCV::SLLI, DL, XLenVT, X,
759fe6060f1SDimitry Andric               CurDAG->getTargetConstant(C3 - C2, DL, XLenVT));
760fe6060f1SDimitry Andric           SDNode *SRLI =
761fe6060f1SDimitry Andric               CurDAG->getMachineNode(RISCV::SRLI, DL, XLenVT, SDValue(SLLI, 0),
762fe6060f1SDimitry Andric                                      CurDAG->getTargetConstant(C3, DL, XLenVT));
763fe6060f1SDimitry Andric           ReplaceNode(Node, SRLI);
764fe6060f1SDimitry Andric           return;
765fe6060f1SDimitry Andric         }
766fe6060f1SDimitry Andric       }
767fe6060f1SDimitry Andric     }
768fe6060f1SDimitry Andric 
769349cc55cSDimitry Andric     // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask
770fe6060f1SDimitry Andric     // shifted by c2 bits with c3 leading zeros.
771fe6060f1SDimitry Andric     if (LeftShift && isShiftedMask_64(C1)) {
772fe6060f1SDimitry Andric       uint64_t C3 = XLen - (64 - countLeadingZeros(C1));
773fe6060f1SDimitry Andric 
774fe6060f1SDimitry Andric       if (C2 + C3 < XLen &&
775fe6060f1SDimitry Andric           C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + C3)) << C2)) {
776fe6060f1SDimitry Andric         // Use slli.uw when possible.
777fe6060f1SDimitry Andric         if ((XLen - (C2 + C3)) == 32 && Subtarget->hasStdExtZba()) {
778fe6060f1SDimitry Andric           SDNode *SLLIUW =
779fe6060f1SDimitry Andric               CurDAG->getMachineNode(RISCV::SLLIUW, DL, XLenVT, X,
780fe6060f1SDimitry Andric                                      CurDAG->getTargetConstant(C2, DL, XLenVT));
781fe6060f1SDimitry Andric           ReplaceNode(Node, SLLIUW);
782fe6060f1SDimitry Andric           return;
783fe6060f1SDimitry Andric         }
784fe6060f1SDimitry Andric 
785fe6060f1SDimitry Andric         // (srli (slli c2+c3), c3)
786fe6060f1SDimitry Andric         if (OneUseOrZExtW && !ZExtOrANDI) {
787fe6060f1SDimitry Andric           SDNode *SLLI = CurDAG->getMachineNode(
788fe6060f1SDimitry Andric               RISCV::SLLI, DL, XLenVT, X,
789fe6060f1SDimitry Andric               CurDAG->getTargetConstant(C2 + C3, DL, XLenVT));
790fe6060f1SDimitry Andric           SDNode *SRLI =
791fe6060f1SDimitry Andric               CurDAG->getMachineNode(RISCV::SRLI, DL, XLenVT, SDValue(SLLI, 0),
792fe6060f1SDimitry Andric                                      CurDAG->getTargetConstant(C3, DL, XLenVT));
793fe6060f1SDimitry Andric           ReplaceNode(Node, SRLI);
794fe6060f1SDimitry Andric           return;
795fe6060f1SDimitry Andric         }
796fe6060f1SDimitry Andric       }
797fe6060f1SDimitry Andric     }
798fe6060f1SDimitry Andric 
799349cc55cSDimitry Andric     // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a
800349cc55cSDimitry Andric     // shifted mask with c2 leading zeros and c3 trailing zeros.
801349cc55cSDimitry Andric     if (!LeftShift && isShiftedMask_64(C1)) {
802349cc55cSDimitry Andric       uint64_t Leading = XLen - (64 - countLeadingZeros(C1));
803349cc55cSDimitry Andric       uint64_t C3 = countTrailingZeros(C1);
804349cc55cSDimitry Andric       if (Leading == C2 && C2 + C3 < XLen && OneUseOrZExtW && !ZExtOrANDI) {
805349cc55cSDimitry Andric         SDNode *SRLI = CurDAG->getMachineNode(
806349cc55cSDimitry Andric             RISCV::SRLI, DL, XLenVT, X,
807349cc55cSDimitry Andric             CurDAG->getTargetConstant(C2 + C3, DL, XLenVT));
808349cc55cSDimitry Andric         SDNode *SLLI =
809349cc55cSDimitry Andric             CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLI, 0),
810349cc55cSDimitry Andric                                    CurDAG->getTargetConstant(C3, DL, XLenVT));
811349cc55cSDimitry Andric         ReplaceNode(Node, SLLI);
812349cc55cSDimitry Andric         return;
813349cc55cSDimitry Andric       }
814349cc55cSDimitry Andric       // If the leading zero count is C2+32, we can use SRLIW instead of SRLI.
815349cc55cSDimitry Andric       if (Leading > 32 && (Leading - 32) == C2 && C2 + C3 < 32 &&
816349cc55cSDimitry Andric           OneUseOrZExtW && !ZExtOrANDI) {
817349cc55cSDimitry Andric         SDNode *SRLIW = CurDAG->getMachineNode(
818349cc55cSDimitry Andric             RISCV::SRLIW, DL, XLenVT, X,
819349cc55cSDimitry Andric             CurDAG->getTargetConstant(C2 + C3, DL, XLenVT));
820349cc55cSDimitry Andric         SDNode *SLLI =
821349cc55cSDimitry Andric             CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLIW, 0),
822349cc55cSDimitry Andric                                    CurDAG->getTargetConstant(C3, DL, XLenVT));
823349cc55cSDimitry Andric         ReplaceNode(Node, SLLI);
824349cc55cSDimitry Andric         return;
825349cc55cSDimitry Andric       }
826349cc55cSDimitry Andric     }
827349cc55cSDimitry Andric 
828349cc55cSDimitry Andric     // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a
829349cc55cSDimitry Andric     // shifted mask with no leading zeros and c3 trailing zeros.
830349cc55cSDimitry Andric     if (LeftShift && isShiftedMask_64(C1)) {
831349cc55cSDimitry Andric       uint64_t Leading = XLen - (64 - countLeadingZeros(C1));
832349cc55cSDimitry Andric       uint64_t C3 = countTrailingZeros(C1);
833349cc55cSDimitry Andric       if (Leading == 0 && C2 < C3 && OneUseOrZExtW && !ZExtOrANDI) {
834349cc55cSDimitry Andric         SDNode *SRLI = CurDAG->getMachineNode(
835349cc55cSDimitry Andric             RISCV::SRLI, DL, XLenVT, X,
836349cc55cSDimitry Andric             CurDAG->getTargetConstant(C3 - C2, DL, XLenVT));
837349cc55cSDimitry Andric         SDNode *SLLI =
838349cc55cSDimitry Andric             CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLI, 0),
839349cc55cSDimitry Andric                                    CurDAG->getTargetConstant(C3, DL, XLenVT));
840349cc55cSDimitry Andric         ReplaceNode(Node, SLLI);
841349cc55cSDimitry Andric         return;
842349cc55cSDimitry Andric       }
843349cc55cSDimitry Andric       // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI.
844349cc55cSDimitry Andric       if (C2 < C3 && Leading + C2 == 32 && OneUseOrZExtW && !ZExtOrANDI) {
845349cc55cSDimitry Andric         SDNode *SRLIW = CurDAG->getMachineNode(
846349cc55cSDimitry Andric             RISCV::SRLIW, DL, XLenVT, X,
847349cc55cSDimitry Andric             CurDAG->getTargetConstant(C3 - C2, DL, XLenVT));
848349cc55cSDimitry Andric         SDNode *SLLI =
849349cc55cSDimitry Andric             CurDAG->getMachineNode(RISCV::SLLI, DL, XLenVT, SDValue(SRLIW, 0),
850349cc55cSDimitry Andric                                    CurDAG->getTargetConstant(C3, DL, XLenVT));
851349cc55cSDimitry Andric         ReplaceNode(Node, SLLI);
852349cc55cSDimitry Andric         return;
853349cc55cSDimitry Andric       }
854349cc55cSDimitry Andric     }
855349cc55cSDimitry Andric 
856fe6060f1SDimitry Andric     break;
857fe6060f1SDimitry Andric   }
8580eae32dcSDimitry Andric   case ISD::MUL: {
8590eae32dcSDimitry Andric     // Special case for calculating (mul (and X, C2), C1) where the full product
8600eae32dcSDimitry Andric     // fits in XLen bits. We can shift X left by the number of leading zeros in
8610eae32dcSDimitry Andric     // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final
8620eae32dcSDimitry Andric     // product has XLen trailing zeros, putting it in the output of MULHU. This
8630eae32dcSDimitry Andric     // can avoid materializing a constant in a register for C2.
8640eae32dcSDimitry Andric 
8650eae32dcSDimitry Andric     // RHS should be a constant.
8660eae32dcSDimitry Andric     auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1));
8670eae32dcSDimitry Andric     if (!N1C || !N1C->hasOneUse())
8680eae32dcSDimitry Andric       break;
8690eae32dcSDimitry Andric 
8700eae32dcSDimitry Andric     // LHS should be an AND with constant.
8710eae32dcSDimitry Andric     SDValue N0 = Node->getOperand(0);
8720eae32dcSDimitry Andric     if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1)))
8730eae32dcSDimitry Andric       break;
8740eae32dcSDimitry Andric 
8750eae32dcSDimitry Andric     uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue();
8760eae32dcSDimitry Andric 
8770eae32dcSDimitry Andric     // Constant should be a mask.
8780eae32dcSDimitry Andric     if (!isMask_64(C2))
8790eae32dcSDimitry Andric       break;
8800eae32dcSDimitry Andric 
8810eae32dcSDimitry Andric     // This should be the only use of the AND unless we will use
8820eae32dcSDimitry Andric     // (SRLI (SLLI X, 32), 32). We don't use a shift pair for other AND
8830eae32dcSDimitry Andric     // constants.
8840eae32dcSDimitry Andric     if (!N0.hasOneUse() && C2 != UINT64_C(0xFFFFFFFF))
8850eae32dcSDimitry Andric       break;
8860eae32dcSDimitry Andric 
8870eae32dcSDimitry Andric     // If this can be an ANDI, ZEXT.H or ZEXT.W we don't need to do this
8880eae32dcSDimitry Andric     // optimization.
8890eae32dcSDimitry Andric     if (isInt<12>(C2) ||
8900eae32dcSDimitry Andric         (C2 == UINT64_C(0xFFFF) &&
8910eae32dcSDimitry Andric          (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp())) ||
8920eae32dcSDimitry Andric         (C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba()))
8930eae32dcSDimitry Andric       break;
8940eae32dcSDimitry Andric 
8950eae32dcSDimitry Andric     // We need to shift left the AND input and C1 by a total of XLen bits.
8960eae32dcSDimitry Andric 
8970eae32dcSDimitry Andric     // How far left do we need to shift the AND input?
8980eae32dcSDimitry Andric     unsigned XLen = Subtarget->getXLen();
8990eae32dcSDimitry Andric     unsigned LeadingZeros = XLen - (64 - countLeadingZeros(C2));
9000eae32dcSDimitry Andric 
9010eae32dcSDimitry Andric     // The constant gets shifted by the remaining amount unless that would
9020eae32dcSDimitry Andric     // shift bits out.
9030eae32dcSDimitry Andric     uint64_t C1 = N1C->getZExtValue();
9040eae32dcSDimitry Andric     unsigned ConstantShift = XLen - LeadingZeros;
9050eae32dcSDimitry Andric     if (ConstantShift > (XLen - (64 - countLeadingZeros(C1))))
9060eae32dcSDimitry Andric       break;
9070eae32dcSDimitry Andric 
9080eae32dcSDimitry Andric     uint64_t ShiftedC1 = C1 << ConstantShift;
9090eae32dcSDimitry Andric     // If this RV32, we need to sign extend the constant.
9100eae32dcSDimitry Andric     if (XLen == 32)
9110eae32dcSDimitry Andric       ShiftedC1 = SignExtend64(ShiftedC1, 32);
9120eae32dcSDimitry Andric 
9130eae32dcSDimitry Andric     // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))).
914*04eeddc0SDimitry Andric     SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget);
9150eae32dcSDimitry Andric     SDNode *SLLI =
9160eae32dcSDimitry Andric         CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0),
9170eae32dcSDimitry Andric                                CurDAG->getTargetConstant(LeadingZeros, DL, VT));
9180eae32dcSDimitry Andric     SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT,
9190eae32dcSDimitry Andric                                            SDValue(SLLI, 0), SDValue(Imm, 0));
9200eae32dcSDimitry Andric     ReplaceNode(Node, MULHU);
9210eae32dcSDimitry Andric     return;
9220eae32dcSDimitry Andric   }
923fe6060f1SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN: {
924fe6060f1SDimitry Andric     unsigned IntNo = Node->getConstantOperandVal(0);
925fe6060f1SDimitry Andric     switch (IntNo) {
926fe6060f1SDimitry Andric       // By default we do not custom select any intrinsic.
927fe6060f1SDimitry Andric     default:
928fe6060f1SDimitry Andric       break;
929fe6060f1SDimitry Andric     case Intrinsic::riscv_vmsgeu:
930fe6060f1SDimitry Andric     case Intrinsic::riscv_vmsge: {
931fe6060f1SDimitry Andric       SDValue Src1 = Node->getOperand(1);
932fe6060f1SDimitry Andric       SDValue Src2 = Node->getOperand(2);
933*04eeddc0SDimitry Andric       bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu;
934*04eeddc0SDimitry Andric       bool IsCmpUnsignedZero = false;
935fe6060f1SDimitry Andric       // Only custom select scalar second operand.
936fe6060f1SDimitry Andric       if (Src2.getValueType() != XLenVT)
937fe6060f1SDimitry Andric         break;
938fe6060f1SDimitry Andric       // Small constants are handled with patterns.
939fe6060f1SDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Src2)) {
940fe6060f1SDimitry Andric         int64_t CVal = C->getSExtValue();
941*04eeddc0SDimitry Andric         if (CVal >= -15 && CVal <= 16) {
942*04eeddc0SDimitry Andric           if (!IsUnsigned || CVal != 0)
943fe6060f1SDimitry Andric             break;
944*04eeddc0SDimitry Andric           IsCmpUnsignedZero = true;
945fe6060f1SDimitry Andric         }
946*04eeddc0SDimitry Andric       }
947fe6060f1SDimitry Andric       MVT Src1VT = Src1.getSimpleValueType();
948*04eeddc0SDimitry Andric       unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode;
949fe6060f1SDimitry Andric       switch (RISCVTargetLowering::getLMUL(Src1VT)) {
950fe6060f1SDimitry Andric       default:
951fe6060f1SDimitry Andric         llvm_unreachable("Unexpected LMUL!");
952*04eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b)            \
953*04eeddc0SDimitry Andric   case RISCVII::VLMUL::lmulenum:                                               \
954*04eeddc0SDimitry Andric     VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix                 \
955*04eeddc0SDimitry Andric                              : RISCV::PseudoVMSLT_VX_##suffix;                 \
956*04eeddc0SDimitry Andric     VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix;                            \
957*04eeddc0SDimitry Andric     VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b;                             \
958fe6060f1SDimitry Andric     break;
959*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1)
960*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2)
961*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4)
962*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8)
963*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16)
964*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32)
965*04eeddc0SDimitry Andric         CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64)
966*04eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES
967fe6060f1SDimitry Andric       }
968fe6060f1SDimitry Andric       SDValue SEW = CurDAG->getTargetConstant(
969fe6060f1SDimitry Andric           Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT);
970fe6060f1SDimitry Andric       SDValue VL;
971fe6060f1SDimitry Andric       selectVLOp(Node->getOperand(3), VL);
972fe6060f1SDimitry Andric 
973*04eeddc0SDimitry Andric       // If vmsgeu with 0 immediate, expand it to vmset.
974*04eeddc0SDimitry Andric       if (IsCmpUnsignedZero) {
975*04eeddc0SDimitry Andric         ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW));
976*04eeddc0SDimitry Andric         return;
977*04eeddc0SDimitry Andric       }
978*04eeddc0SDimitry Andric 
979fe6060f1SDimitry Andric       // Expand to
980fe6060f1SDimitry Andric       // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd
981fe6060f1SDimitry Andric       SDValue Cmp = SDValue(
982fe6060f1SDimitry Andric           CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}),
983fe6060f1SDimitry Andric           0);
984fe6060f1SDimitry Andric       ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT,
985fe6060f1SDimitry Andric                                                {Cmp, Cmp, VL, SEW}));
986fe6060f1SDimitry Andric       return;
987fe6060f1SDimitry Andric     }
988fe6060f1SDimitry Andric     case Intrinsic::riscv_vmsgeu_mask:
989fe6060f1SDimitry Andric     case Intrinsic::riscv_vmsge_mask: {
990fe6060f1SDimitry Andric       SDValue Src1 = Node->getOperand(2);
991fe6060f1SDimitry Andric       SDValue Src2 = Node->getOperand(3);
992*04eeddc0SDimitry Andric       bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask;
993*04eeddc0SDimitry Andric       bool IsCmpUnsignedZero = false;
994fe6060f1SDimitry Andric       // Only custom select scalar second operand.
995fe6060f1SDimitry Andric       if (Src2.getValueType() != XLenVT)
996fe6060f1SDimitry Andric         break;
997fe6060f1SDimitry Andric       // Small constants are handled with patterns.
998fe6060f1SDimitry Andric       if (auto *C = dyn_cast<ConstantSDNode>(Src2)) {
999fe6060f1SDimitry Andric         int64_t CVal = C->getSExtValue();
1000*04eeddc0SDimitry Andric         if (CVal >= -15 && CVal <= 16) {
1001*04eeddc0SDimitry Andric           if (!IsUnsigned || CVal != 0)
1002fe6060f1SDimitry Andric             break;
1003*04eeddc0SDimitry Andric           IsCmpUnsignedZero = true;
1004fe6060f1SDimitry Andric         }
1005*04eeddc0SDimitry Andric       }
1006fe6060f1SDimitry Andric       MVT Src1VT = Src1.getSimpleValueType();
1007*04eeddc0SDimitry Andric       unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode,
1008*04eeddc0SDimitry Andric           VMSetOpcode, VMANDOpcode;
1009fe6060f1SDimitry Andric       switch (RISCVTargetLowering::getLMUL(Src1VT)) {
1010fe6060f1SDimitry Andric       default:
1011fe6060f1SDimitry Andric         llvm_unreachable("Unexpected LMUL!");
1012*04eeddc0SDimitry Andric #define CASE_VMSLT_VMSET_OPCODES(lmulenum, suffix, suffix_b)                   \
1013*04eeddc0SDimitry Andric   case RISCVII::VLMUL::lmulenum:                                               \
1014*04eeddc0SDimitry Andric     VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix                 \
1015*04eeddc0SDimitry Andric                              : RISCV::PseudoVMSLT_VX_##suffix;                 \
1016*04eeddc0SDimitry Andric     VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK      \
1017*04eeddc0SDimitry Andric                                  : RISCV::PseudoVMSLT_VX_##suffix##_MASK;      \
1018*04eeddc0SDimitry Andric     VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b;                             \
1019fe6060f1SDimitry Andric     break;
1020*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_F8, MF8, B1)
1021*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_F4, MF4, B2)
1022*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_F2, MF2, B4)
1023*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_1, M1, B8)
1024*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_2, M2, B16)
1025*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_4, M4, B32)
1026*04eeddc0SDimitry Andric         CASE_VMSLT_VMSET_OPCODES(LMUL_8, M8, B64)
1027*04eeddc0SDimitry Andric #undef CASE_VMSLT_VMSET_OPCODES
1028fe6060f1SDimitry Andric       }
1029fe6060f1SDimitry Andric       // Mask operations use the LMUL from the mask type.
1030fe6060f1SDimitry Andric       switch (RISCVTargetLowering::getLMUL(VT)) {
1031fe6060f1SDimitry Andric       default:
1032fe6060f1SDimitry Andric         llvm_unreachable("Unexpected LMUL!");
1033*04eeddc0SDimitry Andric #define CASE_VMXOR_VMANDN_VMAND_OPCODES(lmulenum, suffix)                       \
1034*04eeddc0SDimitry Andric   case RISCVII::VLMUL::lmulenum:                                               \
1035*04eeddc0SDimitry Andric     VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix;                              \
1036*04eeddc0SDimitry Andric     VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix;                            \
1037*04eeddc0SDimitry Andric     VMANDOpcode = RISCV::PseudoVMAND_MM_##suffix;                              \
1038fe6060f1SDimitry Andric     break;
1039*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_F8, MF8)
1040*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_F4, MF4)
1041*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_F2, MF2)
1042*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_1, M1)
1043*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_2, M2)
1044*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_4, M4)
1045*04eeddc0SDimitry Andric         CASE_VMXOR_VMANDN_VMAND_OPCODES(LMUL_8, M8)
1046*04eeddc0SDimitry Andric #undef CASE_VMXOR_VMANDN_VMAND_OPCODES
1047fe6060f1SDimitry Andric       }
1048fe6060f1SDimitry Andric       SDValue SEW = CurDAG->getTargetConstant(
1049fe6060f1SDimitry Andric           Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT);
1050fe6060f1SDimitry Andric       SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT);
1051fe6060f1SDimitry Andric       SDValue VL;
1052fe6060f1SDimitry Andric       selectVLOp(Node->getOperand(5), VL);
1053fe6060f1SDimitry Andric       SDValue MaskedOff = Node->getOperand(1);
1054fe6060f1SDimitry Andric       SDValue Mask = Node->getOperand(4);
1055*04eeddc0SDimitry Andric 
1056*04eeddc0SDimitry Andric       // If vmsgeu_mask with 0 immediate, expand it to {vmset, vmand}.
1057*04eeddc0SDimitry Andric       if (IsCmpUnsignedZero) {
1058*04eeddc0SDimitry Andric         SDValue VMSet =
1059*04eeddc0SDimitry Andric             SDValue(CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW), 0);
1060*04eeddc0SDimitry Andric         ReplaceNode(Node, CurDAG->getMachineNode(VMANDOpcode, DL, VT,
1061*04eeddc0SDimitry Andric                                                  {Mask, VMSet, VL, MaskSEW}));
1062*04eeddc0SDimitry Andric         return;
1063*04eeddc0SDimitry Andric       }
1064*04eeddc0SDimitry Andric 
1065fe6060f1SDimitry Andric       // If the MaskedOff value and the Mask are the same value use
1066349cc55cSDimitry Andric       // vmslt{u}.vx vt, va, x;  vmandn.mm vd, vd, vt
1067fe6060f1SDimitry Andric       // This avoids needing to copy v0 to vd before starting the next sequence.
1068fe6060f1SDimitry Andric       if (Mask == MaskedOff) {
1069fe6060f1SDimitry Andric         SDValue Cmp = SDValue(
1070fe6060f1SDimitry Andric             CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}),
1071fe6060f1SDimitry Andric             0);
1072349cc55cSDimitry Andric         ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT,
1073fe6060f1SDimitry Andric                                                  {Mask, Cmp, VL, MaskSEW}));
1074fe6060f1SDimitry Andric         return;
1075fe6060f1SDimitry Andric       }
1076fe6060f1SDimitry Andric 
1077fe6060f1SDimitry Andric       // Mask needs to be copied to V0.
1078fe6060f1SDimitry Andric       SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
1079fe6060f1SDimitry Andric                                            RISCV::V0, Mask, SDValue());
1080fe6060f1SDimitry Andric       SDValue Glue = Chain.getValue(1);
1081fe6060f1SDimitry Andric       SDValue V0 = CurDAG->getRegister(RISCV::V0, VT);
1082fe6060f1SDimitry Andric 
1083fe6060f1SDimitry Andric       // Otherwise use
1084fe6060f1SDimitry Andric       // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0
1085fe6060f1SDimitry Andric       SDValue Cmp = SDValue(
1086fe6060f1SDimitry Andric           CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT,
1087fe6060f1SDimitry Andric                                  {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}),
1088fe6060f1SDimitry Andric           0);
1089fe6060f1SDimitry Andric       ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT,
1090fe6060f1SDimitry Andric                                                {Cmp, Mask, VL, MaskSEW}));
1091fe6060f1SDimitry Andric       return;
1092fe6060f1SDimitry Andric     }
1093*04eeddc0SDimitry Andric     case Intrinsic::riscv_vsetvli_opt:
1094*04eeddc0SDimitry Andric     case Intrinsic::riscv_vsetvlimax_opt:
1095*04eeddc0SDimitry Andric       return selectVSETVLI(Node);
1096fe6060f1SDimitry Andric     }
1097fe6060f1SDimitry Andric     break;
1098fe6060f1SDimitry Andric   }
1099e8d8bef9SDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
1100e8d8bef9SDimitry Andric     unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
1101e8d8bef9SDimitry Andric     switch (IntNo) {
1102e8d8bef9SDimitry Andric       // By default we do not custom select any intrinsic.
1103e8d8bef9SDimitry Andric     default:
11040b57cec5SDimitry Andric       break;
1105fe6060f1SDimitry Andric     case Intrinsic::riscv_vsetvli:
1106*04eeddc0SDimitry Andric     case Intrinsic::riscv_vsetvlimax:
1107*04eeddc0SDimitry Andric       return selectVSETVLI(Node);
1108e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg2:
1109e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg3:
1110e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg4:
1111e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg5:
1112e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg6:
1113e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg7:
1114e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg8: {
1115fe6060f1SDimitry Andric       selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false);
1116e8d8bef9SDimitry Andric       return;
1117e8d8bef9SDimitry Andric     }
1118e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg2_mask:
1119e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg3_mask:
1120e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg4_mask:
1121e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg5_mask:
1122e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg6_mask:
1123e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg7_mask:
1124e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlseg8_mask: {
1125fe6060f1SDimitry Andric       selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false);
1126e8d8bef9SDimitry Andric       return;
1127e8d8bef9SDimitry Andric     }
1128e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg2:
1129e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg3:
1130e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg4:
1131e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg5:
1132e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg6:
1133e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg7:
1134e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg8: {
1135fe6060f1SDimitry Andric       selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true);
1136e8d8bef9SDimitry Andric       return;
1137e8d8bef9SDimitry Andric     }
1138e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg2_mask:
1139e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg3_mask:
1140e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg4_mask:
1141e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg5_mask:
1142e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg6_mask:
1143e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg7_mask:
1144e8d8bef9SDimitry Andric     case Intrinsic::riscv_vlsseg8_mask: {
1145fe6060f1SDimitry Andric       selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true);
1146e8d8bef9SDimitry Andric       return;
1147e8d8bef9SDimitry Andric     }
1148e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg2:
1149e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg3:
1150e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg4:
1151e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg5:
1152e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg6:
1153e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg7:
1154e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg8:
1155fe6060f1SDimitry Andric       selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true);
1156fe6060f1SDimitry Andric       return;
1157e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg2:
1158e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg3:
1159e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg4:
1160e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg5:
1161e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg6:
1162e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg7:
1163fe6060f1SDimitry Andric     case Intrinsic::riscv_vluxseg8:
1164fe6060f1SDimitry Andric       selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false);
1165e8d8bef9SDimitry Andric       return;
1166e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg2_mask:
1167e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg3_mask:
1168e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg4_mask:
1169e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg5_mask:
1170e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg6_mask:
1171e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg7_mask:
1172e8d8bef9SDimitry Andric     case Intrinsic::riscv_vloxseg8_mask:
1173fe6060f1SDimitry Andric       selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true);
1174fe6060f1SDimitry Andric       return;
1175e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg2_mask:
1176e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg3_mask:
1177e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg4_mask:
1178e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg5_mask:
1179e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg6_mask:
1180e8d8bef9SDimitry Andric     case Intrinsic::riscv_vluxseg7_mask:
1181fe6060f1SDimitry Andric     case Intrinsic::riscv_vluxseg8_mask:
1182fe6060f1SDimitry Andric       selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false);
1183fe6060f1SDimitry Andric       return;
1184fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg8ff:
1185fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg7ff:
1186fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg6ff:
1187fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg5ff:
1188fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg4ff:
1189fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg3ff:
1190fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg2ff: {
1191fe6060f1SDimitry Andric       selectVLSEGFF(Node, /*IsMasked*/ false);
1192fe6060f1SDimitry Andric       return;
1193fe6060f1SDimitry Andric     }
1194fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg8ff_mask:
1195fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg7ff_mask:
1196fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg6ff_mask:
1197fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg5ff_mask:
1198fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg4ff_mask:
1199fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg3ff_mask:
1200fe6060f1SDimitry Andric     case Intrinsic::riscv_vlseg2ff_mask: {
1201fe6060f1SDimitry Andric       selectVLSEGFF(Node, /*IsMasked*/ true);
1202fe6060f1SDimitry Andric       return;
1203fe6060f1SDimitry Andric     }
1204fe6060f1SDimitry Andric     case Intrinsic::riscv_vloxei:
1205fe6060f1SDimitry Andric     case Intrinsic::riscv_vloxei_mask:
1206fe6060f1SDimitry Andric     case Intrinsic::riscv_vluxei:
1207fe6060f1SDimitry Andric     case Intrinsic::riscv_vluxei_mask: {
1208fe6060f1SDimitry Andric       bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask ||
1209fe6060f1SDimitry Andric                       IntNo == Intrinsic::riscv_vluxei_mask;
1210fe6060f1SDimitry Andric       bool IsOrdered = IntNo == Intrinsic::riscv_vloxei ||
1211fe6060f1SDimitry Andric                        IntNo == Intrinsic::riscv_vloxei_mask;
1212fe6060f1SDimitry Andric 
1213fe6060f1SDimitry Andric       MVT VT = Node->getSimpleValueType(0);
1214fe6060f1SDimitry Andric       unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1215fe6060f1SDimitry Andric 
1216fe6060f1SDimitry Andric       unsigned CurOp = 2;
1217*04eeddc0SDimitry Andric       // Masked intrinsic only have TU version pseduo instructions.
1218*04eeddc0SDimitry Andric       bool IsTU = IsMasked || (!IsMasked && !Node->getOperand(CurOp).isUndef());
1219fe6060f1SDimitry Andric       SmallVector<SDValue, 8> Operands;
1220*04eeddc0SDimitry Andric       if (IsTU)
1221fe6060f1SDimitry Andric         Operands.push_back(Node->getOperand(CurOp++));
1222*04eeddc0SDimitry Andric       else
1223*04eeddc0SDimitry Andric         // Skip the undef passthru operand for nomask TA version pseudo
1224*04eeddc0SDimitry Andric         CurOp++;
1225fe6060f1SDimitry Andric 
1226fe6060f1SDimitry Andric       MVT IndexVT;
1227fe6060f1SDimitry Andric       addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
1228fe6060f1SDimitry Andric                                  /*IsStridedOrIndexed*/ true, Operands,
1229349cc55cSDimitry Andric                                  /*IsLoad=*/true, &IndexVT);
1230fe6060f1SDimitry Andric 
1231fe6060f1SDimitry Andric       assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() &&
1232fe6060f1SDimitry Andric              "Element count mismatch");
1233fe6060f1SDimitry Andric 
1234fe6060f1SDimitry Andric       RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1235fe6060f1SDimitry Andric       RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT);
1236fe6060f1SDimitry Andric       unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits());
1237*04eeddc0SDimitry Andric       if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) {
1238*04eeddc0SDimitry Andric         report_fatal_error("The V extension does not support EEW=64 for index "
1239*04eeddc0SDimitry Andric                            "values when XLEN=32");
1240*04eeddc0SDimitry Andric       }
1241fe6060f1SDimitry Andric       const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo(
1242*04eeddc0SDimitry Andric           IsMasked, IsTU, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL),
1243fe6060f1SDimitry Andric           static_cast<unsigned>(IndexLMUL));
1244fe6060f1SDimitry Andric       MachineSDNode *Load =
1245fe6060f1SDimitry Andric           CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands);
1246fe6060f1SDimitry Andric 
1247fe6060f1SDimitry Andric       if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1248fe6060f1SDimitry Andric         CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
1249fe6060f1SDimitry Andric 
1250fe6060f1SDimitry Andric       ReplaceNode(Node, Load);
1251fe6060f1SDimitry Andric       return;
1252fe6060f1SDimitry Andric     }
1253349cc55cSDimitry Andric     case Intrinsic::riscv_vlm:
1254fe6060f1SDimitry Andric     case Intrinsic::riscv_vle:
1255fe6060f1SDimitry Andric     case Intrinsic::riscv_vle_mask:
1256fe6060f1SDimitry Andric     case Intrinsic::riscv_vlse:
1257fe6060f1SDimitry Andric     case Intrinsic::riscv_vlse_mask: {
1258fe6060f1SDimitry Andric       bool IsMasked = IntNo == Intrinsic::riscv_vle_mask ||
1259fe6060f1SDimitry Andric                       IntNo == Intrinsic::riscv_vlse_mask;
1260fe6060f1SDimitry Andric       bool IsStrided =
1261fe6060f1SDimitry Andric           IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask;
1262fe6060f1SDimitry Andric 
1263fe6060f1SDimitry Andric       MVT VT = Node->getSimpleValueType(0);
1264fe6060f1SDimitry Andric       unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1265fe6060f1SDimitry Andric 
1266fe6060f1SDimitry Andric       unsigned CurOp = 2;
1267*04eeddc0SDimitry Andric       // The riscv_vlm intrinsic are always tail agnostic and no passthru operand.
1268*04eeddc0SDimitry Andric       bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm;
1269*04eeddc0SDimitry Andric       // Masked intrinsic only have TU version pseduo instructions.
1270*04eeddc0SDimitry Andric       bool IsTU =
1271*04eeddc0SDimitry Andric           HasPassthruOperand &&
1272*04eeddc0SDimitry Andric           ((!IsMasked && !Node->getOperand(CurOp).isUndef()) || IsMasked);
1273fe6060f1SDimitry Andric       SmallVector<SDValue, 8> Operands;
1274*04eeddc0SDimitry Andric       if (IsTU)
1275fe6060f1SDimitry Andric         Operands.push_back(Node->getOperand(CurOp++));
1276*04eeddc0SDimitry Andric       else if (HasPassthruOperand)
1277*04eeddc0SDimitry Andric         // Skip the undef passthru operand for nomask TA version pseudo
1278*04eeddc0SDimitry Andric         CurOp++;
1279fe6060f1SDimitry Andric 
1280fe6060f1SDimitry Andric       addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided,
1281349cc55cSDimitry Andric                                  Operands, /*IsLoad=*/true);
1282fe6060f1SDimitry Andric 
1283fe6060f1SDimitry Andric       RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1284fe6060f1SDimitry Andric       const RISCV::VLEPseudo *P =
1285*04eeddc0SDimitry Andric           RISCV::getVLEPseudo(IsMasked, IsTU, IsStrided, /*FF*/ false, Log2SEW,
1286fe6060f1SDimitry Andric                               static_cast<unsigned>(LMUL));
1287fe6060f1SDimitry Andric       MachineSDNode *Load =
1288fe6060f1SDimitry Andric           CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands);
1289fe6060f1SDimitry Andric 
1290fe6060f1SDimitry Andric       if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1291fe6060f1SDimitry Andric         CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
1292fe6060f1SDimitry Andric 
1293fe6060f1SDimitry Andric       ReplaceNode(Node, Load);
1294fe6060f1SDimitry Andric       return;
1295fe6060f1SDimitry Andric     }
1296fe6060f1SDimitry Andric     case Intrinsic::riscv_vleff:
1297fe6060f1SDimitry Andric     case Intrinsic::riscv_vleff_mask: {
1298fe6060f1SDimitry Andric       bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask;
1299fe6060f1SDimitry Andric 
1300fe6060f1SDimitry Andric       MVT VT = Node->getSimpleValueType(0);
1301fe6060f1SDimitry Andric       unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1302fe6060f1SDimitry Andric 
1303fe6060f1SDimitry Andric       unsigned CurOp = 2;
1304*04eeddc0SDimitry Andric       // Masked intrinsic only have TU version pseduo instructions.
1305*04eeddc0SDimitry Andric       bool IsTU = IsMasked || (!IsMasked && !Node->getOperand(CurOp).isUndef());
1306fe6060f1SDimitry Andric       SmallVector<SDValue, 7> Operands;
1307*04eeddc0SDimitry Andric       if (IsTU)
1308fe6060f1SDimitry Andric         Operands.push_back(Node->getOperand(CurOp++));
1309*04eeddc0SDimitry Andric       else
1310*04eeddc0SDimitry Andric         // Skip the undef passthru operand for nomask TA version pseudo
1311*04eeddc0SDimitry Andric         CurOp++;
1312fe6060f1SDimitry Andric 
1313fe6060f1SDimitry Andric       addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
1314349cc55cSDimitry Andric                                  /*IsStridedOrIndexed*/ false, Operands,
1315349cc55cSDimitry Andric                                  /*IsLoad=*/true);
1316fe6060f1SDimitry Andric 
1317fe6060f1SDimitry Andric       RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1318fe6060f1SDimitry Andric       const RISCV::VLEPseudo *P =
1319*04eeddc0SDimitry Andric           RISCV::getVLEPseudo(IsMasked, IsTU, /*Strided*/ false, /*FF*/ true,
1320*04eeddc0SDimitry Andric                               Log2SEW, static_cast<unsigned>(LMUL));
1321fe6060f1SDimitry Andric       MachineSDNode *Load =
1322fe6060f1SDimitry Andric           CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0),
1323fe6060f1SDimitry Andric                                  MVT::Other, MVT::Glue, Operands);
1324fe6060f1SDimitry Andric       SDNode *ReadVL = CurDAG->getMachineNode(RISCV::PseudoReadVL, DL, XLenVT,
1325fe6060f1SDimitry Andric                                               /*Glue*/ SDValue(Load, 2));
1326fe6060f1SDimitry Andric 
1327fe6060f1SDimitry Andric       if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1328fe6060f1SDimitry Andric         CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
1329fe6060f1SDimitry Andric 
1330fe6060f1SDimitry Andric       ReplaceUses(SDValue(Node, 0), SDValue(Load, 0));
1331fe6060f1SDimitry Andric       ReplaceUses(SDValue(Node, 1), SDValue(ReadVL, 0)); // VL
1332fe6060f1SDimitry Andric       ReplaceUses(SDValue(Node, 2), SDValue(Load, 1));   // Chain
1333fe6060f1SDimitry Andric       CurDAG->RemoveDeadNode(Node);
13340b57cec5SDimitry Andric       return;
13350b57cec5SDimitry Andric     }
13360b57cec5SDimitry Andric     }
13370b57cec5SDimitry Andric     break;
13380b57cec5SDimitry Andric   }
1339e8d8bef9SDimitry Andric   case ISD::INTRINSIC_VOID: {
1340e8d8bef9SDimitry Andric     unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
1341e8d8bef9SDimitry Andric     switch (IntNo) {
1342e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg2:
1343e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg3:
1344e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg4:
1345e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg5:
1346e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg6:
1347e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg7:
1348e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg8: {
1349fe6060f1SDimitry Andric       selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false);
13500b57cec5SDimitry Andric       return;
13510b57cec5SDimitry Andric     }
1352e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg2_mask:
1353e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg3_mask:
1354e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg4_mask:
1355e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg5_mask:
1356e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg6_mask:
1357e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg7_mask:
1358e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsseg8_mask: {
1359fe6060f1SDimitry Andric       selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false);
1360e8d8bef9SDimitry Andric       return;
1361e8d8bef9SDimitry Andric     }
1362e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg2:
1363e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg3:
1364e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg4:
1365e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg5:
1366e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg6:
1367e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg7:
1368e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg8: {
1369fe6060f1SDimitry Andric       selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true);
1370e8d8bef9SDimitry Andric       return;
1371e8d8bef9SDimitry Andric     }
1372e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg2_mask:
1373e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg3_mask:
1374e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg4_mask:
1375e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg5_mask:
1376e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg6_mask:
1377e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg7_mask:
1378e8d8bef9SDimitry Andric     case Intrinsic::riscv_vssseg8_mask: {
1379fe6060f1SDimitry Andric       selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true);
1380e8d8bef9SDimitry Andric       return;
1381e8d8bef9SDimitry Andric     }
1382e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg2:
1383e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg3:
1384e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg4:
1385e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg5:
1386e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg6:
1387e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg7:
1388e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg8:
1389fe6060f1SDimitry Andric       selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true);
1390fe6060f1SDimitry Andric       return;
1391e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg2:
1392e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg3:
1393e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg4:
1394e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg5:
1395e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg6:
1396e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg7:
1397fe6060f1SDimitry Andric     case Intrinsic::riscv_vsuxseg8:
1398fe6060f1SDimitry Andric       selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false);
1399e8d8bef9SDimitry Andric       return;
1400e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg2_mask:
1401e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg3_mask:
1402e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg4_mask:
1403e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg5_mask:
1404e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg6_mask:
1405e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg7_mask:
1406e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsoxseg8_mask:
1407fe6060f1SDimitry Andric       selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true);
1408fe6060f1SDimitry Andric       return;
1409e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg2_mask:
1410e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg3_mask:
1411e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg4_mask:
1412e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg5_mask:
1413e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg6_mask:
1414e8d8bef9SDimitry Andric     case Intrinsic::riscv_vsuxseg7_mask:
1415fe6060f1SDimitry Andric     case Intrinsic::riscv_vsuxseg8_mask:
1416fe6060f1SDimitry Andric       selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false);
1417fe6060f1SDimitry Andric       return;
1418fe6060f1SDimitry Andric     case Intrinsic::riscv_vsoxei:
1419fe6060f1SDimitry Andric     case Intrinsic::riscv_vsoxei_mask:
1420fe6060f1SDimitry Andric     case Intrinsic::riscv_vsuxei:
1421fe6060f1SDimitry Andric     case Intrinsic::riscv_vsuxei_mask: {
1422fe6060f1SDimitry Andric       bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask ||
1423fe6060f1SDimitry Andric                       IntNo == Intrinsic::riscv_vsuxei_mask;
1424fe6060f1SDimitry Andric       bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei ||
1425fe6060f1SDimitry Andric                        IntNo == Intrinsic::riscv_vsoxei_mask;
1426fe6060f1SDimitry Andric 
1427fe6060f1SDimitry Andric       MVT VT = Node->getOperand(2)->getSimpleValueType(0);
1428fe6060f1SDimitry Andric       unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1429fe6060f1SDimitry Andric 
1430fe6060f1SDimitry Andric       unsigned CurOp = 2;
1431fe6060f1SDimitry Andric       SmallVector<SDValue, 8> Operands;
1432fe6060f1SDimitry Andric       Operands.push_back(Node->getOperand(CurOp++)); // Store value.
1433fe6060f1SDimitry Andric 
1434fe6060f1SDimitry Andric       MVT IndexVT;
1435fe6060f1SDimitry Andric       addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked,
1436fe6060f1SDimitry Andric                                  /*IsStridedOrIndexed*/ true, Operands,
1437349cc55cSDimitry Andric                                  /*IsLoad=*/false, &IndexVT);
1438fe6060f1SDimitry Andric 
1439fe6060f1SDimitry Andric       assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() &&
1440fe6060f1SDimitry Andric              "Element count mismatch");
1441fe6060f1SDimitry Andric 
1442fe6060f1SDimitry Andric       RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1443fe6060f1SDimitry Andric       RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT);
1444fe6060f1SDimitry Andric       unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits());
1445*04eeddc0SDimitry Andric       if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) {
1446*04eeddc0SDimitry Andric         report_fatal_error("The V extension does not support EEW=64 for index "
1447*04eeddc0SDimitry Andric                            "values when XLEN=32");
1448*04eeddc0SDimitry Andric       }
1449fe6060f1SDimitry Andric       const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo(
1450*04eeddc0SDimitry Andric           IsMasked, /*TU*/ false, IsOrdered, IndexLog2EEW,
1451*04eeddc0SDimitry Andric           static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL));
1452fe6060f1SDimitry Andric       MachineSDNode *Store =
1453fe6060f1SDimitry Andric           CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands);
1454fe6060f1SDimitry Andric 
1455fe6060f1SDimitry Andric       if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1456fe6060f1SDimitry Andric         CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()});
1457fe6060f1SDimitry Andric 
1458fe6060f1SDimitry Andric       ReplaceNode(Node, Store);
1459fe6060f1SDimitry Andric       return;
1460fe6060f1SDimitry Andric     }
1461349cc55cSDimitry Andric     case Intrinsic::riscv_vsm:
1462fe6060f1SDimitry Andric     case Intrinsic::riscv_vse:
1463fe6060f1SDimitry Andric     case Intrinsic::riscv_vse_mask:
1464fe6060f1SDimitry Andric     case Intrinsic::riscv_vsse:
1465fe6060f1SDimitry Andric     case Intrinsic::riscv_vsse_mask: {
1466fe6060f1SDimitry Andric       bool IsMasked = IntNo == Intrinsic::riscv_vse_mask ||
1467fe6060f1SDimitry Andric                       IntNo == Intrinsic::riscv_vsse_mask;
1468fe6060f1SDimitry Andric       bool IsStrided =
1469fe6060f1SDimitry Andric           IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask;
1470fe6060f1SDimitry Andric 
1471fe6060f1SDimitry Andric       MVT VT = Node->getOperand(2)->getSimpleValueType(0);
1472fe6060f1SDimitry Andric       unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1473fe6060f1SDimitry Andric 
1474fe6060f1SDimitry Andric       unsigned CurOp = 2;
1475fe6060f1SDimitry Andric       SmallVector<SDValue, 8> Operands;
1476fe6060f1SDimitry Andric       Operands.push_back(Node->getOperand(CurOp++)); // Store value.
1477fe6060f1SDimitry Andric 
1478fe6060f1SDimitry Andric       addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided,
1479fe6060f1SDimitry Andric                                  Operands);
1480fe6060f1SDimitry Andric 
1481fe6060f1SDimitry Andric       RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1482fe6060f1SDimitry Andric       const RISCV::VSEPseudo *P = RISCV::getVSEPseudo(
1483fe6060f1SDimitry Andric           IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL));
1484fe6060f1SDimitry Andric       MachineSDNode *Store =
1485fe6060f1SDimitry Andric           CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands);
1486fe6060f1SDimitry Andric       if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1487fe6060f1SDimitry Andric         CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()});
1488fe6060f1SDimitry Andric 
1489fe6060f1SDimitry Andric       ReplaceNode(Node, Store);
1490e8d8bef9SDimitry Andric       return;
1491e8d8bef9SDimitry Andric     }
1492e8d8bef9SDimitry Andric     }
1493e8d8bef9SDimitry Andric     break;
1494e8d8bef9SDimitry Andric   }
1495fe6060f1SDimitry Andric   case ISD::BITCAST: {
1496fe6060f1SDimitry Andric     MVT SrcVT = Node->getOperand(0).getSimpleValueType();
1497fe6060f1SDimitry Andric     // Just drop bitcasts between vectors if both are fixed or both are
1498fe6060f1SDimitry Andric     // scalable.
1499fe6060f1SDimitry Andric     if ((VT.isScalableVector() && SrcVT.isScalableVector()) ||
1500fe6060f1SDimitry Andric         (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) {
1501fe6060f1SDimitry Andric       ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
1502fe6060f1SDimitry Andric       CurDAG->RemoveDeadNode(Node);
1503e8d8bef9SDimitry Andric       return;
1504e8d8bef9SDimitry Andric     }
1505fe6060f1SDimitry Andric     break;
1506fe6060f1SDimitry Andric   }
1507fe6060f1SDimitry Andric   case ISD::INSERT_SUBVECTOR: {
1508fe6060f1SDimitry Andric     SDValue V = Node->getOperand(0);
1509fe6060f1SDimitry Andric     SDValue SubV = Node->getOperand(1);
1510fe6060f1SDimitry Andric     SDLoc DL(SubV);
1511fe6060f1SDimitry Andric     auto Idx = Node->getConstantOperandVal(2);
1512fe6060f1SDimitry Andric     MVT SubVecVT = SubV.getSimpleValueType();
1513fe6060f1SDimitry Andric 
1514fe6060f1SDimitry Andric     const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering();
1515fe6060f1SDimitry Andric     MVT SubVecContainerVT = SubVecVT;
1516fe6060f1SDimitry Andric     // Establish the correct scalable-vector types for any fixed-length type.
1517fe6060f1SDimitry Andric     if (SubVecVT.isFixedLengthVector())
1518fe6060f1SDimitry Andric       SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT);
1519fe6060f1SDimitry Andric     if (VT.isFixedLengthVector())
1520fe6060f1SDimitry Andric       VT = TLI.getContainerForFixedLengthVector(VT);
1521fe6060f1SDimitry Andric 
1522fe6060f1SDimitry Andric     const auto *TRI = Subtarget->getRegisterInfo();
1523fe6060f1SDimitry Andric     unsigned SubRegIdx;
1524fe6060f1SDimitry Andric     std::tie(SubRegIdx, Idx) =
1525fe6060f1SDimitry Andric         RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs(
1526fe6060f1SDimitry Andric             VT, SubVecContainerVT, Idx, TRI);
1527fe6060f1SDimitry Andric 
1528fe6060f1SDimitry Andric     // If the Idx hasn't been completely eliminated then this is a subvector
1529fe6060f1SDimitry Andric     // insert which doesn't naturally align to a vector register. These must
1530fe6060f1SDimitry Andric     // be handled using instructions to manipulate the vector registers.
1531fe6060f1SDimitry Andric     if (Idx != 0)
1532fe6060f1SDimitry Andric       break;
1533fe6060f1SDimitry Andric 
1534fe6060f1SDimitry Andric     RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT);
1535fe6060f1SDimitry Andric     bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 ||
1536fe6060f1SDimitry Andric                            SubVecLMUL == RISCVII::VLMUL::LMUL_F4 ||
1537fe6060f1SDimitry Andric                            SubVecLMUL == RISCVII::VLMUL::LMUL_F8;
1538fe6060f1SDimitry Andric     (void)IsSubVecPartReg; // Silence unused variable warning without asserts.
1539fe6060f1SDimitry Andric     assert((!IsSubVecPartReg || V.isUndef()) &&
1540fe6060f1SDimitry Andric            "Expecting lowering to have created legal INSERT_SUBVECTORs when "
1541fe6060f1SDimitry Andric            "the subvector is smaller than a full-sized register");
1542fe6060f1SDimitry Andric 
1543fe6060f1SDimitry Andric     // If we haven't set a SubRegIdx, then we must be going between
1544fe6060f1SDimitry Andric     // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy.
1545fe6060f1SDimitry Andric     if (SubRegIdx == RISCV::NoSubRegister) {
1546fe6060f1SDimitry Andric       unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT);
1547fe6060f1SDimitry Andric       assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) ==
1548fe6060f1SDimitry Andric                  InRegClassID &&
1549fe6060f1SDimitry Andric              "Unexpected subvector extraction");
1550fe6060f1SDimitry Andric       SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT);
1551fe6060f1SDimitry Andric       SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS,
1552fe6060f1SDimitry Andric                                                DL, VT, SubV, RC);
1553fe6060f1SDimitry Andric       ReplaceNode(Node, NewNode);
1554fe6060f1SDimitry Andric       return;
1555fe6060f1SDimitry Andric     }
1556fe6060f1SDimitry Andric 
1557fe6060f1SDimitry Andric     SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV);
1558fe6060f1SDimitry Andric     ReplaceNode(Node, Insert.getNode());
1559fe6060f1SDimitry Andric     return;
1560fe6060f1SDimitry Andric   }
1561fe6060f1SDimitry Andric   case ISD::EXTRACT_SUBVECTOR: {
1562fe6060f1SDimitry Andric     SDValue V = Node->getOperand(0);
1563fe6060f1SDimitry Andric     auto Idx = Node->getConstantOperandVal(1);
1564fe6060f1SDimitry Andric     MVT InVT = V.getSimpleValueType();
1565fe6060f1SDimitry Andric     SDLoc DL(V);
1566fe6060f1SDimitry Andric 
1567fe6060f1SDimitry Andric     const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering();
1568fe6060f1SDimitry Andric     MVT SubVecContainerVT = VT;
1569fe6060f1SDimitry Andric     // Establish the correct scalable-vector types for any fixed-length type.
1570fe6060f1SDimitry Andric     if (VT.isFixedLengthVector())
1571fe6060f1SDimitry Andric       SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT);
1572fe6060f1SDimitry Andric     if (InVT.isFixedLengthVector())
1573fe6060f1SDimitry Andric       InVT = TLI.getContainerForFixedLengthVector(InVT);
1574fe6060f1SDimitry Andric 
1575fe6060f1SDimitry Andric     const auto *TRI = Subtarget->getRegisterInfo();
1576fe6060f1SDimitry Andric     unsigned SubRegIdx;
1577fe6060f1SDimitry Andric     std::tie(SubRegIdx, Idx) =
1578fe6060f1SDimitry Andric         RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs(
1579fe6060f1SDimitry Andric             InVT, SubVecContainerVT, Idx, TRI);
1580fe6060f1SDimitry Andric 
1581fe6060f1SDimitry Andric     // If the Idx hasn't been completely eliminated then this is a subvector
1582fe6060f1SDimitry Andric     // extract which doesn't naturally align to a vector register. These must
1583fe6060f1SDimitry Andric     // be handled using instructions to manipulate the vector registers.
1584fe6060f1SDimitry Andric     if (Idx != 0)
1585fe6060f1SDimitry Andric       break;
1586fe6060f1SDimitry Andric 
1587fe6060f1SDimitry Andric     // If we haven't set a SubRegIdx, then we must be going between
1588fe6060f1SDimitry Andric     // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy.
1589fe6060f1SDimitry Andric     if (SubRegIdx == RISCV::NoSubRegister) {
1590fe6060f1SDimitry Andric       unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT);
1591fe6060f1SDimitry Andric       assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) ==
1592fe6060f1SDimitry Andric                  InRegClassID &&
1593fe6060f1SDimitry Andric              "Unexpected subvector extraction");
1594fe6060f1SDimitry Andric       SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT);
1595fe6060f1SDimitry Andric       SDNode *NewNode =
1596fe6060f1SDimitry Andric           CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC);
1597fe6060f1SDimitry Andric       ReplaceNode(Node, NewNode);
1598fe6060f1SDimitry Andric       return;
1599fe6060f1SDimitry Andric     }
1600fe6060f1SDimitry Andric 
1601fe6060f1SDimitry Andric     SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V);
1602fe6060f1SDimitry Andric     ReplaceNode(Node, Extract.getNode());
1603fe6060f1SDimitry Andric     return;
1604fe6060f1SDimitry Andric   }
16050eae32dcSDimitry Andric   case ISD::SPLAT_VECTOR:
1606*04eeddc0SDimitry Andric   case RISCVISD::VMV_S_X_VL:
1607*04eeddc0SDimitry Andric   case RISCVISD::VFMV_S_F_VL:
1608fe6060f1SDimitry Andric   case RISCVISD::VMV_V_X_VL:
1609fe6060f1SDimitry Andric   case RISCVISD::VFMV_V_F_VL: {
1610fe6060f1SDimitry Andric     // Try to match splat of a scalar load to a strided load with stride of x0.
1611*04eeddc0SDimitry Andric     bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL ||
1612*04eeddc0SDimitry Andric                         Node->getOpcode() == RISCVISD::VFMV_S_F_VL;
1613*04eeddc0SDimitry Andric     if (IsScalarMove && !Node->getOperand(0).isUndef())
1614*04eeddc0SDimitry Andric       break;
1615*04eeddc0SDimitry Andric     SDValue Src = IsScalarMove ? Node->getOperand(1) : Node->getOperand(0);
1616fe6060f1SDimitry Andric     auto *Ld = dyn_cast<LoadSDNode>(Src);
1617fe6060f1SDimitry Andric     if (!Ld)
1618fe6060f1SDimitry Andric       break;
1619fe6060f1SDimitry Andric     EVT MemVT = Ld->getMemoryVT();
1620fe6060f1SDimitry Andric     // The memory VT should be the same size as the element type.
1621fe6060f1SDimitry Andric     if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize())
1622fe6060f1SDimitry Andric       break;
1623fe6060f1SDimitry Andric     if (!IsProfitableToFold(Src, Node, Node) ||
1624fe6060f1SDimitry Andric         !IsLegalToFold(Src, Node, Node, TM.getOptLevel()))
1625fe6060f1SDimitry Andric       break;
1626fe6060f1SDimitry Andric 
1627fe6060f1SDimitry Andric     SDValue VL;
16280eae32dcSDimitry Andric     if (Node->getOpcode() == ISD::SPLAT_VECTOR)
16290eae32dcSDimitry Andric       VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, DL, XLenVT);
1630*04eeddc0SDimitry Andric     else if (IsScalarMove) {
1631*04eeddc0SDimitry Andric       // We could deal with more VL if we update the VSETVLI insert pass to
1632*04eeddc0SDimitry Andric       // avoid introducing more VSETVLI.
1633*04eeddc0SDimitry Andric       if (!isOneConstant(Node->getOperand(2)))
1634*04eeddc0SDimitry Andric         break;
1635*04eeddc0SDimitry Andric       selectVLOp(Node->getOperand(2), VL);
1636*04eeddc0SDimitry Andric     } else
1637fe6060f1SDimitry Andric       selectVLOp(Node->getOperand(1), VL);
1638fe6060f1SDimitry Andric 
1639fe6060f1SDimitry Andric     unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits());
1640fe6060f1SDimitry Andric     SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT);
1641fe6060f1SDimitry Andric 
1642fe6060f1SDimitry Andric     SDValue Operands[] = {Ld->getBasePtr(),
1643fe6060f1SDimitry Andric                           CurDAG->getRegister(RISCV::X0, XLenVT), VL, SEW,
1644fe6060f1SDimitry Andric                           Ld->getChain()};
1645fe6060f1SDimitry Andric 
1646fe6060f1SDimitry Andric     RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT);
1647fe6060f1SDimitry Andric     const RISCV::VLEPseudo *P = RISCV::getVLEPseudo(
1648*04eeddc0SDimitry Andric         /*IsMasked*/ false, /*IsTU*/ false, /*IsStrided*/ true, /*FF*/ false,
1649*04eeddc0SDimitry Andric         Log2SEW, static_cast<unsigned>(LMUL));
1650fe6060f1SDimitry Andric     MachineSDNode *Load =
1651fe6060f1SDimitry Andric         CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands);
1652fe6060f1SDimitry Andric 
1653fe6060f1SDimitry Andric     if (auto *MemOp = dyn_cast<MemSDNode>(Node))
1654fe6060f1SDimitry Andric       CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()});
1655fe6060f1SDimitry Andric 
1656fe6060f1SDimitry Andric     ReplaceNode(Node, Load);
1657e8d8bef9SDimitry Andric     return;
1658e8d8bef9SDimitry Andric   }
1659e8d8bef9SDimitry Andric   }
16600b57cec5SDimitry Andric 
16610b57cec5SDimitry Andric   // Select the default instruction.
16620b57cec5SDimitry Andric   SelectCode(Node);
16630b57cec5SDimitry Andric }
16640b57cec5SDimitry Andric 
16650b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(
16660b57cec5SDimitry Andric     const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
16670b57cec5SDimitry Andric   switch (ConstraintID) {
16680b57cec5SDimitry Andric   case InlineAsm::Constraint_m:
16690b57cec5SDimitry Andric     // We just support simple memory operands that have a single address
16700b57cec5SDimitry Andric     // operand and need no special handling.
16710b57cec5SDimitry Andric     OutOps.push_back(Op);
16720b57cec5SDimitry Andric     return false;
16730b57cec5SDimitry Andric   case InlineAsm::Constraint_A:
16740b57cec5SDimitry Andric     OutOps.push_back(Op);
16750b57cec5SDimitry Andric     return false;
16760b57cec5SDimitry Andric   default:
16770b57cec5SDimitry Andric     break;
16780b57cec5SDimitry Andric   }
16790b57cec5SDimitry Andric 
16800b57cec5SDimitry Andric   return true;
16810b57cec5SDimitry Andric }
16820b57cec5SDimitry Andric 
16830b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
1684fe6060f1SDimitry Andric   if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
16850b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
16860b57cec5SDimitry Andric     return true;
16870b57cec5SDimitry Andric   }
16880b57cec5SDimitry Andric   return false;
16890b57cec5SDimitry Andric }
16900b57cec5SDimitry Andric 
1691fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
1692fe6060f1SDimitry Andric   // If this is FrameIndex, select it directly. Otherwise just let it get
1693fe6060f1SDimitry Andric   // selected to a register independently.
1694fe6060f1SDimitry Andric   if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
1695fe6060f1SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
1696fe6060f1SDimitry Andric   else
1697fe6060f1SDimitry Andric     Base = Addr;
1698fe6060f1SDimitry Andric   return true;
1699e8d8bef9SDimitry Andric }
1700e8d8bef9SDimitry Andric 
1701fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
1702fe6060f1SDimitry Andric                                         SDValue &ShAmt) {
1703fe6060f1SDimitry Andric   // Shift instructions on RISCV only read the lower 5 or 6 bits of the shift
1704fe6060f1SDimitry Andric   // amount. If there is an AND on the shift amount, we can bypass it if it
1705fe6060f1SDimitry Andric   // doesn't affect any of those bits.
1706fe6060f1SDimitry Andric   if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
1707fe6060f1SDimitry Andric     const APInt &AndMask = N->getConstantOperandAPInt(1);
1708979e22ffSDimitry Andric 
1709fe6060f1SDimitry Andric     // Since the max shift amount is a power of 2 we can subtract 1 to make a
1710fe6060f1SDimitry Andric     // mask that covers the bits needed to represent all shift amounts.
1711fe6060f1SDimitry Andric     assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
1712fe6060f1SDimitry Andric     APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
1713e8d8bef9SDimitry Andric 
1714fe6060f1SDimitry Andric     if (ShMask.isSubsetOf(AndMask)) {
1715fe6060f1SDimitry Andric       ShAmt = N.getOperand(0);
1716fe6060f1SDimitry Andric       return true;
1717e8d8bef9SDimitry Andric     }
1718e8d8bef9SDimitry Andric 
1719fe6060f1SDimitry Andric     // SimplifyDemandedBits may have optimized the mask so try restoring any
1720fe6060f1SDimitry Andric     // bits that are known zero.
1721fe6060f1SDimitry Andric     KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
1722fe6060f1SDimitry Andric     if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
1723fe6060f1SDimitry Andric       ShAmt = N.getOperand(0);
1724fe6060f1SDimitry Andric       return true;
1725fe6060f1SDimitry Andric     }
1726fe6060f1SDimitry Andric   }
1727fe6060f1SDimitry Andric 
1728fe6060f1SDimitry Andric   ShAmt = N;
1729fe6060f1SDimitry Andric   return true;
1730fe6060f1SDimitry Andric }
1731fe6060f1SDimitry Andric 
1732fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
1733fe6060f1SDimitry Andric   if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
1734fe6060f1SDimitry Andric       cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
1735fe6060f1SDimitry Andric     Val = N.getOperand(0);
1736fe6060f1SDimitry Andric     return true;
1737fe6060f1SDimitry Andric   }
1738fe6060f1SDimitry Andric   MVT VT = N.getSimpleValueType();
1739fe6060f1SDimitry Andric   if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
1740fe6060f1SDimitry Andric     Val = N;
1741fe6060f1SDimitry Andric     return true;
1742fe6060f1SDimitry Andric   }
1743fe6060f1SDimitry Andric 
1744fe6060f1SDimitry Andric   return false;
1745fe6060f1SDimitry Andric }
1746fe6060f1SDimitry Andric 
1747fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
1748fe6060f1SDimitry Andric   if (N.getOpcode() == ISD::AND) {
1749fe6060f1SDimitry Andric     auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
1750fe6060f1SDimitry Andric     if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
1751fe6060f1SDimitry Andric       Val = N.getOperand(0);
1752fe6060f1SDimitry Andric       return true;
1753fe6060f1SDimitry Andric     }
1754fe6060f1SDimitry Andric   }
1755fe6060f1SDimitry Andric   MVT VT = N.getSimpleValueType();
1756fe6060f1SDimitry Andric   APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
1757fe6060f1SDimitry Andric   if (CurDAG->MaskedValueIsZero(N, Mask)) {
1758fe6060f1SDimitry Andric     Val = N;
1759fe6060f1SDimitry Andric     return true;
1760fe6060f1SDimitry Andric   }
1761fe6060f1SDimitry Andric 
1762fe6060f1SDimitry Andric   return false;
1763fe6060f1SDimitry Andric }
1764fe6060f1SDimitry Andric 
1765349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits.
1766349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the
1767349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if
1768349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some
1769349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave
1770349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we
1771349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if
1772349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists
1773349cc55cSDimitry Andric // before doing this, but that would be more complicated.
1774349cc55cSDimitry Andric // TODO: Does this need to look through AND/OR/XOR to their users to find more
1775349cc55cSDimitry Andric // opportunities.
1776349cc55cSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits) const {
1777349cc55cSDimitry Andric   assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB ||
1778349cc55cSDimitry Andric           Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL ||
1779349cc55cSDimitry Andric           Node->getOpcode() == ISD::SRL ||
1780349cc55cSDimitry Andric           Node->getOpcode() == ISD::SIGN_EXTEND_INREG ||
1781349cc55cSDimitry Andric           isa<ConstantSDNode>(Node)) &&
1782349cc55cSDimitry Andric          "Unexpected opcode");
1783349cc55cSDimitry Andric 
1784349cc55cSDimitry Andric   for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) {
1785349cc55cSDimitry Andric     SDNode *User = *UI;
1786349cc55cSDimitry Andric     // Users of this node should have already been instruction selected
1787349cc55cSDimitry Andric     if (!User->isMachineOpcode())
1788349cc55cSDimitry Andric       return false;
1789349cc55cSDimitry Andric 
1790349cc55cSDimitry Andric     // TODO: Add more opcodes?
1791349cc55cSDimitry Andric     switch (User->getMachineOpcode()) {
1792349cc55cSDimitry Andric     default:
1793349cc55cSDimitry Andric       return false;
1794349cc55cSDimitry Andric     case RISCV::ADDW:
1795349cc55cSDimitry Andric     case RISCV::ADDIW:
1796349cc55cSDimitry Andric     case RISCV::SUBW:
1797349cc55cSDimitry Andric     case RISCV::MULW:
1798349cc55cSDimitry Andric     case RISCV::SLLW:
1799349cc55cSDimitry Andric     case RISCV::SLLIW:
1800349cc55cSDimitry Andric     case RISCV::SRAW:
1801349cc55cSDimitry Andric     case RISCV::SRAIW:
1802349cc55cSDimitry Andric     case RISCV::SRLW:
1803349cc55cSDimitry Andric     case RISCV::SRLIW:
1804349cc55cSDimitry Andric     case RISCV::DIVW:
1805349cc55cSDimitry Andric     case RISCV::DIVUW:
1806349cc55cSDimitry Andric     case RISCV::REMW:
1807349cc55cSDimitry Andric     case RISCV::REMUW:
1808349cc55cSDimitry Andric     case RISCV::ROLW:
1809349cc55cSDimitry Andric     case RISCV::RORW:
1810349cc55cSDimitry Andric     case RISCV::RORIW:
1811349cc55cSDimitry Andric     case RISCV::CLZW:
1812349cc55cSDimitry Andric     case RISCV::CTZW:
1813349cc55cSDimitry Andric     case RISCV::CPOPW:
1814349cc55cSDimitry Andric     case RISCV::SLLIUW:
1815349cc55cSDimitry Andric     case RISCV::FCVT_H_W:
1816349cc55cSDimitry Andric     case RISCV::FCVT_H_WU:
1817349cc55cSDimitry Andric     case RISCV::FCVT_S_W:
1818349cc55cSDimitry Andric     case RISCV::FCVT_S_WU:
1819349cc55cSDimitry Andric     case RISCV::FCVT_D_W:
1820349cc55cSDimitry Andric     case RISCV::FCVT_D_WU:
1821349cc55cSDimitry Andric       if (Bits < 32)
1822349cc55cSDimitry Andric         return false;
1823349cc55cSDimitry Andric       break;
1824349cc55cSDimitry Andric     case RISCV::SLLI:
1825349cc55cSDimitry Andric       // SLLI only uses the lower (XLen - ShAmt) bits.
1826349cc55cSDimitry Andric       if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1))
1827349cc55cSDimitry Andric         return false;
1828349cc55cSDimitry Andric       break;
1829*04eeddc0SDimitry Andric     case RISCV::ANDI:
1830*04eeddc0SDimitry Andric       if (Bits < (64 - countLeadingZeros(User->getConstantOperandVal(1))))
1831*04eeddc0SDimitry Andric         return false;
1832*04eeddc0SDimitry Andric       break;
1833*04eeddc0SDimitry Andric     case RISCV::SEXTB:
1834*04eeddc0SDimitry Andric       if (Bits < 8)
1835*04eeddc0SDimitry Andric         return false;
1836*04eeddc0SDimitry Andric       break;
1837*04eeddc0SDimitry Andric     case RISCV::SEXTH:
1838*04eeddc0SDimitry Andric     case RISCV::ZEXTH_RV32:
1839*04eeddc0SDimitry Andric     case RISCV::ZEXTH_RV64:
1840*04eeddc0SDimitry Andric       if (Bits < 16)
1841*04eeddc0SDimitry Andric         return false;
1842*04eeddc0SDimitry Andric       break;
1843349cc55cSDimitry Andric     case RISCV::ADDUW:
1844349cc55cSDimitry Andric     case RISCV::SH1ADDUW:
1845349cc55cSDimitry Andric     case RISCV::SH2ADDUW:
1846349cc55cSDimitry Andric     case RISCV::SH3ADDUW:
1847349cc55cSDimitry Andric       // The first operand to add.uw/shXadd.uw is implicitly zero extended from
1848349cc55cSDimitry Andric       // 32 bits.
1849349cc55cSDimitry Andric       if (UI.getOperandNo() != 0 || Bits < 32)
1850349cc55cSDimitry Andric         return false;
1851349cc55cSDimitry Andric       break;
1852349cc55cSDimitry Andric     case RISCV::SB:
1853349cc55cSDimitry Andric       if (UI.getOperandNo() != 0 || Bits < 8)
1854349cc55cSDimitry Andric         return false;
1855349cc55cSDimitry Andric       break;
1856349cc55cSDimitry Andric     case RISCV::SH:
1857349cc55cSDimitry Andric       if (UI.getOperandNo() != 0 || Bits < 16)
1858349cc55cSDimitry Andric         return false;
1859349cc55cSDimitry Andric       break;
1860349cc55cSDimitry Andric     case RISCV::SW:
1861349cc55cSDimitry Andric       if (UI.getOperandNo() != 0 || Bits < 32)
1862349cc55cSDimitry Andric         return false;
1863349cc55cSDimitry Andric       break;
1864349cc55cSDimitry Andric     }
1865349cc55cSDimitry Andric   }
1866349cc55cSDimitry Andric 
1867349cc55cSDimitry Andric   return true;
1868349cc55cSDimitry Andric }
1869349cc55cSDimitry Andric 
1870fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This
1871fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later.
1872d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) {
1873d409305fSDimitry Andric   auto *C = dyn_cast<ConstantSDNode>(N);
1874*04eeddc0SDimitry Andric   if (C && (isUInt<5>(C->getZExtValue()) ||
1875*04eeddc0SDimitry Andric             C->getSExtValue() == RISCV::VLMaxSentinel))
1876fe6060f1SDimitry Andric     VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N),
1877fe6060f1SDimitry Andric                                    N->getValueType(0));
1878d409305fSDimitry Andric   else
1879d409305fSDimitry Andric     VL = N;
1880d409305fSDimitry Andric 
1881d409305fSDimitry Andric   return true;
1882d409305fSDimitry Andric }
1883d409305fSDimitry Andric 
1884e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) {
1885e8d8bef9SDimitry Andric   if (N.getOpcode() != ISD::SPLAT_VECTOR &&
1886fe6060f1SDimitry Andric       N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 &&
1887fe6060f1SDimitry Andric       N.getOpcode() != RISCVISD::VMV_V_X_VL)
1888e8d8bef9SDimitry Andric     return false;
1889e8d8bef9SDimitry Andric   SplatVal = N.getOperand(0);
1890979e22ffSDimitry Andric   return true;
1891979e22ffSDimitry Andric }
1892e8d8bef9SDimitry Andric 
1893fe6060f1SDimitry Andric using ValidateFn = bool (*)(int64_t);
1894fe6060f1SDimitry Andric 
1895fe6060f1SDimitry Andric static bool selectVSplatSimmHelper(SDValue N, SDValue &SplatVal,
1896fe6060f1SDimitry Andric                                    SelectionDAG &DAG,
1897fe6060f1SDimitry Andric                                    const RISCVSubtarget &Subtarget,
1898fe6060f1SDimitry Andric                                    ValidateFn ValidateImm) {
1899e8d8bef9SDimitry Andric   if ((N.getOpcode() != ISD::SPLAT_VECTOR &&
1900fe6060f1SDimitry Andric        N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 &&
1901fe6060f1SDimitry Andric        N.getOpcode() != RISCVISD::VMV_V_X_VL) ||
1902e8d8bef9SDimitry Andric       !isa<ConstantSDNode>(N.getOperand(0)))
1903979e22ffSDimitry Andric     return false;
1904e8d8bef9SDimitry Andric 
1905e8d8bef9SDimitry Andric   int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue();
1906e8d8bef9SDimitry Andric 
1907fe6060f1SDimitry Andric   // ISD::SPLAT_VECTOR, RISCVISD::SPLAT_VECTOR_I64 and RISCVISD::VMV_V_X_VL
1908fe6060f1SDimitry Andric   // share semantics when the operand type is wider than the resulting vector
1909fe6060f1SDimitry Andric   // element type: an implicit truncation first takes place. Therefore, perform
1910fe6060f1SDimitry Andric   // a manual truncation/sign-extension in order to ignore any truncated bits
1911fe6060f1SDimitry Andric   // and catch any zero-extended immediate.
1912e8d8bef9SDimitry Andric   // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first
1913e8d8bef9SDimitry Andric   // sign-extending to (XLenVT -1).
1914fe6060f1SDimitry Andric   MVT XLenVT = Subtarget.getXLenVT();
1915e8d8bef9SDimitry Andric   assert(XLenVT == N.getOperand(0).getSimpleValueType() &&
1916e8d8bef9SDimitry Andric          "Unexpected splat operand type");
1917fe6060f1SDimitry Andric   MVT EltVT = N.getSimpleValueType().getVectorElementType();
1918fe6060f1SDimitry Andric   if (EltVT.bitsLT(XLenVT))
1919e8d8bef9SDimitry Andric     SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits());
1920979e22ffSDimitry Andric 
1921fe6060f1SDimitry Andric   if (!ValidateImm(SplatImm))
1922e8d8bef9SDimitry Andric     return false;
1923979e22ffSDimitry Andric 
1924fe6060f1SDimitry Andric   SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), XLenVT);
1925979e22ffSDimitry Andric   return true;
1926979e22ffSDimitry Andric }
1927e8d8bef9SDimitry Andric 
1928fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) {
1929fe6060f1SDimitry Andric   return selectVSplatSimmHelper(N, SplatVal, *CurDAG, *Subtarget,
1930fe6060f1SDimitry Andric                                 [](int64_t Imm) { return isInt<5>(Imm); });
1931fe6060f1SDimitry Andric }
1932fe6060f1SDimitry Andric 
1933fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) {
1934fe6060f1SDimitry Andric   return selectVSplatSimmHelper(
1935fe6060f1SDimitry Andric       N, SplatVal, *CurDAG, *Subtarget,
1936fe6060f1SDimitry Andric       [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; });
1937fe6060f1SDimitry Andric }
1938fe6060f1SDimitry Andric 
1939fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N,
1940fe6060f1SDimitry Andric                                                       SDValue &SplatVal) {
1941fe6060f1SDimitry Andric   return selectVSplatSimmHelper(
1942fe6060f1SDimitry Andric       N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) {
1943fe6060f1SDimitry Andric         return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16);
1944fe6060f1SDimitry Andric       });
1945fe6060f1SDimitry Andric }
1946fe6060f1SDimitry Andric 
1947e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &SplatVal) {
1948e8d8bef9SDimitry Andric   if ((N.getOpcode() != ISD::SPLAT_VECTOR &&
1949fe6060f1SDimitry Andric        N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64 &&
1950fe6060f1SDimitry Andric        N.getOpcode() != RISCVISD::VMV_V_X_VL) ||
1951e8d8bef9SDimitry Andric       !isa<ConstantSDNode>(N.getOperand(0)))
1952979e22ffSDimitry Andric     return false;
1953979e22ffSDimitry Andric 
1954e8d8bef9SDimitry Andric   int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue();
1955979e22ffSDimitry Andric 
1956e8d8bef9SDimitry Andric   if (!isUInt<5>(SplatImm))
1957e8d8bef9SDimitry Andric     return false;
1958e8d8bef9SDimitry Andric 
1959e8d8bef9SDimitry Andric   SplatVal =
1960e8d8bef9SDimitry Andric       CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT());
1961e8d8bef9SDimitry Andric 
1962979e22ffSDimitry Andric   return true;
1963979e22ffSDimitry Andric }
1964979e22ffSDimitry Andric 
1965fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width,
1966fe6060f1SDimitry Andric                                        SDValue &Imm) {
1967fe6060f1SDimitry Andric   if (auto *C = dyn_cast<ConstantSDNode>(N)) {
1968fe6060f1SDimitry Andric     int64_t ImmVal = SignExtend64(C->getSExtValue(), Width);
1969fe6060f1SDimitry Andric 
1970fe6060f1SDimitry Andric     if (!isInt<5>(ImmVal))
1971fe6060f1SDimitry Andric       return false;
1972fe6060f1SDimitry Andric 
1973fe6060f1SDimitry Andric     Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT());
1974fe6060f1SDimitry Andric     return true;
1975fe6060f1SDimitry Andric   }
1976fe6060f1SDimitry Andric 
1977fe6060f1SDimitry Andric   return false;
1978fe6060f1SDimitry Andric }
1979fe6060f1SDimitry Andric 
19800b57cec5SDimitry Andric // Merge an ADDI into the offset of a load/store instruction where possible.
19815ffd83dbSDimitry Andric // (load (addi base, off1), off2) -> (load base, off1+off2)
19825ffd83dbSDimitry Andric // (store val, (addi base, off1), off2) -> (store val, base, off1+off2)
19835ffd83dbSDimitry Andric // This is possible when off1+off2 fits a 12-bit immediate.
1984349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeLoadStoreADDI(SDNode *N) {
19850b57cec5SDimitry Andric   int OffsetOpIdx;
19860b57cec5SDimitry Andric   int BaseOpIdx;
19870b57cec5SDimitry Andric 
19880b57cec5SDimitry Andric   // Only attempt this optimisation for I-type loads and S-type stores.
19890b57cec5SDimitry Andric   switch (N->getMachineOpcode()) {
19900b57cec5SDimitry Andric   default:
1991349cc55cSDimitry Andric     return false;
19920b57cec5SDimitry Andric   case RISCV::LB:
19930b57cec5SDimitry Andric   case RISCV::LH:
19940b57cec5SDimitry Andric   case RISCV::LW:
19950b57cec5SDimitry Andric   case RISCV::LBU:
19960b57cec5SDimitry Andric   case RISCV::LHU:
19970b57cec5SDimitry Andric   case RISCV::LWU:
19980b57cec5SDimitry Andric   case RISCV::LD:
1999e8d8bef9SDimitry Andric   case RISCV::FLH:
20000b57cec5SDimitry Andric   case RISCV::FLW:
20010b57cec5SDimitry Andric   case RISCV::FLD:
20020b57cec5SDimitry Andric     BaseOpIdx = 0;
20030b57cec5SDimitry Andric     OffsetOpIdx = 1;
20040b57cec5SDimitry Andric     break;
20050b57cec5SDimitry Andric   case RISCV::SB:
20060b57cec5SDimitry Andric   case RISCV::SH:
20070b57cec5SDimitry Andric   case RISCV::SW:
20080b57cec5SDimitry Andric   case RISCV::SD:
2009e8d8bef9SDimitry Andric   case RISCV::FSH:
20100b57cec5SDimitry Andric   case RISCV::FSW:
20110b57cec5SDimitry Andric   case RISCV::FSD:
20120b57cec5SDimitry Andric     BaseOpIdx = 1;
20130b57cec5SDimitry Andric     OffsetOpIdx = 2;
20140b57cec5SDimitry Andric     break;
20150b57cec5SDimitry Andric   }
20160b57cec5SDimitry Andric 
20175ffd83dbSDimitry Andric   if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx)))
2018349cc55cSDimitry Andric     return false;
20190b57cec5SDimitry Andric 
20200b57cec5SDimitry Andric   SDValue Base = N->getOperand(BaseOpIdx);
20210b57cec5SDimitry Andric 
20220b57cec5SDimitry Andric   // If the base is an ADDI, we can merge it in to the load/store.
20230b57cec5SDimitry Andric   if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI)
2024349cc55cSDimitry Andric     return false;
20250b57cec5SDimitry Andric 
20260b57cec5SDimitry Andric   SDValue ImmOperand = Base.getOperand(1);
20275ffd83dbSDimitry Andric   uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx);
20280b57cec5SDimitry Andric 
2029fe6060f1SDimitry Andric   if (auto *Const = dyn_cast<ConstantSDNode>(ImmOperand)) {
20305ffd83dbSDimitry Andric     int64_t Offset1 = Const->getSExtValue();
20315ffd83dbSDimitry Andric     int64_t CombinedOffset = Offset1 + Offset2;
20325ffd83dbSDimitry Andric     if (!isInt<12>(CombinedOffset))
2033349cc55cSDimitry Andric       return false;
20345ffd83dbSDimitry Andric     ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand),
20355ffd83dbSDimitry Andric                                            ImmOperand.getValueType());
2036fe6060f1SDimitry Andric   } else if (auto *GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) {
20375ffd83dbSDimitry Andric     // If the off1 in (addi base, off1) is a global variable's address (its
20385ffd83dbSDimitry Andric     // low part, really), then we can rely on the alignment of that variable
20395ffd83dbSDimitry Andric     // to provide a margin of safety before off1 can overflow the 12 bits.
20405ffd83dbSDimitry Andric     // Check if off2 falls within that margin; if so off1+off2 can't overflow.
20415ffd83dbSDimitry Andric     const DataLayout &DL = CurDAG->getDataLayout();
20425ffd83dbSDimitry Andric     Align Alignment = GA->getGlobal()->getPointerAlignment(DL);
20435ffd83dbSDimitry Andric     if (Offset2 != 0 && Alignment <= Offset2)
2044349cc55cSDimitry Andric       return false;
20455ffd83dbSDimitry Andric     int64_t Offset1 = GA->getOffset();
20465ffd83dbSDimitry Andric     int64_t CombinedOffset = Offset1 + Offset2;
20470b57cec5SDimitry Andric     ImmOperand = CurDAG->getTargetGlobalAddress(
20480b57cec5SDimitry Andric         GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(),
20495ffd83dbSDimitry Andric         CombinedOffset, GA->getTargetFlags());
2050fe6060f1SDimitry Andric   } else if (auto *CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) {
20515ffd83dbSDimitry Andric     // Ditto.
20525ffd83dbSDimitry Andric     Align Alignment = CP->getAlign();
20535ffd83dbSDimitry Andric     if (Offset2 != 0 && Alignment <= Offset2)
2054349cc55cSDimitry Andric       return false;
20555ffd83dbSDimitry Andric     int64_t Offset1 = CP->getOffset();
20565ffd83dbSDimitry Andric     int64_t CombinedOffset = Offset1 + Offset2;
20575ffd83dbSDimitry Andric     ImmOperand = CurDAG->getTargetConstantPool(
20585ffd83dbSDimitry Andric         CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(),
20595ffd83dbSDimitry Andric         CombinedOffset, CP->getTargetFlags());
20600b57cec5SDimitry Andric   } else {
2061349cc55cSDimitry Andric     return false;
20620b57cec5SDimitry Andric   }
20630b57cec5SDimitry Andric 
20640b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase:    ");
20650b57cec5SDimitry Andric   LLVM_DEBUG(Base->dump(CurDAG));
20660b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "\nN: ");
20670b57cec5SDimitry Andric   LLVM_DEBUG(N->dump(CurDAG));
20680b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "\n");
20690b57cec5SDimitry Andric 
20700b57cec5SDimitry Andric   // Modify the offset operand of the load/store.
20710b57cec5SDimitry Andric   if (BaseOpIdx == 0) // Load
20720b57cec5SDimitry Andric     CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand,
20730b57cec5SDimitry Andric                                N->getOperand(2));
20740b57cec5SDimitry Andric   else // Store
20750b57cec5SDimitry Andric     CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0),
20760b57cec5SDimitry Andric                                ImmOperand, N->getOperand(3));
20770b57cec5SDimitry Andric 
2078349cc55cSDimitry Andric   return true;
20790b57cec5SDimitry Andric }
2080349cc55cSDimitry Andric 
2081349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into
2082349cc55cSDimitry Andric // a W instruction cheaply.
2083349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) {
2084349cc55cSDimitry Andric   // Look for the sext.w pattern, addiw rd, rs1, 0.
2085349cc55cSDimitry Andric   if (N->getMachineOpcode() != RISCV::ADDIW ||
2086349cc55cSDimitry Andric       !isNullConstant(N->getOperand(1)))
2087349cc55cSDimitry Andric     return false;
2088349cc55cSDimitry Andric 
2089349cc55cSDimitry Andric   SDValue N0 = N->getOperand(0);
2090349cc55cSDimitry Andric   if (!N0.isMachineOpcode())
2091349cc55cSDimitry Andric     return false;
2092349cc55cSDimitry Andric 
2093349cc55cSDimitry Andric   switch (N0.getMachineOpcode()) {
2094349cc55cSDimitry Andric   default:
2095349cc55cSDimitry Andric     break;
2096349cc55cSDimitry Andric   case RISCV::ADD:
2097349cc55cSDimitry Andric   case RISCV::ADDI:
2098349cc55cSDimitry Andric   case RISCV::SUB:
2099349cc55cSDimitry Andric   case RISCV::MUL:
2100349cc55cSDimitry Andric   case RISCV::SLLI: {
2101349cc55cSDimitry Andric     // Convert sext.w+add/sub/mul to their W instructions. This will create
2102349cc55cSDimitry Andric     // a new independent instruction. This improves latency.
2103349cc55cSDimitry Andric     unsigned Opc;
2104349cc55cSDimitry Andric     switch (N0.getMachineOpcode()) {
2105349cc55cSDimitry Andric     default:
2106349cc55cSDimitry Andric       llvm_unreachable("Unexpected opcode!");
2107349cc55cSDimitry Andric     case RISCV::ADD:  Opc = RISCV::ADDW;  break;
2108349cc55cSDimitry Andric     case RISCV::ADDI: Opc = RISCV::ADDIW; break;
2109349cc55cSDimitry Andric     case RISCV::SUB:  Opc = RISCV::SUBW;  break;
2110349cc55cSDimitry Andric     case RISCV::MUL:  Opc = RISCV::MULW;  break;
2111349cc55cSDimitry Andric     case RISCV::SLLI: Opc = RISCV::SLLIW; break;
2112349cc55cSDimitry Andric     }
2113349cc55cSDimitry Andric 
2114349cc55cSDimitry Andric     SDValue N00 = N0.getOperand(0);
2115349cc55cSDimitry Andric     SDValue N01 = N0.getOperand(1);
2116349cc55cSDimitry Andric 
2117349cc55cSDimitry Andric     // Shift amount needs to be uimm5.
2118349cc55cSDimitry Andric     if (N0.getMachineOpcode() == RISCV::SLLI &&
2119349cc55cSDimitry Andric         !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue()))
2120349cc55cSDimitry Andric       break;
2121349cc55cSDimitry Andric 
2122349cc55cSDimitry Andric     SDNode *Result =
2123349cc55cSDimitry Andric         CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0),
2124349cc55cSDimitry Andric                                N00, N01);
2125349cc55cSDimitry Andric     ReplaceUses(N, Result);
2126349cc55cSDimitry Andric     return true;
2127349cc55cSDimitry Andric   }
2128349cc55cSDimitry Andric   case RISCV::ADDW:
2129349cc55cSDimitry Andric   case RISCV::ADDIW:
2130349cc55cSDimitry Andric   case RISCV::SUBW:
2131349cc55cSDimitry Andric   case RISCV::MULW:
2132349cc55cSDimitry Andric   case RISCV::SLLIW:
2133349cc55cSDimitry Andric     // Result is already sign extended just remove the sext.w.
2134349cc55cSDimitry Andric     // NOTE: We only handle the nodes that are selected with hasAllWUsers.
2135349cc55cSDimitry Andric     ReplaceUses(N, N0.getNode());
2136349cc55cSDimitry Andric     return true;
2137349cc55cSDimitry Andric   }
2138349cc55cSDimitry Andric 
2139349cc55cSDimitry Andric   return false;
21400b57cec5SDimitry Andric }
21410b57cec5SDimitry Andric 
21420b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready
21430b57cec5SDimitry Andric // for instruction scheduling.
21440b57cec5SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
21450b57cec5SDimitry Andric   return new RISCVDAGToDAGISel(TM);
21460b57cec5SDimitry Andric }
2147