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 4081ad6265SDimitry Andric #define GET_RISCVMaskedPseudosTable_IMPL 41fe6060f1SDimitry Andric #include "RISCVGenSearchableTables.inc" 42fe6060f1SDimitry Andric } // namespace RISCV 43fe6060f1SDimitry Andric } // namespace llvm 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric void RISCVDAGToDAGISel::PreprocessISelDAG() { 46*753f127fSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 47fe6060f1SDimitry Andric 48*753f127fSDimitry Andric bool MadeChange = false; 49*753f127fSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 50*753f127fSDimitry Andric SDNode *N = &*--Position; 51*753f127fSDimitry Andric if (N->use_empty()) 52*753f127fSDimitry Andric continue; 53*753f127fSDimitry Andric 54*753f127fSDimitry Andric SDValue Result; 55*753f127fSDimitry Andric switch (N->getOpcode()) { 56*753f127fSDimitry Andric case ISD::SPLAT_VECTOR: { 5781ad6265SDimitry Andric // Convert integer SPLAT_VECTOR to VMV_V_X_VL and floating-point 5881ad6265SDimitry Andric // SPLAT_VECTOR to VFMV_V_F_VL to reduce isel burden. 5981ad6265SDimitry Andric MVT VT = N->getSimpleValueType(0); 6081ad6265SDimitry Andric unsigned Opc = 6181ad6265SDimitry Andric VT.isInteger() ? RISCVISD::VMV_V_X_VL : RISCVISD::VFMV_V_F_VL; 6281ad6265SDimitry Andric SDLoc DL(N); 6381ad6265SDimitry Andric SDValue VL = CurDAG->getRegister(RISCV::X0, Subtarget->getXLenVT()); 64*753f127fSDimitry Andric Result = CurDAG->getNode(Opc, DL, VT, CurDAG->getUNDEF(VT), 6581ad6265SDimitry Andric N->getOperand(0), VL); 66*753f127fSDimitry Andric break; 6781ad6265SDimitry Andric } 68*753f127fSDimitry Andric case RISCVISD::SPLAT_VECTOR_SPLIT_I64_VL: { 69fe6060f1SDimitry Andric // Lower SPLAT_VECTOR_SPLIT_I64 to two scalar stores and a stride 0 vector 70fe6060f1SDimitry Andric // load. Done after lowering and combining so that we have a chance to 71fe6060f1SDimitry Andric // optimize this to VMV_V_X_VL when the upper bits aren't needed. 7281ad6265SDimitry Andric assert(N->getNumOperands() == 4 && "Unexpected number of operands"); 73fe6060f1SDimitry Andric MVT VT = N->getSimpleValueType(0); 7481ad6265SDimitry Andric SDValue Passthru = N->getOperand(0); 7581ad6265SDimitry Andric SDValue Lo = N->getOperand(1); 7681ad6265SDimitry Andric SDValue Hi = N->getOperand(2); 7781ad6265SDimitry Andric SDValue VL = N->getOperand(3); 78fe6060f1SDimitry Andric assert(VT.getVectorElementType() == MVT::i64 && VT.isScalableVector() && 79fe6060f1SDimitry Andric Lo.getValueType() == MVT::i32 && Hi.getValueType() == MVT::i32 && 80fe6060f1SDimitry Andric "Unexpected VTs!"); 81fe6060f1SDimitry Andric MachineFunction &MF = CurDAG->getMachineFunction(); 82*753f127fSDimitry Andric RISCVMachineFunctionInfo *FuncInfo = 83*753f127fSDimitry Andric MF.getInfo<RISCVMachineFunctionInfo>(); 84fe6060f1SDimitry Andric SDLoc DL(N); 85fe6060f1SDimitry Andric 86fe6060f1SDimitry Andric // We use the same frame index we use for moving two i32s into 64-bit FPR. 87fe6060f1SDimitry Andric // This is an analogous operation. 88fe6060f1SDimitry Andric int FI = FuncInfo->getMoveF64FrameIndex(MF); 89fe6060f1SDimitry Andric MachinePointerInfo MPI = MachinePointerInfo::getFixedStack(MF, FI); 90fe6060f1SDimitry Andric const TargetLowering &TLI = CurDAG->getTargetLoweringInfo(); 91fe6060f1SDimitry Andric SDValue StackSlot = 92fe6060f1SDimitry Andric CurDAG->getFrameIndex(FI, TLI.getPointerTy(CurDAG->getDataLayout())); 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric SDValue Chain = CurDAG->getEntryNode(); 95fe6060f1SDimitry Andric Lo = CurDAG->getStore(Chain, DL, Lo, StackSlot, MPI, Align(8)); 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric SDValue OffsetSlot = 98fe6060f1SDimitry Andric CurDAG->getMemBasePlusOffset(StackSlot, TypeSize::Fixed(4), DL); 99fe6060f1SDimitry Andric Hi = CurDAG->getStore(Chain, DL, Hi, OffsetSlot, MPI.getWithOffset(4), 100fe6060f1SDimitry Andric Align(8)); 101fe6060f1SDimitry Andric 102fe6060f1SDimitry Andric Chain = CurDAG->getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric SDVTList VTs = CurDAG->getVTList({VT, MVT::Other}); 105fe6060f1SDimitry Andric SDValue IntID = 106fe6060f1SDimitry Andric CurDAG->getTargetConstant(Intrinsic::riscv_vlse, DL, MVT::i64); 10704eeddc0SDimitry Andric SDValue Ops[] = {Chain, 10804eeddc0SDimitry Andric IntID, 10981ad6265SDimitry Andric Passthru, 11004eeddc0SDimitry Andric StackSlot, 11104eeddc0SDimitry Andric CurDAG->getRegister(RISCV::X0, MVT::i64), 11204eeddc0SDimitry Andric VL}; 113fe6060f1SDimitry Andric 114*753f127fSDimitry Andric Result = CurDAG->getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, VTs, Ops, 115*753f127fSDimitry Andric MVT::i64, MPI, Align(8), 116fe6060f1SDimitry Andric MachineMemOperand::MOLoad); 117*753f127fSDimitry Andric break; 118fe6060f1SDimitry Andric } 119fe6060f1SDimitry Andric } 120fe6060f1SDimitry Andric 121*753f127fSDimitry Andric if (Result) { 122*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "RISCV DAG preprocessing replacing:\nOld: "); 123*753f127fSDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 124*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\nNew: "); 125*753f127fSDimitry Andric LLVM_DEBUG(Result->dump(CurDAG)); 126*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 127*753f127fSDimitry Andric 128*753f127fSDimitry Andric CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), Result); 129*753f127fSDimitry Andric MadeChange = true; 130*753f127fSDimitry Andric } 131*753f127fSDimitry Andric } 132*753f127fSDimitry Andric 133*753f127fSDimitry Andric if (MadeChange) 134*753f127fSDimitry Andric CurDAG->RemoveDeadNodes(); 135*753f127fSDimitry Andric } 136*753f127fSDimitry Andric 1370b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 13881ad6265SDimitry Andric HandleSDNode Dummy(CurDAG->getRoot()); 139349cc55cSDimitry Andric SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end(); 140349cc55cSDimitry Andric 141349cc55cSDimitry Andric bool MadeChange = false; 142349cc55cSDimitry Andric while (Position != CurDAG->allnodes_begin()) { 143349cc55cSDimitry Andric SDNode *N = &*--Position; 144349cc55cSDimitry Andric // Skip dead nodes and any non-machine opcodes. 145349cc55cSDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 146349cc55cSDimitry Andric continue; 147349cc55cSDimitry Andric 148349cc55cSDimitry Andric MadeChange |= doPeepholeSExtW(N); 14981ad6265SDimitry Andric MadeChange |= doPeepholeMaskedRVV(N); 150349cc55cSDimitry Andric } 151349cc55cSDimitry Andric 15281ad6265SDimitry Andric CurDAG->setRoot(Dummy.getValue()); 15381ad6265SDimitry Andric 154349cc55cSDimitry Andric if (MadeChange) 155349cc55cSDimitry Andric CurDAG->RemoveDeadNodes(); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 15881ad6265SDimitry Andric static SDNode *selectImmSeq(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 15981ad6265SDimitry Andric RISCVMatInt::InstSeq &Seq) { 1608bcb0991SDimitry Andric SDNode *Result = nullptr; 16181ad6265SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, VT); 1620b57cec5SDimitry Andric for (RISCVMatInt::Inst &Inst : Seq) { 16381ad6265SDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, VT); 16481ad6265SDimitry Andric switch (Inst.getOpndKind()) { 16581ad6265SDimitry Andric case RISCVMatInt::Imm: 16681ad6265SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, VT, SDImm); 16781ad6265SDimitry Andric break; 16881ad6265SDimitry Andric case RISCVMatInt::RegX0: 16981ad6265SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, VT, SrcReg, 17081ad6265SDimitry Andric CurDAG->getRegister(RISCV::X0, VT)); 17181ad6265SDimitry Andric break; 17281ad6265SDimitry Andric case RISCVMatInt::RegReg: 17381ad6265SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, VT, SrcReg, SrcReg); 17481ad6265SDimitry Andric break; 17581ad6265SDimitry Andric case RISCVMatInt::RegImm: 17681ad6265SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, VT, SrcReg, SDImm); 17781ad6265SDimitry Andric break; 17881ad6265SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 1810b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric return Result; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 18781ad6265SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT, 18881ad6265SDimitry Andric int64_t Imm, const RISCVSubtarget &Subtarget) { 18981ad6265SDimitry Andric RISCVMatInt::InstSeq Seq = 19081ad6265SDimitry Andric RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits()); 19181ad6265SDimitry Andric 19281ad6265SDimitry Andric return selectImmSeq(CurDAG, DL, VT, Seq); 19381ad6265SDimitry Andric } 19481ad6265SDimitry Andric 19581ad6265SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 19681ad6265SDimitry Andric unsigned NF, RISCVII::VLMUL LMUL) { 19781ad6265SDimitry Andric static const unsigned M1TupleRegClassIDs[] = { 19881ad6265SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 19981ad6265SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 20081ad6265SDimitry Andric RISCV::VRN8M1RegClassID}; 20181ad6265SDimitry Andric static const unsigned M2TupleRegClassIDs[] = {RISCV::VRN2M2RegClassID, 20281ad6265SDimitry Andric RISCV::VRN3M2RegClassID, 20381ad6265SDimitry Andric RISCV::VRN4M2RegClassID}; 20481ad6265SDimitry Andric 205e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 206e8d8bef9SDimitry Andric 20781ad6265SDimitry Andric unsigned RegClassID; 20881ad6265SDimitry Andric unsigned SubReg0; 20981ad6265SDimitry Andric switch (LMUL) { 21081ad6265SDimitry Andric default: 21181ad6265SDimitry Andric llvm_unreachable("Invalid LMUL."); 21281ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F8: 21381ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F4: 21481ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_F2: 21581ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_1: 21681ad6265SDimitry Andric static_assert(RISCV::sub_vrm1_7 == RISCV::sub_vrm1_0 + 7, 21781ad6265SDimitry Andric "Unexpected subreg numbering"); 21881ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm1_0; 21981ad6265SDimitry Andric RegClassID = M1TupleRegClassIDs[NF - 2]; 22081ad6265SDimitry Andric break; 22181ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_2: 22281ad6265SDimitry Andric static_assert(RISCV::sub_vrm2_3 == RISCV::sub_vrm2_0 + 3, 22381ad6265SDimitry Andric "Unexpected subreg numbering"); 22481ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm2_0; 22581ad6265SDimitry Andric RegClassID = M2TupleRegClassIDs[NF - 2]; 22681ad6265SDimitry Andric break; 22781ad6265SDimitry Andric case RISCVII::VLMUL::LMUL_4: 22881ad6265SDimitry Andric static_assert(RISCV::sub_vrm4_1 == RISCV::sub_vrm4_0 + 1, 22981ad6265SDimitry Andric "Unexpected subreg numbering"); 23081ad6265SDimitry Andric SubReg0 = RISCV::sub_vrm4_0; 23181ad6265SDimitry Andric RegClassID = RISCV::VRN2M4RegClassID; 23281ad6265SDimitry Andric break; 23381ad6265SDimitry Andric } 23481ad6265SDimitry Andric 235e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 236e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 237e8d8bef9SDimitry Andric 238e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 239e8d8bef9SDimitry Andric 240e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 241e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 242e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 243e8d8bef9SDimitry Andric } 244e8d8bef9SDimitry Andric SDNode *N = 245e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 246e8d8bef9SDimitry Andric return SDValue(N, 0); 247e8d8bef9SDimitry Andric } 248e8d8bef9SDimitry Andric 249fe6060f1SDimitry Andric void RISCVDAGToDAGISel::addVectorLoadStoreOperands( 250fe6060f1SDimitry Andric SDNode *Node, unsigned Log2SEW, const SDLoc &DL, unsigned CurOp, 251fe6060f1SDimitry Andric bool IsMasked, bool IsStridedOrIndexed, SmallVectorImpl<SDValue> &Operands, 252349cc55cSDimitry Andric bool IsLoad, MVT *IndexVT) { 253fe6060f1SDimitry Andric SDValue Chain = Node->getOperand(0); 254fe6060f1SDimitry Andric SDValue Glue; 255fe6060f1SDimitry Andric 256*753f127fSDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Base pointer. 257fe6060f1SDimitry Andric 258fe6060f1SDimitry Andric if (IsStridedOrIndexed) { 259fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Index. 260fe6060f1SDimitry Andric if (IndexVT) 261fe6060f1SDimitry Andric *IndexVT = Operands.back()->getSimpleValueType(0); 262fe6060f1SDimitry Andric } 263fe6060f1SDimitry Andric 264fe6060f1SDimitry Andric if (IsMasked) { 265fe6060f1SDimitry Andric // Mask needs to be copied to V0. 266fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(CurOp++); 267fe6060f1SDimitry Andric Chain = CurDAG->getCopyToReg(Chain, DL, RISCV::V0, Mask, SDValue()); 268fe6060f1SDimitry Andric Glue = Chain.getValue(1); 269fe6060f1SDimitry Andric Operands.push_back(CurDAG->getRegister(RISCV::V0, Mask.getValueType())); 270fe6060f1SDimitry Andric } 271fe6060f1SDimitry Andric SDValue VL; 272fe6060f1SDimitry Andric selectVLOp(Node->getOperand(CurOp++), VL); 273fe6060f1SDimitry Andric Operands.push_back(VL); 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 276fe6060f1SDimitry Andric SDValue SEWOp = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 277fe6060f1SDimitry Andric Operands.push_back(SEWOp); 278fe6060f1SDimitry Andric 279349cc55cSDimitry Andric // Masked load has the tail policy argument. 280349cc55cSDimitry Andric if (IsMasked && IsLoad) { 281349cc55cSDimitry Andric // Policy must be a constant. 282349cc55cSDimitry Andric uint64_t Policy = Node->getConstantOperandVal(CurOp++); 283349cc55cSDimitry Andric SDValue PolicyOp = CurDAG->getTargetConstant(Policy, DL, XLenVT); 284349cc55cSDimitry Andric Operands.push_back(PolicyOp); 285349cc55cSDimitry Andric } 286349cc55cSDimitry Andric 287fe6060f1SDimitry Andric Operands.push_back(Chain); // Chain. 288fe6060f1SDimitry Andric if (Glue) 289fe6060f1SDimitry Andric Operands.push_back(Glue); 290fe6060f1SDimitry Andric } 291fe6060f1SDimitry Andric 29281ad6265SDimitry Andric static bool isAllUndef(ArrayRef<SDValue> Values) { 29381ad6265SDimitry Andric return llvm::all_of(Values, [](SDValue V) { return V->isUndef(); }); 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 296fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, bool IsMasked, 297e8d8bef9SDimitry Andric bool IsStrided) { 298e8d8bef9SDimitry Andric SDLoc DL(Node); 299e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 300fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 301fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 302fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 303e8d8bef9SDimitry Andric 304fe6060f1SDimitry Andric unsigned CurOp = 2; 305fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 30681ad6265SDimitry Andric 307fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 308fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 30981ad6265SDimitry Andric bool IsTU = IsMasked || !isAllUndef(Regs); 31081ad6265SDimitry Andric if (IsTU) { 31181ad6265SDimitry Andric SDValue Merge = createTuple(*CurDAG, Regs, NF, LMUL); 31281ad6265SDimitry Andric Operands.push_back(Merge); 313e8d8bef9SDimitry Andric } 31481ad6265SDimitry Andric CurOp += NF; 315fe6060f1SDimitry Andric 316fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 317349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 318fe6060f1SDimitry Andric 319fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 32081ad6265SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsTU, IsStrided, /*FF*/ false, Log2SEW, 321fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 322fe6060f1SDimitry Andric MachineSDNode *Load = 323e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 324fe6060f1SDimitry Andric 325fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 326fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 327fe6060f1SDimitry Andric 328e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 329fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 330fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 331e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 332fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 333fe6060f1SDimitry Andric } 334e8d8bef9SDimitry Andric 335e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 336e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 337e8d8bef9SDimitry Andric } 338e8d8bef9SDimitry Andric 339fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node, bool IsMasked) { 340e8d8bef9SDimitry Andric SDLoc DL(Node); 341fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count VL and Chain. 342fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 343e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 344fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 345fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 346e8d8bef9SDimitry Andric 347fe6060f1SDimitry Andric unsigned CurOp = 2; 348e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 34981ad6265SDimitry Andric 350fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 351fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 35281ad6265SDimitry Andric bool IsTU = IsMasked || !isAllUndef(Regs); 35381ad6265SDimitry Andric if (IsTU) { 354e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 355fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 356fe6060f1SDimitry Andric } 35781ad6265SDimitry Andric CurOp += NF; 358e8d8bef9SDimitry Andric 359fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 360349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 361349cc55cSDimitry Andric /*IsLoad=*/true); 362fe6060f1SDimitry Andric 363fe6060f1SDimitry Andric const RISCV::VLSEGPseudo *P = 36481ad6265SDimitry Andric RISCV::getVLSEGPseudo(NF, IsMasked, IsTU, /*Strided*/ false, /*FF*/ true, 365fe6060f1SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 366fe6060f1SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, 36781ad6265SDimitry Andric XLenVT, MVT::Other, Operands); 368fe6060f1SDimitry Andric 369fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 370fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 371fe6060f1SDimitry Andric 372e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 373fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 374fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 375e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 376fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 377fe6060f1SDimitry Andric } 378fe6060f1SDimitry Andric 37981ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // VL 38081ad6265SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Chain 381fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 382fe6060f1SDimitry Andric } 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, bool IsMasked, 385fe6060f1SDimitry Andric bool IsOrdered) { 386fe6060f1SDimitry Andric SDLoc DL(Node); 387fe6060f1SDimitry Andric unsigned NF = Node->getNumValues() - 1; 388fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 389fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 390fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 391fe6060f1SDimitry Andric 392fe6060f1SDimitry Andric unsigned CurOp = 2; 393fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 39481ad6265SDimitry Andric 395fe6060f1SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + CurOp, 396fe6060f1SDimitry Andric Node->op_begin() + CurOp + NF); 39781ad6265SDimitry Andric bool IsTU = IsMasked || !isAllUndef(Regs); 39881ad6265SDimitry Andric if (IsTU) { 399fe6060f1SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 400fe6060f1SDimitry Andric Operands.push_back(MaskedOff); 401fe6060f1SDimitry Andric } 40281ad6265SDimitry Andric CurOp += NF; 403fe6060f1SDimitry Andric 404fe6060f1SDimitry Andric MVT IndexVT; 405fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 406349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 407349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 408fe6060f1SDimitry Andric 409fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 410fe6060f1SDimitry Andric "Element count mismatch"); 411fe6060f1SDimitry Andric 412fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 413fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 41404eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 41504eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 41604eeddc0SDimitry Andric "values when XLEN=32"); 41704eeddc0SDimitry Andric } 418fe6060f1SDimitry Andric const RISCV::VLXSEGPseudo *P = RISCV::getVLXSEGPseudo( 41981ad6265SDimitry Andric NF, IsMasked, IsTU, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 420fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 421fe6060f1SDimitry Andric MachineSDNode *Load = 422fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 423fe6060f1SDimitry Andric 424fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 425fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 426fe6060f1SDimitry Andric 427fe6060f1SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 428fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) { 429fe6060f1SDimitry Andric unsigned SubRegIdx = RISCVTargetLowering::getSubregIndexByMVT(VT, I); 430fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, I), 431fe6060f1SDimitry Andric CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, SuperReg)); 432fe6060f1SDimitry Andric } 433e8d8bef9SDimitry Andric 434e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 435e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 436e8d8bef9SDimitry Andric } 437e8d8bef9SDimitry Andric 438fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, bool IsMasked, 439e8d8bef9SDimitry Andric bool IsStrided) { 440e8d8bef9SDimitry Andric SDLoc DL(Node); 441e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 442e8d8bef9SDimitry Andric if (IsStrided) 443e8d8bef9SDimitry Andric NF--; 444fe6060f1SDimitry Andric if (IsMasked) 445e8d8bef9SDimitry Andric NF--; 446fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 447fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 448fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 449e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 450e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 451fe6060f1SDimitry Andric 452fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 453e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 454fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 455fe6060f1SDimitry Andric 456fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 457fe6060f1SDimitry Andric Operands); 458fe6060f1SDimitry Andric 459fe6060f1SDimitry Andric const RISCV::VSSEGPseudo *P = RISCV::getVSSEGPseudo( 460fe6060f1SDimitry Andric NF, IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 461fe6060f1SDimitry Andric MachineSDNode *Store = 462e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 463fe6060f1SDimitry Andric 464fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 465fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 466fe6060f1SDimitry Andric 467e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 468e8d8bef9SDimitry Andric } 469e8d8bef9SDimitry Andric 470fe6060f1SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, bool IsMasked, 471fe6060f1SDimitry Andric bool IsOrdered) { 472e8d8bef9SDimitry Andric SDLoc DL(Node); 473e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 474fe6060f1SDimitry Andric if (IsMasked) 475fe6060f1SDimitry Andric --NF; 476fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 477fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 478fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 479e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 480e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 481e8d8bef9SDimitry Andric 482fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 483fe6060f1SDimitry Andric Operands.push_back(StoreVal); 484fe6060f1SDimitry Andric unsigned CurOp = 2 + NF; 485fe6060f1SDimitry Andric 486fe6060f1SDimitry Andric MVT IndexVT; 487fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 488349cc55cSDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 489349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 490fe6060f1SDimitry Andric 491fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 492fe6060f1SDimitry Andric "Element count mismatch"); 493fe6060f1SDimitry Andric 494fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 495fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 49604eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 49704eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 49804eeddc0SDimitry Andric "values when XLEN=32"); 49904eeddc0SDimitry Andric } 500fe6060f1SDimitry Andric const RISCV::VSXSEGPseudo *P = RISCV::getVSXSEGPseudo( 501fe6060f1SDimitry Andric NF, IsMasked, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 502e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 503fe6060f1SDimitry Andric MachineSDNode *Store = 504e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 505fe6060f1SDimitry Andric 506fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 507fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 508fe6060f1SDimitry Andric 509e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 510e8d8bef9SDimitry Andric } 511e8d8bef9SDimitry Andric 51204eeddc0SDimitry Andric void RISCVDAGToDAGISel::selectVSETVLI(SDNode *Node) { 51304eeddc0SDimitry Andric if (!Subtarget->hasVInstructions()) 51404eeddc0SDimitry Andric return; 51504eeddc0SDimitry Andric 51604eeddc0SDimitry Andric assert((Node->getOpcode() == ISD::INTRINSIC_W_CHAIN || 51704eeddc0SDimitry Andric Node->getOpcode() == ISD::INTRINSIC_WO_CHAIN) && 51804eeddc0SDimitry Andric "Unexpected opcode"); 51904eeddc0SDimitry Andric 52004eeddc0SDimitry Andric SDLoc DL(Node); 52104eeddc0SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 52204eeddc0SDimitry Andric 52304eeddc0SDimitry Andric bool HasChain = Node->getOpcode() == ISD::INTRINSIC_W_CHAIN; 52404eeddc0SDimitry Andric unsigned IntNoOffset = HasChain ? 1 : 0; 52504eeddc0SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(IntNoOffset); 52604eeddc0SDimitry Andric 52704eeddc0SDimitry Andric assert((IntNo == Intrinsic::riscv_vsetvli || 52804eeddc0SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax || 52904eeddc0SDimitry Andric IntNo == Intrinsic::riscv_vsetvli_opt || 53004eeddc0SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax_opt) && 53104eeddc0SDimitry Andric "Unexpected vsetvli intrinsic"); 53204eeddc0SDimitry Andric 53304eeddc0SDimitry Andric bool VLMax = IntNo == Intrinsic::riscv_vsetvlimax || 53404eeddc0SDimitry Andric IntNo == Intrinsic::riscv_vsetvlimax_opt; 53504eeddc0SDimitry Andric unsigned Offset = IntNoOffset + (VLMax ? 1 : 2); 53604eeddc0SDimitry Andric 53704eeddc0SDimitry Andric assert(Node->getNumOperands() == Offset + 2 && 53804eeddc0SDimitry Andric "Unexpected number of operands"); 53904eeddc0SDimitry Andric 54004eeddc0SDimitry Andric unsigned SEW = 54104eeddc0SDimitry Andric RISCVVType::decodeVSEW(Node->getConstantOperandVal(Offset) & 0x7); 54204eeddc0SDimitry Andric RISCVII::VLMUL VLMul = static_cast<RISCVII::VLMUL>( 54304eeddc0SDimitry Andric Node->getConstantOperandVal(Offset + 1) & 0x7); 54404eeddc0SDimitry Andric 54504eeddc0SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE(VLMul, SEW, /*TailAgnostic*/ true, 54604eeddc0SDimitry Andric /*MaskAgnostic*/ false); 54704eeddc0SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 54804eeddc0SDimitry Andric 54904eeddc0SDimitry Andric SmallVector<EVT, 2> VTs = {XLenVT}; 55004eeddc0SDimitry Andric if (HasChain) 55104eeddc0SDimitry Andric VTs.push_back(MVT::Other); 55204eeddc0SDimitry Andric 55304eeddc0SDimitry Andric SDValue VLOperand; 55404eeddc0SDimitry Andric unsigned Opcode = RISCV::PseudoVSETVLI; 55504eeddc0SDimitry Andric if (VLMax) { 55604eeddc0SDimitry Andric VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 55704eeddc0SDimitry Andric Opcode = RISCV::PseudoVSETVLIX0; 55804eeddc0SDimitry Andric } else { 55904eeddc0SDimitry Andric VLOperand = Node->getOperand(IntNoOffset + 1); 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 56204eeddc0SDimitry Andric uint64_t AVL = C->getZExtValue(); 56304eeddc0SDimitry Andric if (isUInt<5>(AVL)) { 56404eeddc0SDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 56504eeddc0SDimitry Andric SmallVector<SDValue, 3> Ops = {VLImm, VTypeIOp}; 56604eeddc0SDimitry Andric if (HasChain) 56704eeddc0SDimitry Andric Ops.push_back(Node->getOperand(0)); 56804eeddc0SDimitry Andric ReplaceNode( 56904eeddc0SDimitry Andric Node, CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, VTs, Ops)); 57004eeddc0SDimitry Andric return; 57104eeddc0SDimitry Andric } 57204eeddc0SDimitry Andric } 57304eeddc0SDimitry Andric } 57404eeddc0SDimitry Andric 57504eeddc0SDimitry Andric SmallVector<SDValue, 3> Ops = {VLOperand, VTypeIOp}; 57604eeddc0SDimitry Andric if (HasChain) 57704eeddc0SDimitry Andric Ops.push_back(Node->getOperand(0)); 57804eeddc0SDimitry Andric 57904eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(Opcode, DL, VTs, Ops)); 58004eeddc0SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 5830b57cec5SDimitry Andric // If we have a custom node, we have already selected. 5840b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 5850b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 5860b57cec5SDimitry Andric Node->setNodeId(-1); 5870b57cec5SDimitry Andric return; 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 5910b57cec5SDimitry Andric // should be handled here. 5920b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 5930b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 5940b57cec5SDimitry Andric SDLoc DL(Node); 595fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric switch (Opcode) { 5980b57cec5SDimitry Andric case ISD::Constant: { 599fe6060f1SDimitry Andric auto *ConstNode = cast<ConstantSDNode>(Node); 600349cc55cSDimitry Andric if (VT == XLenVT && ConstNode->isZero()) { 601e8d8bef9SDimitry Andric SDValue New = 602e8d8bef9SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, XLenVT); 6030b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 6040b57cec5SDimitry Andric return; 6050b57cec5SDimitry Andric } 606349cc55cSDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 607349cc55cSDimitry Andric // If the upper XLen-16 bits are not used, try to convert this to a simm12 608349cc55cSDimitry Andric // by sign extending bit 15. 60981ad6265SDimitry Andric if (isUInt<16>(Imm) && isInt<12>(SignExtend64<16>(Imm)) && 610349cc55cSDimitry Andric hasAllHUsers(Node)) 61181ad6265SDimitry Andric Imm = SignExtend64<16>(Imm); 612349cc55cSDimitry Andric // If the upper 32-bits are not used try to convert this into a simm32 by 613349cc55cSDimitry Andric // sign extending bit 32. 614349cc55cSDimitry Andric if (!isInt<32>(Imm) && isUInt<32>(Imm) && hasAllWUsers(Node)) 61581ad6265SDimitry Andric Imm = SignExtend64<32>(Imm); 616349cc55cSDimitry Andric 61704eeddc0SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, VT, Imm, *Subtarget)); 6180b57cec5SDimitry Andric return; 6190b57cec5SDimitry Andric } 62081ad6265SDimitry Andric case ISD::SHL: { 621fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 62204eeddc0SDimitry Andric if (!N1C) 62304eeddc0SDimitry Andric break; 624fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 62504eeddc0SDimitry Andric if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || 62604eeddc0SDimitry Andric !isa<ConstantSDNode>(N0.getOperand(1))) 62704eeddc0SDimitry Andric break; 62804eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 629fe6060f1SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 63081ad6265SDimitry Andric 63181ad6265SDimitry Andric // Optimize (shl (and X, C2), C) -> (slli (srliw X, C3), C3+C) where C2 has 63281ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 63381ad6265SDimitry Andric if (ShAmt <= 32 && isShiftedMask_64(Mask)) { 63481ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 63581ad6265SDimitry Andric unsigned LeadingZeros = XLen - (64 - countLeadingZeros(Mask)); 63681ad6265SDimitry Andric unsigned TrailingZeros = countTrailingZeros(Mask); 63781ad6265SDimitry Andric if (TrailingZeros > 0 && LeadingZeros == 32) { 63881ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 63981ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 64081ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 64181ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 64281ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 64381ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros + ShAmt, DL, VT)); 64481ad6265SDimitry Andric ReplaceNode(Node, SLLI); 64581ad6265SDimitry Andric return; 64681ad6265SDimitry Andric } 64781ad6265SDimitry Andric } 64881ad6265SDimitry Andric break; 64981ad6265SDimitry Andric } 65081ad6265SDimitry Andric case ISD::SRL: { 65181ad6265SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 65281ad6265SDimitry Andric if (!N1C) 65381ad6265SDimitry Andric break; 65481ad6265SDimitry Andric SDValue N0 = Node->getOperand(0); 65581ad6265SDimitry Andric if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || 65681ad6265SDimitry Andric !isa<ConstantSDNode>(N0.getOperand(1))) 65781ad6265SDimitry Andric break; 65881ad6265SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 65981ad6265SDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 66081ad6265SDimitry Andric 66181ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> (slli (srliw X, C3), C3-C) where C2 has 66281ad6265SDimitry Andric // 32 leading zeros and C3 trailing zeros. 66381ad6265SDimitry Andric if (isShiftedMask_64(Mask)) { 66481ad6265SDimitry Andric unsigned XLen = Subtarget->getXLen(); 66581ad6265SDimitry Andric unsigned LeadingZeros = XLen - (64 - countLeadingZeros(Mask)); 66681ad6265SDimitry Andric unsigned TrailingZeros = countTrailingZeros(Mask); 66781ad6265SDimitry Andric if (LeadingZeros == 32 && TrailingZeros > ShAmt) { 66881ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 66981ad6265SDimitry Andric RISCV::SRLIW, DL, VT, N0->getOperand(0), 67081ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros, DL, VT)); 67181ad6265SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 67281ad6265SDimitry Andric RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 67381ad6265SDimitry Andric CurDAG->getTargetConstant(TrailingZeros - ShAmt, DL, VT)); 67481ad6265SDimitry Andric ReplaceNode(Node, SLLI); 67581ad6265SDimitry Andric return; 67681ad6265SDimitry Andric } 67781ad6265SDimitry Andric } 67881ad6265SDimitry Andric 67981ad6265SDimitry Andric // Optimize (srl (and X, C2), C) -> 68081ad6265SDimitry Andric // (srli (slli X, (XLen-C3), (XLen-C3) + C) 68181ad6265SDimitry Andric // Where C2 is a mask with C3 trailing ones. 68281ad6265SDimitry Andric // Taking into account that the C2 may have had lower bits unset by 68381ad6265SDimitry Andric // SimplifyDemandedBits. This avoids materializing the C2 immediate. 68481ad6265SDimitry Andric // This pattern occurs when type legalizing right shifts for types with 68581ad6265SDimitry Andric // less than XLen bits. 686fe6060f1SDimitry Andric Mask |= maskTrailingOnes<uint64_t>(ShAmt); 68704eeddc0SDimitry Andric if (!isMask_64(Mask)) 68804eeddc0SDimitry Andric break; 68904eeddc0SDimitry Andric unsigned TrailingOnes = countTrailingOnes(Mask); 69004eeddc0SDimitry Andric // 32 trailing ones should use srliw via tablegen pattern. 69104eeddc0SDimitry Andric if (TrailingOnes == 32 || ShAmt >= TrailingOnes) 69204eeddc0SDimitry Andric break; 69304eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - TrailingOnes; 694fe6060f1SDimitry Andric SDNode *SLLI = 695fe6060f1SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 696fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 697fe6060f1SDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 698fe6060f1SDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 699fe6060f1SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 700fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 701fe6060f1SDimitry Andric return; 702fe6060f1SDimitry Andric } 70304eeddc0SDimitry Andric case ISD::SRA: { 70404eeddc0SDimitry Andric // Optimize (sra (sext_inreg X, i16), C) -> 70504eeddc0SDimitry Andric // (srai (slli X, (XLen-16), (XLen-16) + C) 70604eeddc0SDimitry Andric // And (sra (sext_inreg X, i8), C) -> 70704eeddc0SDimitry Andric // (srai (slli X, (XLen-8), (XLen-8) + C) 70804eeddc0SDimitry Andric // This can occur when Zbb is enabled, which makes sext_inreg i16/i8 legal. 70904eeddc0SDimitry Andric // This transform matches the code we get without Zbb. The shifts are more 71004eeddc0SDimitry Andric // compressible, and this can help expose CSE opportunities in the sdiv by 71104eeddc0SDimitry Andric // constant optimization. 71204eeddc0SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 71304eeddc0SDimitry Andric if (!N1C) 714fe6060f1SDimitry Andric break; 71504eeddc0SDimitry Andric SDValue N0 = Node->getOperand(0); 71604eeddc0SDimitry Andric if (N0.getOpcode() != ISD::SIGN_EXTEND_INREG || !N0.hasOneUse()) 71704eeddc0SDimitry Andric break; 71804eeddc0SDimitry Andric unsigned ShAmt = N1C->getZExtValue(); 71904eeddc0SDimitry Andric unsigned ExtSize = 72004eeddc0SDimitry Andric cast<VTSDNode>(N0.getOperand(1))->getVT().getSizeInBits(); 72104eeddc0SDimitry Andric // ExtSize of 32 should use sraiw via tablegen pattern. 72204eeddc0SDimitry Andric if (ExtSize >= 32 || ShAmt >= ExtSize) 72304eeddc0SDimitry Andric break; 72404eeddc0SDimitry Andric unsigned LShAmt = Subtarget->getXLen() - ExtSize; 72504eeddc0SDimitry Andric SDNode *SLLI = 72604eeddc0SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0->getOperand(0), 72704eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt, DL, VT)); 72804eeddc0SDimitry Andric SDNode *SRAI = CurDAG->getMachineNode( 72904eeddc0SDimitry Andric RISCV::SRAI, DL, VT, SDValue(SLLI, 0), 73004eeddc0SDimitry Andric CurDAG->getTargetConstant(LShAmt + ShAmt, DL, VT)); 73104eeddc0SDimitry Andric ReplaceNode(Node, SRAI); 73204eeddc0SDimitry Andric return; 733fe6060f1SDimitry Andric } 734fe6060f1SDimitry Andric case ISD::AND: { 735fe6060f1SDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 736fe6060f1SDimitry Andric if (!N1C) 737fe6060f1SDimitry Andric break; 738fe6060f1SDimitry Andric 739fe6060f1SDimitry Andric SDValue N0 = Node->getOperand(0); 740fe6060f1SDimitry Andric 741fe6060f1SDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 742fe6060f1SDimitry Andric if (!LeftShift && N0.getOpcode() != ISD::SRL) 743fe6060f1SDimitry Andric break; 744fe6060f1SDimitry Andric 745fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); 746fe6060f1SDimitry Andric if (!C) 747fe6060f1SDimitry Andric break; 748*753f127fSDimitry Andric unsigned C2 = C->getZExtValue(); 749fe6060f1SDimitry Andric unsigned XLen = Subtarget->getXLen(); 750*753f127fSDimitry Andric assert((C2 > 0 && C2 < XLen) && "Unexpected shift amount!"); 751fe6060f1SDimitry Andric 752fe6060f1SDimitry Andric uint64_t C1 = N1C->getZExtValue(); 753fe6060f1SDimitry Andric 75481ad6265SDimitry Andric // Keep track of whether this is a c.andi. If we can't use c.andi, the 75581ad6265SDimitry Andric // shift pair might offer more compression opportunities. 75681ad6265SDimitry Andric // TODO: We could check for C extension here, but we don't have many lit 75781ad6265SDimitry Andric // tests with the C extension enabled so not checking gets better coverage. 75881ad6265SDimitry Andric // TODO: What if ANDI faster than shift? 75981ad6265SDimitry Andric bool IsCANDI = isInt<6>(N1C->getSExtValue()); 760fe6060f1SDimitry Andric 761fe6060f1SDimitry Andric // Clear irrelevant bits in the mask. 762fe6060f1SDimitry Andric if (LeftShift) 763fe6060f1SDimitry Andric C1 &= maskTrailingZeros<uint64_t>(C2); 764fe6060f1SDimitry Andric else 765fe6060f1SDimitry Andric C1 &= maskTrailingOnes<uint64_t>(XLen - C2); 766fe6060f1SDimitry Andric 767fe6060f1SDimitry Andric // Some transforms should only be done if the shift has a single use or 768fe6060f1SDimitry Andric // the AND would become (srli (slli X, 32), 32) 769fe6060f1SDimitry Andric bool OneUseOrZExtW = N0.hasOneUse() || C1 == UINT64_C(0xFFFFFFFF); 770fe6060f1SDimitry Andric 771fe6060f1SDimitry Andric SDValue X = N0.getOperand(0); 772fe6060f1SDimitry Andric 773fe6060f1SDimitry Andric // Turn (and (srl x, c2) c1) -> (srli (slli x, c3-c2), c3) if c1 is a mask 774fe6060f1SDimitry Andric // with c3 leading zeros. 775fe6060f1SDimitry Andric if (!LeftShift && isMask_64(C1)) { 776*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 777*753f127fSDimitry Andric if (C2 < Leading) { 778fe6060f1SDimitry Andric // If the number of leading zeros is C2+32 this can be SRLIW. 779*753f127fSDimitry Andric if (C2 + 32 == Leading) { 78081ad6265SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 78181ad6265SDimitry Andric RISCV::SRLIW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 782fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 783fe6060f1SDimitry Andric return; 784fe6060f1SDimitry Andric } 785fe6060f1SDimitry Andric 786fe6060f1SDimitry Andric // (and (srl (sexti32 Y), c2), c1) -> (srliw (sraiw Y, 31), c3 - 32) if 787fe6060f1SDimitry Andric // c1 is a mask with c3 leading zeros and c2 >= 32 and c3-c2==1. 788fe6060f1SDimitry Andric // 789fe6060f1SDimitry Andric // This pattern occurs when (i32 (srl (sra 31), c3 - 32)) is type 790fe6060f1SDimitry Andric // legalized and goes through DAG combine. 791*753f127fSDimitry Andric if (C2 >= 32 && (Leading - C2) == 1 && N0.hasOneUse() && 79281ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 79381ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32) { 794fe6060f1SDimitry Andric SDNode *SRAIW = 79581ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SRAIW, DL, VT, X.getOperand(0), 79681ad6265SDimitry Andric CurDAG->getTargetConstant(31, DL, VT)); 797fe6060f1SDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 79881ad6265SDimitry Andric RISCV::SRLIW, DL, VT, SDValue(SRAIW, 0), 799*753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - 32, DL, VT)); 800fe6060f1SDimitry Andric ReplaceNode(Node, SRLIW); 801fe6060f1SDimitry Andric return; 802fe6060f1SDimitry Andric } 803fe6060f1SDimitry Andric 804fe6060f1SDimitry Andric // (srli (slli x, c3-c2), c3). 80581ad6265SDimitry Andric // Skip if we could use (zext.w (sraiw X, C2)). 806*753f127fSDimitry Andric bool Skip = Subtarget->hasStdExtZba() && Leading == 32 && 80781ad6265SDimitry Andric X.getOpcode() == ISD::SIGN_EXTEND_INREG && 80881ad6265SDimitry Andric cast<VTSDNode>(X.getOperand(1))->getVT() == MVT::i32; 80981ad6265SDimitry Andric // Also Skip if we can use bexti. 810*753f127fSDimitry Andric Skip |= Subtarget->hasStdExtZbs() && Leading == XLen - 1; 81181ad6265SDimitry Andric if (OneUseOrZExtW && !Skip) { 812fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 81381ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 814*753f127fSDimitry Andric CurDAG->getTargetConstant(Leading - C2, DL, VT)); 815*753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 816*753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 817*753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 818fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 819fe6060f1SDimitry Andric return; 820fe6060f1SDimitry Andric } 821fe6060f1SDimitry Andric } 822fe6060f1SDimitry Andric } 823fe6060f1SDimitry Andric 824349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (srli (slli c2+c3), c3) if c1 is a mask 825fe6060f1SDimitry Andric // shifted by c2 bits with c3 leading zeros. 826fe6060f1SDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 827*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 828fe6060f1SDimitry Andric 829*753f127fSDimitry Andric if (C2 + Leading < XLen && 830*753f127fSDimitry Andric C1 == (maskTrailingOnes<uint64_t>(XLen - (C2 + Leading)) << C2)) { 831fe6060f1SDimitry Andric // Use slli.uw when possible. 832*753f127fSDimitry Andric if ((XLen - (C2 + Leading)) == 32 && Subtarget->hasStdExtZba()) { 83381ad6265SDimitry Andric SDNode *SLLI_UW = CurDAG->getMachineNode( 83481ad6265SDimitry Andric RISCV::SLLI_UW, DL, VT, X, CurDAG->getTargetConstant(C2, DL, VT)); 8351fd87a68SDimitry Andric ReplaceNode(Node, SLLI_UW); 836fe6060f1SDimitry Andric return; 837fe6060f1SDimitry Andric } 838fe6060f1SDimitry Andric 839fe6060f1SDimitry Andric // (srli (slli c2+c3), c3) 84081ad6265SDimitry Andric if (OneUseOrZExtW && !IsCANDI) { 841fe6060f1SDimitry Andric SDNode *SLLI = CurDAG->getMachineNode( 84281ad6265SDimitry Andric RISCV::SLLI, DL, VT, X, 843*753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Leading, DL, VT)); 844*753f127fSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 845*753f127fSDimitry Andric RISCV::SRLI, DL, VT, SDValue(SLLI, 0), 846*753f127fSDimitry Andric CurDAG->getTargetConstant(Leading, DL, VT)); 847fe6060f1SDimitry Andric ReplaceNode(Node, SRLI); 848fe6060f1SDimitry Andric return; 849fe6060f1SDimitry Andric } 850fe6060f1SDimitry Andric } 851fe6060f1SDimitry Andric } 852fe6060f1SDimitry Andric 853349cc55cSDimitry Andric // Turn (and (shr x, c2), c1) -> (slli (srli x, c2+c3), c3) if c1 is a 854349cc55cSDimitry Andric // shifted mask with c2 leading zeros and c3 trailing zeros. 855349cc55cSDimitry Andric if (!LeftShift && isShiftedMask_64(C1)) { 856*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 857*753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(C1); 858*753f127fSDimitry Andric if (Leading == C2 && C2 + Trailing < XLen && OneUseOrZExtW && !IsCANDI) { 85981ad6265SDimitry Andric unsigned SrliOpc = RISCV::SRLI; 86081ad6265SDimitry Andric // If the input is zexti32 we should use SRLIW. 86181ad6265SDimitry Andric if (X.getOpcode() == ISD::AND && isa<ConstantSDNode>(X.getOperand(1)) && 86281ad6265SDimitry Andric X.getConstantOperandVal(1) == UINT64_C(0xFFFFFFFF)) { 86381ad6265SDimitry Andric SrliOpc = RISCV::SRLIW; 86481ad6265SDimitry Andric X = X.getOperand(0); 86581ad6265SDimitry Andric } 866349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 867*753f127fSDimitry Andric SrliOpc, DL, VT, X, 868*753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 869349cc55cSDimitry Andric SDNode *SLLI = 87081ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 871*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 872349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 873349cc55cSDimitry Andric return; 874349cc55cSDimitry Andric } 875349cc55cSDimitry Andric // If the leading zero count is C2+32, we can use SRLIW instead of SRLI. 876*753f127fSDimitry Andric if (Leading > 32 && (Leading - 32) == C2 && C2 + Trailing < 32 && 87781ad6265SDimitry Andric OneUseOrZExtW && !IsCANDI) { 878*753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 879*753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 880*753f127fSDimitry Andric CurDAG->getTargetConstant(C2 + Trailing, DL, VT)); 881349cc55cSDimitry Andric SDNode *SLLI = 88281ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 883*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 884349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 885349cc55cSDimitry Andric return; 886349cc55cSDimitry Andric } 887349cc55cSDimitry Andric } 888349cc55cSDimitry Andric 889349cc55cSDimitry Andric // Turn (and (shl x, c2), c1) -> (slli (srli x, c3-c2), c3) if c1 is a 890349cc55cSDimitry Andric // shifted mask with no leading zeros and c3 trailing zeros. 891349cc55cSDimitry Andric if (LeftShift && isShiftedMask_64(C1)) { 892*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(C1)); 893*753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(C1); 894*753f127fSDimitry Andric if (Leading == 0 && C2 < Trailing && OneUseOrZExtW && !IsCANDI) { 895349cc55cSDimitry Andric SDNode *SRLI = CurDAG->getMachineNode( 896*753f127fSDimitry Andric RISCV::SRLI, DL, VT, X, 897*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 898349cc55cSDimitry Andric SDNode *SLLI = 89981ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLI, 0), 900*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 901349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 902349cc55cSDimitry Andric return; 903349cc55cSDimitry Andric } 904349cc55cSDimitry Andric // If we have (32-C2) leading zeros, we can use SRLIW instead of SRLI. 905*753f127fSDimitry Andric if (C2 < Trailing && Leading + C2 == 32 && OneUseOrZExtW && !IsCANDI) { 906*753f127fSDimitry Andric SDNode *SRLIW = CurDAG->getMachineNode( 907*753f127fSDimitry Andric RISCV::SRLIW, DL, VT, X, 908*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)); 909349cc55cSDimitry Andric SDNode *SLLI = 91081ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(SRLIW, 0), 911*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)); 912349cc55cSDimitry Andric ReplaceNode(Node, SLLI); 913349cc55cSDimitry Andric return; 914349cc55cSDimitry Andric } 915349cc55cSDimitry Andric } 916349cc55cSDimitry Andric 917fe6060f1SDimitry Andric break; 918fe6060f1SDimitry Andric } 9190eae32dcSDimitry Andric case ISD::MUL: { 9200eae32dcSDimitry Andric // Special case for calculating (mul (and X, C2), C1) where the full product 9210eae32dcSDimitry Andric // fits in XLen bits. We can shift X left by the number of leading zeros in 9220eae32dcSDimitry Andric // C2 and shift C1 left by XLen-lzcnt(C2). This will ensure the final 9230eae32dcSDimitry Andric // product has XLen trailing zeros, putting it in the output of MULHU. This 9240eae32dcSDimitry Andric // can avoid materializing a constant in a register for C2. 9250eae32dcSDimitry Andric 9260eae32dcSDimitry Andric // RHS should be a constant. 9270eae32dcSDimitry Andric auto *N1C = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 9280eae32dcSDimitry Andric if (!N1C || !N1C->hasOneUse()) 9290eae32dcSDimitry Andric break; 9300eae32dcSDimitry Andric 9310eae32dcSDimitry Andric // LHS should be an AND with constant. 9320eae32dcSDimitry Andric SDValue N0 = Node->getOperand(0); 9330eae32dcSDimitry Andric if (N0.getOpcode() != ISD::AND || !isa<ConstantSDNode>(N0.getOperand(1))) 9340eae32dcSDimitry Andric break; 9350eae32dcSDimitry Andric 9360eae32dcSDimitry Andric uint64_t C2 = cast<ConstantSDNode>(N0.getOperand(1))->getZExtValue(); 9370eae32dcSDimitry Andric 9380eae32dcSDimitry Andric // Constant should be a mask. 9390eae32dcSDimitry Andric if (!isMask_64(C2)) 9400eae32dcSDimitry Andric break; 9410eae32dcSDimitry Andric 9420eae32dcSDimitry Andric // This should be the only use of the AND unless we will use 9430eae32dcSDimitry Andric // (SRLI (SLLI X, 32), 32). We don't use a shift pair for other AND 9440eae32dcSDimitry Andric // constants. 9450eae32dcSDimitry Andric if (!N0.hasOneUse() && C2 != UINT64_C(0xFFFFFFFF)) 9460eae32dcSDimitry Andric break; 9470eae32dcSDimitry Andric 9480eae32dcSDimitry Andric // If this can be an ANDI, ZEXT.H or ZEXT.W we don't need to do this 9490eae32dcSDimitry Andric // optimization. 9500eae32dcSDimitry Andric if (isInt<12>(C2) || 9510eae32dcSDimitry Andric (C2 == UINT64_C(0xFFFF) && 9520eae32dcSDimitry Andric (Subtarget->hasStdExtZbb() || Subtarget->hasStdExtZbp())) || 9530eae32dcSDimitry Andric (C2 == UINT64_C(0xFFFFFFFF) && Subtarget->hasStdExtZba())) 9540eae32dcSDimitry Andric break; 9550eae32dcSDimitry Andric 9560eae32dcSDimitry Andric // We need to shift left the AND input and C1 by a total of XLen bits. 9570eae32dcSDimitry Andric 9580eae32dcSDimitry Andric // How far left do we need to shift the AND input? 9590eae32dcSDimitry Andric unsigned XLen = Subtarget->getXLen(); 9600eae32dcSDimitry Andric unsigned LeadingZeros = XLen - (64 - countLeadingZeros(C2)); 9610eae32dcSDimitry Andric 9620eae32dcSDimitry Andric // The constant gets shifted by the remaining amount unless that would 9630eae32dcSDimitry Andric // shift bits out. 9640eae32dcSDimitry Andric uint64_t C1 = N1C->getZExtValue(); 9650eae32dcSDimitry Andric unsigned ConstantShift = XLen - LeadingZeros; 9660eae32dcSDimitry Andric if (ConstantShift > (XLen - (64 - countLeadingZeros(C1)))) 9670eae32dcSDimitry Andric break; 9680eae32dcSDimitry Andric 9690eae32dcSDimitry Andric uint64_t ShiftedC1 = C1 << ConstantShift; 9700eae32dcSDimitry Andric // If this RV32, we need to sign extend the constant. 9710eae32dcSDimitry Andric if (XLen == 32) 97281ad6265SDimitry Andric ShiftedC1 = SignExtend64<32>(ShiftedC1); 9730eae32dcSDimitry Andric 9740eae32dcSDimitry Andric // Create (mulhu (slli X, lzcnt(C2)), C1 << (XLen - lzcnt(C2))). 97504eeddc0SDimitry Andric SDNode *Imm = selectImm(CurDAG, DL, VT, ShiftedC1, *Subtarget); 9760eae32dcSDimitry Andric SDNode *SLLI = 9770eae32dcSDimitry Andric CurDAG->getMachineNode(RISCV::SLLI, DL, VT, N0.getOperand(0), 9780eae32dcSDimitry Andric CurDAG->getTargetConstant(LeadingZeros, DL, VT)); 9790eae32dcSDimitry Andric SDNode *MULHU = CurDAG->getMachineNode(RISCV::MULHU, DL, VT, 9800eae32dcSDimitry Andric SDValue(SLLI, 0), SDValue(Imm, 0)); 9810eae32dcSDimitry Andric ReplaceNode(Node, MULHU); 9820eae32dcSDimitry Andric return; 9830eae32dcSDimitry Andric } 984fe6060f1SDimitry Andric case ISD::INTRINSIC_WO_CHAIN: { 985fe6060f1SDimitry Andric unsigned IntNo = Node->getConstantOperandVal(0); 986fe6060f1SDimitry Andric switch (IntNo) { 987fe6060f1SDimitry Andric // By default we do not custom select any intrinsic. 988fe6060f1SDimitry Andric default: 989fe6060f1SDimitry Andric break; 990fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu: 991fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge: { 992fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(1); 993fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(2); 99404eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; 99504eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 996fe6060f1SDimitry Andric // Only custom select scalar second operand. 997fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 998fe6060f1SDimitry Andric break; 999fe6060f1SDimitry Andric // Small constants are handled with patterns. 1000fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1001fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 100204eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 100304eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1004fe6060f1SDimitry Andric break; 100504eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1006fe6060f1SDimitry Andric } 100704eeddc0SDimitry Andric } 1008fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 100904eeddc0SDimitry Andric unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; 1010fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1011fe6060f1SDimitry Andric default: 1012fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 101304eeddc0SDimitry Andric #define CASE_VMSLT_VMNAND_VMSET_OPCODES(lmulenum, suffix, suffix_b) \ 101404eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 101504eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 101604eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 101704eeddc0SDimitry Andric VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ 101804eeddc0SDimitry Andric VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ 1019fe6060f1SDimitry Andric break; 102004eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F8, MF8, B1) 102104eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F4, MF4, B2) 102204eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_F2, MF2, B4) 102304eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_1, M1, B8) 102404eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_2, M2, B16) 102504eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_4, M4, B32) 102604eeddc0SDimitry Andric CASE_VMSLT_VMNAND_VMSET_OPCODES(LMUL_8, M8, B64) 102704eeddc0SDimitry Andric #undef CASE_VMSLT_VMNAND_VMSET_OPCODES 1028fe6060f1SDimitry Andric } 1029fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1030fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1031fe6060f1SDimitry Andric SDValue VL; 1032fe6060f1SDimitry Andric selectVLOp(Node->getOperand(3), VL); 1033fe6060f1SDimitry Andric 103404eeddc0SDimitry Andric // If vmsgeu with 0 immediate, expand it to vmset. 103504eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 103604eeddc0SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); 103704eeddc0SDimitry Andric return; 103804eeddc0SDimitry Andric } 103904eeddc0SDimitry Andric 1040fe6060f1SDimitry Andric // Expand to 1041fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd 1042fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1043fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1044fe6060f1SDimitry Andric 0); 1045fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMNANDOpcode, DL, VT, 1046fe6060f1SDimitry Andric {Cmp, Cmp, VL, SEW})); 1047fe6060f1SDimitry Andric return; 1048fe6060f1SDimitry Andric } 1049fe6060f1SDimitry Andric case Intrinsic::riscv_vmsgeu_mask: 1050fe6060f1SDimitry Andric case Intrinsic::riscv_vmsge_mask: { 1051fe6060f1SDimitry Andric SDValue Src1 = Node->getOperand(2); 1052fe6060f1SDimitry Andric SDValue Src2 = Node->getOperand(3); 105304eeddc0SDimitry Andric bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; 105404eeddc0SDimitry Andric bool IsCmpUnsignedZero = false; 1055fe6060f1SDimitry Andric // Only custom select scalar second operand. 1056fe6060f1SDimitry Andric if (Src2.getValueType() != XLenVT) 1057fe6060f1SDimitry Andric break; 1058fe6060f1SDimitry Andric // Small constants are handled with patterns. 1059fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(Src2)) { 1060fe6060f1SDimitry Andric int64_t CVal = C->getSExtValue(); 106104eeddc0SDimitry Andric if (CVal >= -15 && CVal <= 16) { 106204eeddc0SDimitry Andric if (!IsUnsigned || CVal != 0) 1063fe6060f1SDimitry Andric break; 106404eeddc0SDimitry Andric IsCmpUnsignedZero = true; 1065fe6060f1SDimitry Andric } 106604eeddc0SDimitry Andric } 1067fe6060f1SDimitry Andric MVT Src1VT = Src1.getSimpleValueType(); 106804eeddc0SDimitry Andric unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, 106981ad6265SDimitry Andric VMOROpcode; 1070fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(Src1VT)) { 1071fe6060f1SDimitry Andric default: 1072fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 107381ad6265SDimitry Andric #define CASE_VMSLT_OPCODES(lmulenum, suffix, suffix_b) \ 107404eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 107504eeddc0SDimitry Andric VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ 107604eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix; \ 107704eeddc0SDimitry Andric VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ 107804eeddc0SDimitry Andric : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ 1079fe6060f1SDimitry Andric break; 108081ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) 108181ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) 108281ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_F2, MF2, B4) 108381ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_1, M1, B8) 108481ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_2, M2, B16) 108581ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_4, M4, B32) 108681ad6265SDimitry Andric CASE_VMSLT_OPCODES(LMUL_8, M8, B64) 108781ad6265SDimitry Andric #undef CASE_VMSLT_OPCODES 1088fe6060f1SDimitry Andric } 1089fe6060f1SDimitry Andric // Mask operations use the LMUL from the mask type. 1090fe6060f1SDimitry Andric switch (RISCVTargetLowering::getLMUL(VT)) { 1091fe6060f1SDimitry Andric default: 1092fe6060f1SDimitry Andric llvm_unreachable("Unexpected LMUL!"); 109381ad6265SDimitry Andric #define CASE_VMXOR_VMANDN_VMOR_OPCODES(lmulenum, suffix) \ 109404eeddc0SDimitry Andric case RISCVII::VLMUL::lmulenum: \ 109504eeddc0SDimitry Andric VMXOROpcode = RISCV::PseudoVMXOR_MM_##suffix; \ 109604eeddc0SDimitry Andric VMANDNOpcode = RISCV::PseudoVMANDN_MM_##suffix; \ 109781ad6265SDimitry Andric VMOROpcode = RISCV::PseudoVMOR_MM_##suffix; \ 1098fe6060f1SDimitry Andric break; 109981ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F8, MF8) 110081ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F4, MF4) 110181ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_F2, MF2) 110281ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_1, M1) 110381ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_2, M2) 110481ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_4, M4) 110581ad6265SDimitry Andric CASE_VMXOR_VMANDN_VMOR_OPCODES(LMUL_8, M8) 110681ad6265SDimitry Andric #undef CASE_VMXOR_VMANDN_VMOR_OPCODES 1107fe6060f1SDimitry Andric } 1108fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant( 1109fe6060f1SDimitry Andric Log2_32(Src1VT.getScalarSizeInBits()), DL, XLenVT); 1110fe6060f1SDimitry Andric SDValue MaskSEW = CurDAG->getTargetConstant(0, DL, XLenVT); 1111fe6060f1SDimitry Andric SDValue VL; 1112fe6060f1SDimitry Andric selectVLOp(Node->getOperand(5), VL); 1113fe6060f1SDimitry Andric SDValue MaskedOff = Node->getOperand(1); 1114fe6060f1SDimitry Andric SDValue Mask = Node->getOperand(4); 111504eeddc0SDimitry Andric 111681ad6265SDimitry Andric // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. 111704eeddc0SDimitry Andric if (IsCmpUnsignedZero) { 111881ad6265SDimitry Andric // We don't need vmor if the MaskedOff and the Mask are the same 111981ad6265SDimitry Andric // value. 112081ad6265SDimitry Andric if (Mask == MaskedOff) { 112181ad6265SDimitry Andric ReplaceUses(Node, Mask.getNode()); 112281ad6265SDimitry Andric return; 112381ad6265SDimitry Andric } 112481ad6265SDimitry Andric ReplaceNode(Node, 112581ad6265SDimitry Andric CurDAG->getMachineNode(VMOROpcode, DL, VT, 112681ad6265SDimitry Andric {Mask, MaskedOff, VL, MaskSEW})); 112704eeddc0SDimitry Andric return; 112804eeddc0SDimitry Andric } 112904eeddc0SDimitry Andric 1130fe6060f1SDimitry Andric // If the MaskedOff value and the Mask are the same value use 1131349cc55cSDimitry Andric // vmslt{u}.vx vt, va, x; vmandn.mm vd, vd, vt 1132fe6060f1SDimitry Andric // This avoids needing to copy v0 to vd before starting the next sequence. 1133fe6060f1SDimitry Andric if (Mask == MaskedOff) { 1134fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1135fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTOpcode, DL, VT, {Src1, Src2, VL, SEW}), 1136fe6060f1SDimitry Andric 0); 1137349cc55cSDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMANDNOpcode, DL, VT, 1138fe6060f1SDimitry Andric {Mask, Cmp, VL, MaskSEW})); 1139fe6060f1SDimitry Andric return; 1140fe6060f1SDimitry Andric } 1141fe6060f1SDimitry Andric 1142fe6060f1SDimitry Andric // Mask needs to be copied to V0. 1143fe6060f1SDimitry Andric SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, 1144fe6060f1SDimitry Andric RISCV::V0, Mask, SDValue()); 1145fe6060f1SDimitry Andric SDValue Glue = Chain.getValue(1); 1146fe6060f1SDimitry Andric SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); 1147fe6060f1SDimitry Andric 1148fe6060f1SDimitry Andric // Otherwise use 1149fe6060f1SDimitry Andric // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 115081ad6265SDimitry Andric // The result is mask undisturbed. 115181ad6265SDimitry Andric // We use the same instructions to emulate mask agnostic behavior, because 115281ad6265SDimitry Andric // the agnostic result can be either undisturbed or all 1. 1153fe6060f1SDimitry Andric SDValue Cmp = SDValue( 1154fe6060f1SDimitry Andric CurDAG->getMachineNode(VMSLTMaskOpcode, DL, VT, 1155fe6060f1SDimitry Andric {MaskedOff, Src1, Src2, V0, VL, SEW, Glue}), 1156fe6060f1SDimitry Andric 0); 115781ad6265SDimitry Andric // vmxor.mm vd, vd, v0 is used to update active value. 1158fe6060f1SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(VMXOROpcode, DL, VT, 1159fe6060f1SDimitry Andric {Cmp, Mask, VL, MaskSEW})); 1160fe6060f1SDimitry Andric return; 1161fe6060f1SDimitry Andric } 116204eeddc0SDimitry Andric case Intrinsic::riscv_vsetvli_opt: 116304eeddc0SDimitry Andric case Intrinsic::riscv_vsetvlimax_opt: 116404eeddc0SDimitry Andric return selectVSETVLI(Node); 1165fe6060f1SDimitry Andric } 1166fe6060f1SDimitry Andric break; 1167fe6060f1SDimitry Andric } 1168e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 1169e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1170e8d8bef9SDimitry Andric switch (IntNo) { 1171e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 1172e8d8bef9SDimitry Andric default: 11730b57cec5SDimitry Andric break; 1174fe6060f1SDimitry Andric case Intrinsic::riscv_vsetvli: 117504eeddc0SDimitry Andric case Intrinsic::riscv_vsetvlimax: 117604eeddc0SDimitry Andric return selectVSETVLI(Node); 1177e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 1178e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 1179e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 1180e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 1181e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 1182e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 1183e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 1184fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 1185e8d8bef9SDimitry Andric return; 1186e8d8bef9SDimitry Andric } 1187e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 1188e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 1189e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 1190e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 1191e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 1192e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 1193e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 1194fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1195e8d8bef9SDimitry Andric return; 1196e8d8bef9SDimitry Andric } 1197e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 1198e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 1199e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 1200e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 1201e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 1202e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 1203e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 1204fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1205e8d8bef9SDimitry Andric return; 1206e8d8bef9SDimitry Andric } 1207e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 1208e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 1209e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 1210e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 1211e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 1212e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 1213e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 1214fe6060f1SDimitry Andric selectVLSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1215e8d8bef9SDimitry Andric return; 1216e8d8bef9SDimitry Andric } 1217e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 1218e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 1219e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 1220e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 1221e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 1222e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 1223e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 1224fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1225fe6060f1SDimitry Andric return; 1226e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 1227e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 1228e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 1229e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 1230e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 1231e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 1232fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8: 1233fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1234e8d8bef9SDimitry Andric return; 1235e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 1236e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 1237e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 1238e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 1239e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 1240e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 1241e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 1242fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1243fe6060f1SDimitry Andric return; 1244e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 1245e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 1246e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 1247e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 1248e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 1249e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 1250fe6060f1SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: 1251fe6060f1SDimitry Andric selectVLXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1252fe6060f1SDimitry Andric return; 1253fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff: 1254fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff: 1255fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff: 1256fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff: 1257fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff: 1258fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff: 1259fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff: { 1260fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ false); 1261fe6060f1SDimitry Andric return; 1262fe6060f1SDimitry Andric } 1263fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg8ff_mask: 1264fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg7ff_mask: 1265fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg6ff_mask: 1266fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg5ff_mask: 1267fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg4ff_mask: 1268fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg3ff_mask: 1269fe6060f1SDimitry Andric case Intrinsic::riscv_vlseg2ff_mask: { 1270fe6060f1SDimitry Andric selectVLSEGFF(Node, /*IsMasked*/ true); 1271fe6060f1SDimitry Andric return; 1272fe6060f1SDimitry Andric } 1273fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei: 1274fe6060f1SDimitry Andric case Intrinsic::riscv_vloxei_mask: 1275fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei: 1276fe6060f1SDimitry Andric case Intrinsic::riscv_vluxei_mask: { 1277fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vloxei_mask || 1278fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vluxei_mask; 1279fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vloxei || 1280fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vloxei_mask; 1281fe6060f1SDimitry Andric 1282fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1283fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1284fe6060f1SDimitry Andric 1285fe6060f1SDimitry Andric unsigned CurOp = 2; 128604eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 128781ad6265SDimitry Andric bool IsTU = IsMasked || !Node->getOperand(CurOp).isUndef(); 1288fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 128904eeddc0SDimitry Andric if (IsTU) 1290fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 129104eeddc0SDimitry Andric else 129204eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 129304eeddc0SDimitry Andric CurOp++; 1294fe6060f1SDimitry Andric 1295fe6060f1SDimitry Andric MVT IndexVT; 1296fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1297fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1298349cc55cSDimitry Andric /*IsLoad=*/true, &IndexVT); 1299fe6060f1SDimitry Andric 1300fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1301fe6060f1SDimitry Andric "Element count mismatch"); 1302fe6060f1SDimitry Andric 1303fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1304fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1305fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 130604eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 130704eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 130804eeddc0SDimitry Andric "values when XLEN=32"); 130904eeddc0SDimitry Andric } 1310fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVLXPseudo( 131104eeddc0SDimitry Andric IsMasked, IsTU, IsOrdered, IndexLog2EEW, static_cast<unsigned>(LMUL), 1312fe6060f1SDimitry Andric static_cast<unsigned>(IndexLMUL)); 1313fe6060f1SDimitry Andric MachineSDNode *Load = 1314fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1315fe6060f1SDimitry Andric 1316fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1317fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1318fe6060f1SDimitry Andric 1319fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1320fe6060f1SDimitry Andric return; 1321fe6060f1SDimitry Andric } 1322349cc55cSDimitry Andric case Intrinsic::riscv_vlm: 1323fe6060f1SDimitry Andric case Intrinsic::riscv_vle: 1324fe6060f1SDimitry Andric case Intrinsic::riscv_vle_mask: 1325fe6060f1SDimitry Andric case Intrinsic::riscv_vlse: 1326fe6060f1SDimitry Andric case Intrinsic::riscv_vlse_mask: { 1327fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vle_mask || 1328fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse_mask; 1329fe6060f1SDimitry Andric bool IsStrided = 1330fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vlse || IntNo == Intrinsic::riscv_vlse_mask; 1331fe6060f1SDimitry Andric 1332fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1333fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1334fe6060f1SDimitry Andric 1335fe6060f1SDimitry Andric unsigned CurOp = 2; 133604eeddc0SDimitry Andric // The riscv_vlm intrinsic are always tail agnostic and no passthru operand. 133704eeddc0SDimitry Andric bool HasPassthruOperand = IntNo != Intrinsic::riscv_vlm; 133804eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 133981ad6265SDimitry Andric bool IsTU = HasPassthruOperand && 134081ad6265SDimitry Andric (IsMasked || !Node->getOperand(CurOp).isUndef()); 1341fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 134204eeddc0SDimitry Andric if (IsTU) 1343fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 134404eeddc0SDimitry Andric else if (HasPassthruOperand) 134504eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 134604eeddc0SDimitry Andric CurOp++; 1347fe6060f1SDimitry Andric 1348fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1349349cc55cSDimitry Andric Operands, /*IsLoad=*/true); 1350fe6060f1SDimitry Andric 1351fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1352fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 135304eeddc0SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsTU, IsStrided, /*FF*/ false, Log2SEW, 1354fe6060f1SDimitry Andric static_cast<unsigned>(LMUL)); 1355fe6060f1SDimitry Andric MachineSDNode *Load = 1356fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1357fe6060f1SDimitry Andric 1358fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1359fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1360fe6060f1SDimitry Andric 1361fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1362fe6060f1SDimitry Andric return; 1363fe6060f1SDimitry Andric } 1364fe6060f1SDimitry Andric case Intrinsic::riscv_vleff: 1365fe6060f1SDimitry Andric case Intrinsic::riscv_vleff_mask: { 1366fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vleff_mask; 1367fe6060f1SDimitry Andric 1368fe6060f1SDimitry Andric MVT VT = Node->getSimpleValueType(0); 1369fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1370fe6060f1SDimitry Andric 1371fe6060f1SDimitry Andric unsigned CurOp = 2; 137204eeddc0SDimitry Andric // Masked intrinsic only have TU version pseduo instructions. 137381ad6265SDimitry Andric bool IsTU = IsMasked || !Node->getOperand(CurOp).isUndef(); 1374fe6060f1SDimitry Andric SmallVector<SDValue, 7> Operands; 137504eeddc0SDimitry Andric if (IsTU) 1376fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); 137704eeddc0SDimitry Andric else 137804eeddc0SDimitry Andric // Skip the undef passthru operand for nomask TA version pseudo 137904eeddc0SDimitry Andric CurOp++; 1380fe6060f1SDimitry Andric 1381fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1382349cc55cSDimitry Andric /*IsStridedOrIndexed*/ false, Operands, 1383349cc55cSDimitry Andric /*IsLoad=*/true); 1384fe6060f1SDimitry Andric 1385fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1386fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = 138704eeddc0SDimitry Andric RISCV::getVLEPseudo(IsMasked, IsTU, /*Strided*/ false, /*FF*/ true, 138804eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 138981ad6265SDimitry Andric MachineSDNode *Load = CurDAG->getMachineNode( 139081ad6265SDimitry Andric P->Pseudo, DL, Node->getVTList(), Operands); 1391fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1392fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Load, {MemOp->getMemOperand()}); 1393fe6060f1SDimitry Andric 139481ad6265SDimitry Andric ReplaceNode(Node, Load); 13950b57cec5SDimitry Andric return; 13960b57cec5SDimitry Andric } 13970b57cec5SDimitry Andric } 13980b57cec5SDimitry Andric break; 13990b57cec5SDimitry Andric } 1400e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 1401e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 1402e8d8bef9SDimitry Andric switch (IntNo) { 1403e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 1404e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 1405e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 1406e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 1407e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 1408e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 1409e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 1410fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ false); 14110b57cec5SDimitry Andric return; 14120b57cec5SDimitry Andric } 1413e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 1414e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 1415e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 1416e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 1417e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 1418e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 1419e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 1420fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ false); 1421e8d8bef9SDimitry Andric return; 1422e8d8bef9SDimitry Andric } 1423e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 1424e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 1425e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 1426e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 1427e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 1428e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 1429e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 1430fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ false, /*IsStrided*/ true); 1431e8d8bef9SDimitry Andric return; 1432e8d8bef9SDimitry Andric } 1433e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 1434e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 1435e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 1436e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 1437e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 1438e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 1439e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 1440fe6060f1SDimitry Andric selectVSSEG(Node, /*IsMasked*/ true, /*IsStrided*/ true); 1441e8d8bef9SDimitry Andric return; 1442e8d8bef9SDimitry Andric } 1443e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 1444e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 1445e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 1446e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 1447e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 1448e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 1449e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 1450fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ true); 1451fe6060f1SDimitry Andric return; 1452e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 1453e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 1454e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 1455e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 1456e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 1457e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 1458fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8: 1459fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ false, /*IsOrdered*/ false); 1460e8d8bef9SDimitry Andric return; 1461e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 1462e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 1463e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 1464e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 1465e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 1466e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 1467e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 1468fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ true); 1469fe6060f1SDimitry Andric return; 1470e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 1471e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 1472e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 1473e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 1474e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 1475e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 1476fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: 1477fe6060f1SDimitry Andric selectVSXSEG(Node, /*IsMasked*/ true, /*IsOrdered*/ false); 1478fe6060f1SDimitry Andric return; 1479fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei: 1480fe6060f1SDimitry Andric case Intrinsic::riscv_vsoxei_mask: 1481fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei: 1482fe6060f1SDimitry Andric case Intrinsic::riscv_vsuxei_mask: { 1483fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vsoxei_mask || 1484fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsuxei_mask; 1485fe6060f1SDimitry Andric bool IsOrdered = IntNo == Intrinsic::riscv_vsoxei || 1486fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsoxei_mask; 1487fe6060f1SDimitry Andric 1488fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1489fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1490fe6060f1SDimitry Andric 1491fe6060f1SDimitry Andric unsigned CurOp = 2; 1492fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1493fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1494fe6060f1SDimitry Andric 1495fe6060f1SDimitry Andric MVT IndexVT; 1496fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, 1497fe6060f1SDimitry Andric /*IsStridedOrIndexed*/ true, Operands, 1498349cc55cSDimitry Andric /*IsLoad=*/false, &IndexVT); 1499fe6060f1SDimitry Andric 1500fe6060f1SDimitry Andric assert(VT.getVectorElementCount() == IndexVT.getVectorElementCount() && 1501fe6060f1SDimitry Andric "Element count mismatch"); 1502fe6060f1SDimitry Andric 1503fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1504fe6060f1SDimitry Andric RISCVII::VLMUL IndexLMUL = RISCVTargetLowering::getLMUL(IndexVT); 1505fe6060f1SDimitry Andric unsigned IndexLog2EEW = Log2_32(IndexVT.getScalarSizeInBits()); 150604eeddc0SDimitry Andric if (IndexLog2EEW == 6 && !Subtarget->is64Bit()) { 150704eeddc0SDimitry Andric report_fatal_error("The V extension does not support EEW=64 for index " 150804eeddc0SDimitry Andric "values when XLEN=32"); 150904eeddc0SDimitry Andric } 1510fe6060f1SDimitry Andric const RISCV::VLX_VSXPseudo *P = RISCV::getVSXPseudo( 151104eeddc0SDimitry Andric IsMasked, /*TU*/ false, IsOrdered, IndexLog2EEW, 151204eeddc0SDimitry Andric static_cast<unsigned>(LMUL), static_cast<unsigned>(IndexLMUL)); 1513fe6060f1SDimitry Andric MachineSDNode *Store = 1514fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1515fe6060f1SDimitry Andric 1516fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1517fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1518fe6060f1SDimitry Andric 1519fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1520fe6060f1SDimitry Andric return; 1521fe6060f1SDimitry Andric } 1522349cc55cSDimitry Andric case Intrinsic::riscv_vsm: 1523fe6060f1SDimitry Andric case Intrinsic::riscv_vse: 1524fe6060f1SDimitry Andric case Intrinsic::riscv_vse_mask: 1525fe6060f1SDimitry Andric case Intrinsic::riscv_vsse: 1526fe6060f1SDimitry Andric case Intrinsic::riscv_vsse_mask: { 1527fe6060f1SDimitry Andric bool IsMasked = IntNo == Intrinsic::riscv_vse_mask || 1528fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse_mask; 1529fe6060f1SDimitry Andric bool IsStrided = 1530fe6060f1SDimitry Andric IntNo == Intrinsic::riscv_vsse || IntNo == Intrinsic::riscv_vsse_mask; 1531fe6060f1SDimitry Andric 1532fe6060f1SDimitry Andric MVT VT = Node->getOperand(2)->getSimpleValueType(0); 1533fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1534fe6060f1SDimitry Andric 1535fe6060f1SDimitry Andric unsigned CurOp = 2; 1536fe6060f1SDimitry Andric SmallVector<SDValue, 8> Operands; 1537fe6060f1SDimitry Andric Operands.push_back(Node->getOperand(CurOp++)); // Store value. 1538fe6060f1SDimitry Andric 1539fe6060f1SDimitry Andric addVectorLoadStoreOperands(Node, Log2SEW, DL, CurOp, IsMasked, IsStrided, 1540fe6060f1SDimitry Andric Operands); 1541fe6060f1SDimitry Andric 1542fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1543fe6060f1SDimitry Andric const RISCV::VSEPseudo *P = RISCV::getVSEPseudo( 1544fe6060f1SDimitry Andric IsMasked, IsStrided, Log2SEW, static_cast<unsigned>(LMUL)); 1545fe6060f1SDimitry Andric MachineSDNode *Store = 1546fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1547fe6060f1SDimitry Andric if (auto *MemOp = dyn_cast<MemSDNode>(Node)) 1548fe6060f1SDimitry Andric CurDAG->setNodeMemRefs(Store, {MemOp->getMemOperand()}); 1549fe6060f1SDimitry Andric 1550fe6060f1SDimitry Andric ReplaceNode(Node, Store); 1551e8d8bef9SDimitry Andric return; 1552e8d8bef9SDimitry Andric } 1553e8d8bef9SDimitry Andric } 1554e8d8bef9SDimitry Andric break; 1555e8d8bef9SDimitry Andric } 1556fe6060f1SDimitry Andric case ISD::BITCAST: { 1557fe6060f1SDimitry Andric MVT SrcVT = Node->getOperand(0).getSimpleValueType(); 1558fe6060f1SDimitry Andric // Just drop bitcasts between vectors if both are fixed or both are 1559fe6060f1SDimitry Andric // scalable. 1560fe6060f1SDimitry Andric if ((VT.isScalableVector() && SrcVT.isScalableVector()) || 1561fe6060f1SDimitry Andric (VT.isFixedLengthVector() && SrcVT.isFixedLengthVector())) { 1562fe6060f1SDimitry Andric ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 1563fe6060f1SDimitry Andric CurDAG->RemoveDeadNode(Node); 1564e8d8bef9SDimitry Andric return; 1565e8d8bef9SDimitry Andric } 1566fe6060f1SDimitry Andric break; 1567fe6060f1SDimitry Andric } 1568fe6060f1SDimitry Andric case ISD::INSERT_SUBVECTOR: { 1569fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1570fe6060f1SDimitry Andric SDValue SubV = Node->getOperand(1); 1571fe6060f1SDimitry Andric SDLoc DL(SubV); 1572fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(2); 1573fe6060f1SDimitry Andric MVT SubVecVT = SubV.getSimpleValueType(); 1574fe6060f1SDimitry Andric 1575fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1576fe6060f1SDimitry Andric MVT SubVecContainerVT = SubVecVT; 1577fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1578fe6060f1SDimitry Andric if (SubVecVT.isFixedLengthVector()) 1579fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(SubVecVT); 1580fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1581fe6060f1SDimitry Andric VT = TLI.getContainerForFixedLengthVector(VT); 1582fe6060f1SDimitry Andric 1583fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1584fe6060f1SDimitry Andric unsigned SubRegIdx; 1585fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1586fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1587fe6060f1SDimitry Andric VT, SubVecContainerVT, Idx, TRI); 1588fe6060f1SDimitry Andric 1589fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1590fe6060f1SDimitry Andric // insert which doesn't naturally align to a vector register. These must 1591fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1592fe6060f1SDimitry Andric if (Idx != 0) 1593fe6060f1SDimitry Andric break; 1594fe6060f1SDimitry Andric 1595fe6060f1SDimitry Andric RISCVII::VLMUL SubVecLMUL = RISCVTargetLowering::getLMUL(SubVecContainerVT); 1596fe6060f1SDimitry Andric bool IsSubVecPartReg = SubVecLMUL == RISCVII::VLMUL::LMUL_F2 || 1597fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F4 || 1598fe6060f1SDimitry Andric SubVecLMUL == RISCVII::VLMUL::LMUL_F8; 1599fe6060f1SDimitry Andric (void)IsSubVecPartReg; // Silence unused variable warning without asserts. 1600fe6060f1SDimitry Andric assert((!IsSubVecPartReg || V.isUndef()) && 1601fe6060f1SDimitry Andric "Expecting lowering to have created legal INSERT_SUBVECTORs when " 1602fe6060f1SDimitry Andric "the subvector is smaller than a full-sized register"); 1603fe6060f1SDimitry Andric 1604fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1605fe6060f1SDimitry Andric // equally-sized LMUL groups (e.g. VR -> VR). This can be done as a copy. 1606fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1607fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(VT); 1608fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1609fe6060f1SDimitry Andric InRegClassID && 1610fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1611fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1612fe6060f1SDimitry Andric SDNode *NewNode = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, 1613fe6060f1SDimitry Andric DL, VT, SubV, RC); 1614fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1615fe6060f1SDimitry Andric return; 1616fe6060f1SDimitry Andric } 1617fe6060f1SDimitry Andric 1618fe6060f1SDimitry Andric SDValue Insert = CurDAG->getTargetInsertSubreg(SubRegIdx, DL, VT, V, SubV); 1619fe6060f1SDimitry Andric ReplaceNode(Node, Insert.getNode()); 1620fe6060f1SDimitry Andric return; 1621fe6060f1SDimitry Andric } 1622fe6060f1SDimitry Andric case ISD::EXTRACT_SUBVECTOR: { 1623fe6060f1SDimitry Andric SDValue V = Node->getOperand(0); 1624fe6060f1SDimitry Andric auto Idx = Node->getConstantOperandVal(1); 1625fe6060f1SDimitry Andric MVT InVT = V.getSimpleValueType(); 1626fe6060f1SDimitry Andric SDLoc DL(V); 1627fe6060f1SDimitry Andric 1628fe6060f1SDimitry Andric const RISCVTargetLowering &TLI = *Subtarget->getTargetLowering(); 1629fe6060f1SDimitry Andric MVT SubVecContainerVT = VT; 1630fe6060f1SDimitry Andric // Establish the correct scalable-vector types for any fixed-length type. 1631fe6060f1SDimitry Andric if (VT.isFixedLengthVector()) 1632fe6060f1SDimitry Andric SubVecContainerVT = TLI.getContainerForFixedLengthVector(VT); 1633fe6060f1SDimitry Andric if (InVT.isFixedLengthVector()) 1634fe6060f1SDimitry Andric InVT = TLI.getContainerForFixedLengthVector(InVT); 1635fe6060f1SDimitry Andric 1636fe6060f1SDimitry Andric const auto *TRI = Subtarget->getRegisterInfo(); 1637fe6060f1SDimitry Andric unsigned SubRegIdx; 1638fe6060f1SDimitry Andric std::tie(SubRegIdx, Idx) = 1639fe6060f1SDimitry Andric RISCVTargetLowering::decomposeSubvectorInsertExtractToSubRegs( 1640fe6060f1SDimitry Andric InVT, SubVecContainerVT, Idx, TRI); 1641fe6060f1SDimitry Andric 1642fe6060f1SDimitry Andric // If the Idx hasn't been completely eliminated then this is a subvector 1643fe6060f1SDimitry Andric // extract which doesn't naturally align to a vector register. These must 1644fe6060f1SDimitry Andric // be handled using instructions to manipulate the vector registers. 1645fe6060f1SDimitry Andric if (Idx != 0) 1646fe6060f1SDimitry Andric break; 1647fe6060f1SDimitry Andric 1648fe6060f1SDimitry Andric // If we haven't set a SubRegIdx, then we must be going between 1649fe6060f1SDimitry Andric // equally-sized LMUL types (e.g. VR -> VR). This can be done as a copy. 1650fe6060f1SDimitry Andric if (SubRegIdx == RISCV::NoSubRegister) { 1651fe6060f1SDimitry Andric unsigned InRegClassID = RISCVTargetLowering::getRegClassIDForVecVT(InVT); 1652fe6060f1SDimitry Andric assert(RISCVTargetLowering::getRegClassIDForVecVT(SubVecContainerVT) == 1653fe6060f1SDimitry Andric InRegClassID && 1654fe6060f1SDimitry Andric "Unexpected subvector extraction"); 1655fe6060f1SDimitry Andric SDValue RC = CurDAG->getTargetConstant(InRegClassID, DL, XLenVT); 1656fe6060f1SDimitry Andric SDNode *NewNode = 1657fe6060f1SDimitry Andric CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, VT, V, RC); 1658fe6060f1SDimitry Andric ReplaceNode(Node, NewNode); 1659fe6060f1SDimitry Andric return; 1660fe6060f1SDimitry Andric } 1661fe6060f1SDimitry Andric 1662fe6060f1SDimitry Andric SDValue Extract = CurDAG->getTargetExtractSubreg(SubRegIdx, DL, VT, V); 1663fe6060f1SDimitry Andric ReplaceNode(Node, Extract.getNode()); 1664fe6060f1SDimitry Andric return; 1665fe6060f1SDimitry Andric } 16660eae32dcSDimitry Andric case ISD::SPLAT_VECTOR: 166704eeddc0SDimitry Andric case RISCVISD::VMV_S_X_VL: 166804eeddc0SDimitry Andric case RISCVISD::VFMV_S_F_VL: 1669fe6060f1SDimitry Andric case RISCVISD::VMV_V_X_VL: 1670fe6060f1SDimitry Andric case RISCVISD::VFMV_V_F_VL: { 1671fe6060f1SDimitry Andric // Try to match splat of a scalar load to a strided load with stride of x0. 167204eeddc0SDimitry Andric bool IsScalarMove = Node->getOpcode() == RISCVISD::VMV_S_X_VL || 167304eeddc0SDimitry Andric Node->getOpcode() == RISCVISD::VFMV_S_F_VL; 167481ad6265SDimitry Andric bool HasPassthruOperand = Node->getOpcode() != ISD::SPLAT_VECTOR; 167581ad6265SDimitry Andric if (HasPassthruOperand && !Node->getOperand(0).isUndef()) 167604eeddc0SDimitry Andric break; 167781ad6265SDimitry Andric SDValue Src = HasPassthruOperand ? Node->getOperand(1) : Node->getOperand(0); 1678fe6060f1SDimitry Andric auto *Ld = dyn_cast<LoadSDNode>(Src); 1679fe6060f1SDimitry Andric if (!Ld) 1680fe6060f1SDimitry Andric break; 1681fe6060f1SDimitry Andric EVT MemVT = Ld->getMemoryVT(); 1682fe6060f1SDimitry Andric // The memory VT should be the same size as the element type. 1683fe6060f1SDimitry Andric if (MemVT.getStoreSize() != VT.getVectorElementType().getStoreSize()) 1684fe6060f1SDimitry Andric break; 1685fe6060f1SDimitry Andric if (!IsProfitableToFold(Src, Node, Node) || 1686fe6060f1SDimitry Andric !IsLegalToFold(Src, Node, Node, TM.getOptLevel())) 1687fe6060f1SDimitry Andric break; 1688fe6060f1SDimitry Andric 1689fe6060f1SDimitry Andric SDValue VL; 16900eae32dcSDimitry Andric if (Node->getOpcode() == ISD::SPLAT_VECTOR) 16910eae32dcSDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, DL, XLenVT); 169204eeddc0SDimitry Andric else if (IsScalarMove) { 169304eeddc0SDimitry Andric // We could deal with more VL if we update the VSETVLI insert pass to 169404eeddc0SDimitry Andric // avoid introducing more VSETVLI. 169504eeddc0SDimitry Andric if (!isOneConstant(Node->getOperand(2))) 169604eeddc0SDimitry Andric break; 169704eeddc0SDimitry Andric selectVLOp(Node->getOperand(2), VL); 169804eeddc0SDimitry Andric } else 169981ad6265SDimitry Andric selectVLOp(Node->getOperand(2), VL); 1700fe6060f1SDimitry Andric 1701fe6060f1SDimitry Andric unsigned Log2SEW = Log2_32(VT.getScalarSizeInBits()); 1702fe6060f1SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(Log2SEW, DL, XLenVT); 1703fe6060f1SDimitry Andric 1704fe6060f1SDimitry Andric SDValue Operands[] = {Ld->getBasePtr(), 1705fe6060f1SDimitry Andric CurDAG->getRegister(RISCV::X0, XLenVT), VL, SEW, 1706fe6060f1SDimitry Andric Ld->getChain()}; 1707fe6060f1SDimitry Andric 1708fe6060f1SDimitry Andric RISCVII::VLMUL LMUL = RISCVTargetLowering::getLMUL(VT); 1709fe6060f1SDimitry Andric const RISCV::VLEPseudo *P = RISCV::getVLEPseudo( 171004eeddc0SDimitry Andric /*IsMasked*/ false, /*IsTU*/ false, /*IsStrided*/ true, /*FF*/ false, 171104eeddc0SDimitry Andric Log2SEW, static_cast<unsigned>(LMUL)); 1712fe6060f1SDimitry Andric MachineSDNode *Load = 1713fe6060f1SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getVTList(), Operands); 1714fe6060f1SDimitry Andric 171581ad6265SDimitry Andric CurDAG->setNodeMemRefs(Load, {Ld->getMemOperand()}); 1716fe6060f1SDimitry Andric 1717fe6060f1SDimitry Andric ReplaceNode(Node, Load); 1718e8d8bef9SDimitry Andric return; 1719e8d8bef9SDimitry Andric } 1720e8d8bef9SDimitry Andric } 17210b57cec5SDimitry Andric 17220b57cec5SDimitry Andric // Select the default instruction. 17230b57cec5SDimitry Andric SelectCode(Node); 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 17270b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 17280b57cec5SDimitry Andric switch (ConstraintID) { 17290b57cec5SDimitry Andric case InlineAsm::Constraint_m: 17300b57cec5SDimitry Andric // We just support simple memory operands that have a single address 17310b57cec5SDimitry Andric // operand and need no special handling. 17320b57cec5SDimitry Andric OutOps.push_back(Op); 17330b57cec5SDimitry Andric return false; 17340b57cec5SDimitry Andric case InlineAsm::Constraint_A: 17350b57cec5SDimitry Andric OutOps.push_back(Op); 17360b57cec5SDimitry Andric return false; 17370b57cec5SDimitry Andric default: 17380b57cec5SDimitry Andric break; 17390b57cec5SDimitry Andric } 17400b57cec5SDimitry Andric 17410b57cec5SDimitry Andric return true; 17420b57cec5SDimitry Andric } 17430b57cec5SDimitry Andric 174481ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFrameIndex(SDValue Addr, SDValue &Base, 174581ad6265SDimitry Andric SDValue &Offset) { 1746fe6060f1SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 17470b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 174881ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Subtarget->getXLenVT()); 17490b57cec5SDimitry Andric return true; 17500b57cec5SDimitry Andric } 175181ad6265SDimitry Andric 175281ad6265SDimitry Andric return false; 175381ad6265SDimitry Andric } 175481ad6265SDimitry Andric 175581ad6265SDimitry Andric // Select a frame index and an optional immediate offset from an ADD or OR. 175681ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectFrameAddrRegImm(SDValue Addr, SDValue &Base, 175781ad6265SDimitry Andric SDValue &Offset) { 175881ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 175981ad6265SDimitry Andric return true; 176081ad6265SDimitry Andric 176181ad6265SDimitry Andric if (!CurDAG->isBaseWithConstantOffset(Addr)) 176281ad6265SDimitry Andric return false; 176381ad6265SDimitry Andric 176481ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 176581ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 176681ad6265SDimitry Andric if (isInt<12>(CVal)) { 176781ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), 176881ad6265SDimitry Andric Subtarget->getXLenVT()); 176981ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, SDLoc(Addr), 177081ad6265SDimitry Andric Subtarget->getXLenVT()); 177181ad6265SDimitry Andric return true; 177281ad6265SDimitry Andric } 177381ad6265SDimitry Andric } 177481ad6265SDimitry Andric 17750b57cec5SDimitry Andric return false; 17760b57cec5SDimitry Andric } 17770b57cec5SDimitry Andric 1778*753f127fSDimitry Andric // Fold constant addresses. 1779*753f127fSDimitry Andric static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, 1780*753f127fSDimitry Andric const MVT VT, const RISCVSubtarget *Subtarget, 1781*753f127fSDimitry Andric SDValue Addr, SDValue &Base, SDValue &Offset) { 1782*753f127fSDimitry Andric if (!isa<ConstantSDNode>(Addr)) 1783*753f127fSDimitry Andric return false; 1784*753f127fSDimitry Andric 1785*753f127fSDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 1786*753f127fSDimitry Andric 1787*753f127fSDimitry Andric // If the constant is a simm12, we can fold the whole constant and use X0 as 1788*753f127fSDimitry Andric // the base. If the constant can be materialized with LUI+simm12, use LUI as 1789*753f127fSDimitry Andric // the base. We can't use generateInstSeq because it favors LUI+ADDIW. 1790*753f127fSDimitry Andric int64_t Lo12 = SignExtend64<12>(CVal); 1791*753f127fSDimitry Andric int64_t Hi = (uint64_t)CVal - (uint64_t)Lo12; 1792*753f127fSDimitry Andric if (!Subtarget->is64Bit() || isInt<32>(Hi)) { 1793*753f127fSDimitry Andric if (Hi) { 1794*753f127fSDimitry Andric int64_t Hi20 = (Hi >> 12) & 0xfffff; 1795*753f127fSDimitry Andric Base = SDValue( 1796*753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::LUI, DL, VT, 1797*753f127fSDimitry Andric CurDAG->getTargetConstant(Hi20, DL, VT)), 1798*753f127fSDimitry Andric 0); 1799*753f127fSDimitry Andric } else { 1800*753f127fSDimitry Andric Base = CurDAG->getRegister(RISCV::X0, VT); 1801*753f127fSDimitry Andric } 1802*753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 1803*753f127fSDimitry Andric return true; 1804*753f127fSDimitry Andric } 1805*753f127fSDimitry Andric 1806*753f127fSDimitry Andric // Ask how constant materialization would handle this constant. 1807*753f127fSDimitry Andric RISCVMatInt::InstSeq Seq = 1808*753f127fSDimitry Andric RISCVMatInt::generateInstSeq(CVal, Subtarget->getFeatureBits()); 1809*753f127fSDimitry Andric 1810*753f127fSDimitry Andric // If the last instruction would be an ADDI, we can fold its immediate and 1811*753f127fSDimitry Andric // emit the rest of the sequence as the base. 1812*753f127fSDimitry Andric if (Seq.back().Opc != RISCV::ADDI) 1813*753f127fSDimitry Andric return false; 1814*753f127fSDimitry Andric Lo12 = Seq.back().Imm; 1815*753f127fSDimitry Andric 1816*753f127fSDimitry Andric // Drop the last instruction. 1817*753f127fSDimitry Andric Seq.pop_back(); 1818*753f127fSDimitry Andric assert(!Seq.empty() && "Expected more instructions in sequence"); 1819*753f127fSDimitry Andric 1820*753f127fSDimitry Andric Base = SDValue(selectImmSeq(CurDAG, DL, VT, Seq), 0); 1821*753f127fSDimitry Andric Offset = CurDAG->getTargetConstant(Lo12, DL, VT); 1822*753f127fSDimitry Andric return true; 1823*753f127fSDimitry Andric } 1824*753f127fSDimitry Andric 1825*753f127fSDimitry Andric // Is this ADD instruction only used as the base pointer of scalar loads and 1826*753f127fSDimitry Andric // stores? 1827*753f127fSDimitry Andric static bool isWorthFoldingAdd(SDValue Add) { 1828*753f127fSDimitry Andric for (auto Use : Add->uses()) { 1829*753f127fSDimitry Andric if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && 1830*753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_LOAD && 1831*753f127fSDimitry Andric Use->getOpcode() != ISD::ATOMIC_STORE) 1832*753f127fSDimitry Andric return false; 1833*753f127fSDimitry Andric EVT VT = cast<MemSDNode>(Use)->getMemoryVT(); 1834*753f127fSDimitry Andric if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && 1835*753f127fSDimitry Andric VT != MVT::f64) 1836*753f127fSDimitry Andric return false; 1837*753f127fSDimitry Andric // Don't allow stores of the value. It must be used as the address. 1838*753f127fSDimitry Andric if (Use->getOpcode() == ISD::STORE && 1839*753f127fSDimitry Andric cast<StoreSDNode>(Use)->getValue() == Add) 1840*753f127fSDimitry Andric return false; 1841*753f127fSDimitry Andric if (Use->getOpcode() == ISD::ATOMIC_STORE && 1842*753f127fSDimitry Andric cast<AtomicSDNode>(Use)->getVal() == Add) 1843*753f127fSDimitry Andric return false; 1844*753f127fSDimitry Andric } 1845*753f127fSDimitry Andric 1846fe6060f1SDimitry Andric return true; 1847e8d8bef9SDimitry Andric } 1848e8d8bef9SDimitry Andric 184981ad6265SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrRegImm(SDValue Addr, SDValue &Base, 185081ad6265SDimitry Andric SDValue &Offset) { 185181ad6265SDimitry Andric if (SelectAddrFrameIndex(Addr, Base, Offset)) 185281ad6265SDimitry Andric return true; 185381ad6265SDimitry Andric 185481ad6265SDimitry Andric SDLoc DL(Addr); 185581ad6265SDimitry Andric MVT VT = Addr.getSimpleValueType(); 185681ad6265SDimitry Andric 185781ad6265SDimitry Andric if (Addr.getOpcode() == RISCVISD::ADD_LO) { 185881ad6265SDimitry Andric Base = Addr.getOperand(0); 185981ad6265SDimitry Andric Offset = Addr.getOperand(1); 186081ad6265SDimitry Andric return true; 186181ad6265SDimitry Andric } 186281ad6265SDimitry Andric 186381ad6265SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 186481ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 186581ad6265SDimitry Andric if (isInt<12>(CVal)) { 186681ad6265SDimitry Andric Base = Addr.getOperand(0); 186781ad6265SDimitry Andric if (Base.getOpcode() == RISCVISD::ADD_LO) { 186881ad6265SDimitry Andric SDValue LoOperand = Base.getOperand(1); 186981ad6265SDimitry Andric if (auto *GA = dyn_cast<GlobalAddressSDNode>(LoOperand)) { 187081ad6265SDimitry Andric // If the Lo in (ADD_LO hi, lo) is a global variable's address 187181ad6265SDimitry Andric // (its low part, really), then we can rely on the alignment of that 187281ad6265SDimitry Andric // variable to provide a margin of safety before low part can overflow 187381ad6265SDimitry Andric // the 12 bits of the load/store offset. Check if CVal falls within 187481ad6265SDimitry Andric // that margin; if so (low part + CVal) can't overflow. 187581ad6265SDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 187681ad6265SDimitry Andric Align Alignment = commonAlignment( 187781ad6265SDimitry Andric GA->getGlobal()->getPointerAlignment(DL), GA->getOffset()); 187881ad6265SDimitry Andric if (CVal == 0 || Alignment > CVal) { 187981ad6265SDimitry Andric int64_t CombinedOffset = CVal + GA->getOffset(); 188081ad6265SDimitry Andric Base = Base.getOperand(0); 188181ad6265SDimitry Andric Offset = CurDAG->getTargetGlobalAddress( 188281ad6265SDimitry Andric GA->getGlobal(), SDLoc(LoOperand), LoOperand.getValueType(), 188381ad6265SDimitry Andric CombinedOffset, GA->getTargetFlags()); 188481ad6265SDimitry Andric return true; 188581ad6265SDimitry Andric } 188681ad6265SDimitry Andric } 188781ad6265SDimitry Andric } 188881ad6265SDimitry Andric 188981ad6265SDimitry Andric if (auto *FIN = dyn_cast<FrameIndexSDNode>(Base)) 189081ad6265SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), VT); 189181ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal, DL, VT); 189281ad6265SDimitry Andric return true; 189381ad6265SDimitry Andric } 189481ad6265SDimitry Andric } 189581ad6265SDimitry Andric 189681ad6265SDimitry Andric // Handle ADD with large immediates. 189781ad6265SDimitry Andric if (Addr.getOpcode() == ISD::ADD && isa<ConstantSDNode>(Addr.getOperand(1))) { 189881ad6265SDimitry Andric int64_t CVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue(); 189981ad6265SDimitry Andric assert(!isInt<12>(CVal) && "simm12 not already handled?"); 190081ad6265SDimitry Andric 1901*753f127fSDimitry Andric // Handle immediates in the range [-4096,-2049] or [2048, 4094]. We can use 1902*753f127fSDimitry Andric // an ADDI for part of the offset and fold the rest into the load/store. 1903*753f127fSDimitry Andric // This mirrors the AddiPair PatFrag in RISCVInstrInfo.td. 190481ad6265SDimitry Andric if (isInt<12>(CVal / 2) && isInt<12>(CVal - CVal / 2)) { 190581ad6265SDimitry Andric int64_t Adj = CVal < 0 ? -2048 : 2047; 190681ad6265SDimitry Andric Base = SDValue( 190781ad6265SDimitry Andric CurDAG->getMachineNode(RISCV::ADDI, DL, VT, Addr.getOperand(0), 190881ad6265SDimitry Andric CurDAG->getTargetConstant(Adj, DL, VT)), 190981ad6265SDimitry Andric 0); 191081ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(CVal - Adj, DL, VT); 191181ad6265SDimitry Andric return true; 191281ad6265SDimitry Andric } 1913*753f127fSDimitry Andric 1914*753f127fSDimitry Andric // For larger immediates, we might be able to save one instruction from 1915*753f127fSDimitry Andric // constant materialization by folding the Lo12 bits of the immediate into 1916*753f127fSDimitry Andric // the address. We should only do this if the ADD is only used by loads and 1917*753f127fSDimitry Andric // stores that can fold the lo12 bits. Otherwise, the ADD will get iseled 1918*753f127fSDimitry Andric // separately with the full materialized immediate creating extra 1919*753f127fSDimitry Andric // instructions. 1920*753f127fSDimitry Andric if (isWorthFoldingAdd(Addr) && 1921*753f127fSDimitry Andric selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr.getOperand(1), Base, 1922*753f127fSDimitry Andric Offset)) { 1923*753f127fSDimitry Andric // Insert an ADD instruction with the materialized Hi52 bits. 1924*753f127fSDimitry Andric Base = SDValue( 1925*753f127fSDimitry Andric CurDAG->getMachineNode(RISCV::ADD, DL, VT, Addr.getOperand(0), Base), 1926*753f127fSDimitry Andric 0); 1927*753f127fSDimitry Andric return true; 192881ad6265SDimitry Andric } 1929*753f127fSDimitry Andric } 1930*753f127fSDimitry Andric 1931*753f127fSDimitry Andric if (selectConstantAddr(CurDAG, DL, VT, Subtarget, Addr, Base, Offset)) 1932*753f127fSDimitry Andric return true; 193381ad6265SDimitry Andric 193481ad6265SDimitry Andric Base = Addr; 193581ad6265SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, VT); 193681ad6265SDimitry Andric return true; 193781ad6265SDimitry Andric } 193881ad6265SDimitry Andric 1939fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 1940fe6060f1SDimitry Andric SDValue &ShAmt) { 1941fe6060f1SDimitry Andric // Shift instructions on RISCV only read the lower 5 or 6 bits of the shift 1942fe6060f1SDimitry Andric // amount. If there is an AND on the shift amount, we can bypass it if it 1943fe6060f1SDimitry Andric // doesn't affect any of those bits. 1944fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 1945fe6060f1SDimitry Andric const APInt &AndMask = N->getConstantOperandAPInt(1); 1946979e22ffSDimitry Andric 1947fe6060f1SDimitry Andric // Since the max shift amount is a power of 2 we can subtract 1 to make a 1948fe6060f1SDimitry Andric // mask that covers the bits needed to represent all shift amounts. 1949fe6060f1SDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 1950fe6060f1SDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 1951e8d8bef9SDimitry Andric 1952fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 1953fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1954fe6060f1SDimitry Andric return true; 1955e8d8bef9SDimitry Andric } 1956e8d8bef9SDimitry Andric 1957fe6060f1SDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 1958fe6060f1SDimitry Andric // bits that are known zero. 1959fe6060f1SDimitry Andric KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 1960fe6060f1SDimitry Andric if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 1961fe6060f1SDimitry Andric ShAmt = N.getOperand(0); 1962fe6060f1SDimitry Andric return true; 1963fe6060f1SDimitry Andric } 196481ad6265SDimitry Andric } else if (N.getOpcode() == ISD::SUB && 196581ad6265SDimitry Andric isa<ConstantSDNode>(N.getOperand(0))) { 196681ad6265SDimitry Andric uint64_t Imm = N.getConstantOperandVal(0); 196781ad6265SDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 196881ad6265SDimitry Andric // generate a NEG instead of a SUB of a constant. 196981ad6265SDimitry Andric if (Imm != 0 && Imm % ShiftWidth == 0) { 197081ad6265SDimitry Andric SDLoc DL(N); 197181ad6265SDimitry Andric EVT VT = N.getValueType(); 197281ad6265SDimitry Andric SDValue Zero = CurDAG->getRegister(RISCV::X0, VT); 197381ad6265SDimitry Andric unsigned NegOpc = VT == MVT::i64 ? RISCV::SUBW : RISCV::SUB; 197481ad6265SDimitry Andric MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, VT, Zero, 197581ad6265SDimitry Andric N.getOperand(1)); 197681ad6265SDimitry Andric ShAmt = SDValue(Neg, 0); 197781ad6265SDimitry Andric return true; 197881ad6265SDimitry Andric } 1979fe6060f1SDimitry Andric } 1980fe6060f1SDimitry Andric 1981fe6060f1SDimitry Andric ShAmt = N; 1982fe6060f1SDimitry Andric return true; 1983fe6060f1SDimitry Andric } 1984fe6060f1SDimitry Andric 1985fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 1986fe6060f1SDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 1987fe6060f1SDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 1988fe6060f1SDimitry Andric Val = N.getOperand(0); 1989fe6060f1SDimitry Andric return true; 1990fe6060f1SDimitry Andric } 1991fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 1992fe6060f1SDimitry Andric if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 1993fe6060f1SDimitry Andric Val = N; 1994fe6060f1SDimitry Andric return true; 1995fe6060f1SDimitry Andric } 1996fe6060f1SDimitry Andric 1997fe6060f1SDimitry Andric return false; 1998fe6060f1SDimitry Andric } 1999fe6060f1SDimitry Andric 2000fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 2001fe6060f1SDimitry Andric if (N.getOpcode() == ISD::AND) { 2002fe6060f1SDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 2003fe6060f1SDimitry Andric if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 2004fe6060f1SDimitry Andric Val = N.getOperand(0); 2005fe6060f1SDimitry Andric return true; 2006fe6060f1SDimitry Andric } 2007fe6060f1SDimitry Andric } 2008fe6060f1SDimitry Andric MVT VT = N.getSimpleValueType(); 2009fe6060f1SDimitry Andric APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 2010fe6060f1SDimitry Andric if (CurDAG->MaskedValueIsZero(N, Mask)) { 2011fe6060f1SDimitry Andric Val = N; 2012fe6060f1SDimitry Andric return true; 2013fe6060f1SDimitry Andric } 2014fe6060f1SDimitry Andric 2015fe6060f1SDimitry Andric return false; 2016fe6060f1SDimitry Andric } 2017fe6060f1SDimitry Andric 2018*753f127fSDimitry Andric /// Look for various patterns that can be done with a SHL that can be folded 2019*753f127fSDimitry Andric /// into a SHXADD. \p ShAmt contains 1, 2, or 3 and is set based on which 2020*753f127fSDimitry Andric /// SHXADD we are trying to match. 2021*753f127fSDimitry Andric bool RISCVDAGToDAGISel::selectSHXADDOp(SDValue N, unsigned ShAmt, 2022*753f127fSDimitry Andric SDValue &Val) { 2023*753f127fSDimitry Andric if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 2024*753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2025*753f127fSDimitry Andric 2026*753f127fSDimitry Andric bool LeftShift = N0.getOpcode() == ISD::SHL; 2027*753f127fSDimitry Andric if ((LeftShift || N0.getOpcode() == ISD::SRL) && 2028*753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2029*753f127fSDimitry Andric uint64_t Mask = N.getConstantOperandVal(1); 2030*753f127fSDimitry Andric unsigned C2 = N0.getConstantOperandVal(1); 2031*753f127fSDimitry Andric 2032*753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2033*753f127fSDimitry Andric if (LeftShift) 2034*753f127fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2); 2035*753f127fSDimitry Andric else 2036*753f127fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2); 2037*753f127fSDimitry Andric 2038*753f127fSDimitry Andric // Look for (and (shl y, c2), c1) where c1 is a shifted mask with no 2039*753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by c2+c3 2040*753f127fSDimitry Andric // followed by a SHXADD with c3 for the X amount. 2041*753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2042*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(Mask)); 2043*753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(Mask); 2044*753f127fSDimitry Andric if (LeftShift && Leading == 0 && C2 < Trailing && Trailing == ShAmt) { 2045*753f127fSDimitry Andric SDLoc DL(N); 2046*753f127fSDimitry Andric EVT VT = N.getValueType(); 2047*753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2048*753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2049*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing - C2, DL, VT)), 2050*753f127fSDimitry Andric 0); 2051*753f127fSDimitry Andric return true; 2052*753f127fSDimitry Andric } 2053*753f127fSDimitry Andric // Look for (and (shr y, c2), c1) where c1 is a shifted mask with c2 2054*753f127fSDimitry Andric // leading zeros and c3 trailing zeros. We can use an SRLI by C3 2055*753f127fSDimitry Andric // followed by a SHXADD using c3 for the X amount. 2056*753f127fSDimitry Andric if (!LeftShift && Leading == C2 && Trailing == ShAmt) { 2057*753f127fSDimitry Andric SDLoc DL(N); 2058*753f127fSDimitry Andric EVT VT = N.getValueType(); 2059*753f127fSDimitry Andric Val = SDValue( 2060*753f127fSDimitry Andric CurDAG->getMachineNode( 2061*753f127fSDimitry Andric RISCV::SRLI, DL, VT, N0.getOperand(0), 2062*753f127fSDimitry Andric CurDAG->getTargetConstant(Leading + Trailing, DL, VT)), 2063*753f127fSDimitry Andric 0); 2064*753f127fSDimitry Andric return true; 2065*753f127fSDimitry Andric } 2066*753f127fSDimitry Andric } 2067*753f127fSDimitry Andric } 2068*753f127fSDimitry Andric } 2069*753f127fSDimitry Andric 2070*753f127fSDimitry Andric bool LeftShift = N.getOpcode() == ISD::SHL; 2071*753f127fSDimitry Andric if ((LeftShift || N.getOpcode() == ISD::SRL) && 2072*753f127fSDimitry Andric isa<ConstantSDNode>(N.getOperand(1))) { 2073*753f127fSDimitry Andric SDValue N0 = N.getOperand(0); 2074*753f127fSDimitry Andric if (N0.getOpcode() == ISD::AND && N0.hasOneUse() && 2075*753f127fSDimitry Andric isa<ConstantSDNode>(N0.getOperand(1))) { 2076*753f127fSDimitry Andric uint64_t Mask = N0.getConstantOperandVal(1); 2077*753f127fSDimitry Andric if (isShiftedMask_64(Mask)) { 2078*753f127fSDimitry Andric unsigned C1 = N.getConstantOperandVal(1); 2079*753f127fSDimitry Andric unsigned XLen = Subtarget->getXLen(); 2080*753f127fSDimitry Andric unsigned Leading = XLen - (64 - countLeadingZeros(Mask)); 2081*753f127fSDimitry Andric unsigned Trailing = countTrailingZeros(Mask); 2082*753f127fSDimitry Andric // Look for (shl (and X, Mask), C1) where Mask has 32 leading zeros and 2083*753f127fSDimitry Andric // C3 trailing zeros. If C1+C3==ShAmt we can use SRLIW+SHXADD. 2084*753f127fSDimitry Andric if (LeftShift && Leading == 32 && Trailing > 0 && 2085*753f127fSDimitry Andric (Trailing + C1) == ShAmt) { 2086*753f127fSDimitry Andric SDLoc DL(N); 2087*753f127fSDimitry Andric EVT VT = N.getValueType(); 2088*753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2089*753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2090*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2091*753f127fSDimitry Andric 0); 2092*753f127fSDimitry Andric return true; 2093*753f127fSDimitry Andric } 2094*753f127fSDimitry Andric // Look for (srl (and X, Mask), C1) where Mask has 32 leading zeros and 2095*753f127fSDimitry Andric // C3 trailing zeros. If C3-C1==ShAmt we can use SRLIW+SHXADD. 2096*753f127fSDimitry Andric if (!LeftShift && Leading == 32 && Trailing > C1 && 2097*753f127fSDimitry Andric (Trailing - C1) == ShAmt) { 2098*753f127fSDimitry Andric SDLoc DL(N); 2099*753f127fSDimitry Andric EVT VT = N.getValueType(); 2100*753f127fSDimitry Andric Val = SDValue(CurDAG->getMachineNode( 2101*753f127fSDimitry Andric RISCV::SRLIW, DL, VT, N0.getOperand(0), 2102*753f127fSDimitry Andric CurDAG->getTargetConstant(Trailing, DL, VT)), 2103*753f127fSDimitry Andric 0); 2104*753f127fSDimitry Andric return true; 2105*753f127fSDimitry Andric } 2106*753f127fSDimitry Andric } 2107*753f127fSDimitry Andric } 2108*753f127fSDimitry Andric } 2109*753f127fSDimitry Andric 2110*753f127fSDimitry Andric return false; 2111*753f127fSDimitry Andric } 2112*753f127fSDimitry Andric 2113349cc55cSDimitry Andric // Return true if all users of this SDNode* only consume the lower \p Bits. 2114349cc55cSDimitry Andric // This can be used to form W instructions for add/sub/mul/shl even when the 2115349cc55cSDimitry Andric // root isn't a sext_inreg. This can allow the ADDW/SUBW/MULW/SLLIW to CSE if 2116349cc55cSDimitry Andric // SimplifyDemandedBits has made it so some users see a sext_inreg and some 2117349cc55cSDimitry Andric // don't. The sext_inreg+add/sub/mul/shl will get selected, but still leave 2118349cc55cSDimitry Andric // the add/sub/mul/shl to become non-W instructions. By checking the users we 2119349cc55cSDimitry Andric // may be able to use a W instruction and CSE with the other instruction if 2120349cc55cSDimitry Andric // this has happened. We could try to detect that the CSE opportunity exists 2121349cc55cSDimitry Andric // before doing this, but that would be more complicated. 2122349cc55cSDimitry Andric // TODO: Does this need to look through AND/OR/XOR to their users to find more 2123349cc55cSDimitry Andric // opportunities. 2124349cc55cSDimitry Andric bool RISCVDAGToDAGISel::hasAllNBitUsers(SDNode *Node, unsigned Bits) const { 2125349cc55cSDimitry Andric assert((Node->getOpcode() == ISD::ADD || Node->getOpcode() == ISD::SUB || 2126349cc55cSDimitry Andric Node->getOpcode() == ISD::MUL || Node->getOpcode() == ISD::SHL || 2127349cc55cSDimitry Andric Node->getOpcode() == ISD::SRL || 2128349cc55cSDimitry Andric Node->getOpcode() == ISD::SIGN_EXTEND_INREG || 212981ad6265SDimitry Andric Node->getOpcode() == RISCVISD::GREV || 213081ad6265SDimitry Andric Node->getOpcode() == RISCVISD::GORC || 2131349cc55cSDimitry Andric isa<ConstantSDNode>(Node)) && 2132349cc55cSDimitry Andric "Unexpected opcode"); 2133349cc55cSDimitry Andric 2134349cc55cSDimitry Andric for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { 2135349cc55cSDimitry Andric SDNode *User = *UI; 2136349cc55cSDimitry Andric // Users of this node should have already been instruction selected 2137349cc55cSDimitry Andric if (!User->isMachineOpcode()) 2138349cc55cSDimitry Andric return false; 2139349cc55cSDimitry Andric 2140349cc55cSDimitry Andric // TODO: Add more opcodes? 2141349cc55cSDimitry Andric switch (User->getMachineOpcode()) { 2142349cc55cSDimitry Andric default: 2143349cc55cSDimitry Andric return false; 2144349cc55cSDimitry Andric case RISCV::ADDW: 2145349cc55cSDimitry Andric case RISCV::ADDIW: 2146349cc55cSDimitry Andric case RISCV::SUBW: 2147349cc55cSDimitry Andric case RISCV::MULW: 2148349cc55cSDimitry Andric case RISCV::SLLW: 2149349cc55cSDimitry Andric case RISCV::SLLIW: 2150349cc55cSDimitry Andric case RISCV::SRAW: 2151349cc55cSDimitry Andric case RISCV::SRAIW: 2152349cc55cSDimitry Andric case RISCV::SRLW: 2153349cc55cSDimitry Andric case RISCV::SRLIW: 2154349cc55cSDimitry Andric case RISCV::DIVW: 2155349cc55cSDimitry Andric case RISCV::DIVUW: 2156349cc55cSDimitry Andric case RISCV::REMW: 2157349cc55cSDimitry Andric case RISCV::REMUW: 2158349cc55cSDimitry Andric case RISCV::ROLW: 2159349cc55cSDimitry Andric case RISCV::RORW: 2160349cc55cSDimitry Andric case RISCV::RORIW: 2161349cc55cSDimitry Andric case RISCV::CLZW: 2162349cc55cSDimitry Andric case RISCV::CTZW: 2163349cc55cSDimitry Andric case RISCV::CPOPW: 21641fd87a68SDimitry Andric case RISCV::SLLI_UW: 216581ad6265SDimitry Andric case RISCV::FMV_W_X: 2166349cc55cSDimitry Andric case RISCV::FCVT_H_W: 2167349cc55cSDimitry Andric case RISCV::FCVT_H_WU: 2168349cc55cSDimitry Andric case RISCV::FCVT_S_W: 2169349cc55cSDimitry Andric case RISCV::FCVT_S_WU: 2170349cc55cSDimitry Andric case RISCV::FCVT_D_W: 2171349cc55cSDimitry Andric case RISCV::FCVT_D_WU: 2172349cc55cSDimitry Andric if (Bits < 32) 2173349cc55cSDimitry Andric return false; 2174349cc55cSDimitry Andric break; 2175349cc55cSDimitry Andric case RISCV::SLLI: 2176349cc55cSDimitry Andric // SLLI only uses the lower (XLen - ShAmt) bits. 2177349cc55cSDimitry Andric if (Bits < Subtarget->getXLen() - User->getConstantOperandVal(1)) 2178349cc55cSDimitry Andric return false; 2179349cc55cSDimitry Andric break; 218004eeddc0SDimitry Andric case RISCV::ANDI: 218104eeddc0SDimitry Andric if (Bits < (64 - countLeadingZeros(User->getConstantOperandVal(1)))) 218204eeddc0SDimitry Andric return false; 218304eeddc0SDimitry Andric break; 21841fd87a68SDimitry Andric case RISCV::SEXT_B: 218504eeddc0SDimitry Andric if (Bits < 8) 218604eeddc0SDimitry Andric return false; 218704eeddc0SDimitry Andric break; 21881fd87a68SDimitry Andric case RISCV::SEXT_H: 218981ad6265SDimitry Andric case RISCV::FMV_H_X: 21901fd87a68SDimitry Andric case RISCV::ZEXT_H_RV32: 21911fd87a68SDimitry Andric case RISCV::ZEXT_H_RV64: 219204eeddc0SDimitry Andric if (Bits < 16) 219304eeddc0SDimitry Andric return false; 219404eeddc0SDimitry Andric break; 21951fd87a68SDimitry Andric case RISCV::ADD_UW: 21961fd87a68SDimitry Andric case RISCV::SH1ADD_UW: 21971fd87a68SDimitry Andric case RISCV::SH2ADD_UW: 21981fd87a68SDimitry Andric case RISCV::SH3ADD_UW: 2199349cc55cSDimitry Andric // The first operand to add.uw/shXadd.uw is implicitly zero extended from 2200349cc55cSDimitry Andric // 32 bits. 2201349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2202349cc55cSDimitry Andric return false; 2203349cc55cSDimitry Andric break; 2204349cc55cSDimitry Andric case RISCV::SB: 2205349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 8) 2206349cc55cSDimitry Andric return false; 2207349cc55cSDimitry Andric break; 2208349cc55cSDimitry Andric case RISCV::SH: 2209349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 16) 2210349cc55cSDimitry Andric return false; 2211349cc55cSDimitry Andric break; 2212349cc55cSDimitry Andric case RISCV::SW: 2213349cc55cSDimitry Andric if (UI.getOperandNo() != 0 || Bits < 32) 2214349cc55cSDimitry Andric return false; 2215349cc55cSDimitry Andric break; 2216349cc55cSDimitry Andric } 2217349cc55cSDimitry Andric } 2218349cc55cSDimitry Andric 2219349cc55cSDimitry Andric return true; 2220349cc55cSDimitry Andric } 2221349cc55cSDimitry Andric 2222fe6060f1SDimitry Andric // Select VL as a 5 bit immediate or a value that will become a register. This 2223fe6060f1SDimitry Andric // allows us to choose betwen VSETIVLI or VSETVLI later. 2224d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 2225d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 222681ad6265SDimitry Andric if (C && isUInt<5>(C->getZExtValue())) { 2227fe6060f1SDimitry Andric VL = CurDAG->getTargetConstant(C->getZExtValue(), SDLoc(N), 2228fe6060f1SDimitry Andric N->getValueType(0)); 222981ad6265SDimitry Andric } else if (C && C->isAllOnesValue()) { 223081ad6265SDimitry Andric // Treat all ones as VLMax. 223181ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 223281ad6265SDimitry Andric N->getValueType(0)); 223381ad6265SDimitry Andric } else if (isa<RegisterSDNode>(N) && 223481ad6265SDimitry Andric cast<RegisterSDNode>(N)->getReg() == RISCV::X0) { 223581ad6265SDimitry Andric // All our VL operands use an operand that allows GPRNoX0 or an immediate 223681ad6265SDimitry Andric // as the register class. Convert X0 to a special immediate to pass the 223781ad6265SDimitry Andric // MachineVerifier. This is recognized specially by the vsetvli insertion 223881ad6265SDimitry Andric // pass. 223981ad6265SDimitry Andric VL = CurDAG->getTargetConstant(RISCV::VLMaxSentinel, SDLoc(N), 224081ad6265SDimitry Andric N->getValueType(0)); 224181ad6265SDimitry Andric } else { 2242d409305fSDimitry Andric VL = N; 224381ad6265SDimitry Andric } 2244d409305fSDimitry Andric 2245d409305fSDimitry Andric return true; 2246d409305fSDimitry Andric } 2247d409305fSDimitry Andric 2248e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 224981ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef()) 2250e8d8bef9SDimitry Andric return false; 225181ad6265SDimitry Andric SplatVal = N.getOperand(1); 2252979e22ffSDimitry Andric return true; 2253979e22ffSDimitry Andric } 2254e8d8bef9SDimitry Andric 2255fe6060f1SDimitry Andric using ValidateFn = bool (*)(int64_t); 2256fe6060f1SDimitry Andric 2257fe6060f1SDimitry Andric static bool selectVSplatSimmHelper(SDValue N, SDValue &SplatVal, 2258fe6060f1SDimitry Andric SelectionDAG &DAG, 2259fe6060f1SDimitry Andric const RISCVSubtarget &Subtarget, 2260fe6060f1SDimitry Andric ValidateFn ValidateImm) { 226181ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 226281ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 2263979e22ffSDimitry Andric return false; 2264e8d8bef9SDimitry Andric 226581ad6265SDimitry Andric int64_t SplatImm = 226681ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 2267e8d8bef9SDimitry Andric 226881ad6265SDimitry Andric // The semantics of RISCVISD::VMV_V_X_VL is that when the operand 226981ad6265SDimitry Andric // type is wider than the resulting vector element type: an implicit 227081ad6265SDimitry Andric // truncation first takes place. Therefore, perform a manual 227181ad6265SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 227281ad6265SDimitry Andric // any zero-extended immediate. 2273e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 2274e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 2275fe6060f1SDimitry Andric MVT XLenVT = Subtarget.getXLenVT(); 227681ad6265SDimitry Andric assert(XLenVT == N.getOperand(1).getSimpleValueType() && 2277e8d8bef9SDimitry Andric "Unexpected splat operand type"); 2278fe6060f1SDimitry Andric MVT EltVT = N.getSimpleValueType().getVectorElementType(); 2279fe6060f1SDimitry Andric if (EltVT.bitsLT(XLenVT)) 2280e8d8bef9SDimitry Andric SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits()); 2281979e22ffSDimitry Andric 2282fe6060f1SDimitry Andric if (!ValidateImm(SplatImm)) 2283e8d8bef9SDimitry Andric return false; 2284979e22ffSDimitry Andric 2285fe6060f1SDimitry Andric SplatVal = DAG.getTargetConstant(SplatImm, SDLoc(N), XLenVT); 2286979e22ffSDimitry Andric return true; 2287979e22ffSDimitry Andric } 2288e8d8bef9SDimitry Andric 2289fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 2290fe6060f1SDimitry Andric return selectVSplatSimmHelper(N, SplatVal, *CurDAG, *Subtarget, 2291fe6060f1SDimitry Andric [](int64_t Imm) { return isInt<5>(Imm); }); 2292fe6060f1SDimitry Andric } 2293fe6060f1SDimitry Andric 2294fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1(SDValue N, SDValue &SplatVal) { 2295fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2296fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, 2297fe6060f1SDimitry Andric [](int64_t Imm) { return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }); 2298fe6060f1SDimitry Andric } 2299fe6060f1SDimitry Andric 2300fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5Plus1NonZero(SDValue N, 2301fe6060f1SDimitry Andric SDValue &SplatVal) { 2302fe6060f1SDimitry Andric return selectVSplatSimmHelper( 2303fe6060f1SDimitry Andric N, SplatVal, *CurDAG, *Subtarget, [](int64_t Imm) { 2304fe6060f1SDimitry Andric return Imm != 0 && ((isInt<5>(Imm) && Imm != -16) || Imm == 16); 2305fe6060f1SDimitry Andric }); 2306fe6060f1SDimitry Andric } 2307fe6060f1SDimitry Andric 2308e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &SplatVal) { 230981ad6265SDimitry Andric if (N.getOpcode() != RISCVISD::VMV_V_X_VL || !N.getOperand(0).isUndef() || 231081ad6265SDimitry Andric !isa<ConstantSDNode>(N.getOperand(1))) 2311979e22ffSDimitry Andric return false; 2312979e22ffSDimitry Andric 231381ad6265SDimitry Andric int64_t SplatImm = 231481ad6265SDimitry Andric cast<ConstantSDNode>(N.getOperand(1))->getSExtValue(); 2315979e22ffSDimitry Andric 2316e8d8bef9SDimitry Andric if (!isUInt<5>(SplatImm)) 2317e8d8bef9SDimitry Andric return false; 2318e8d8bef9SDimitry Andric 2319e8d8bef9SDimitry Andric SplatVal = 2320e8d8bef9SDimitry Andric CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT()); 2321e8d8bef9SDimitry Andric 2322979e22ffSDimitry Andric return true; 2323979e22ffSDimitry Andric } 2324979e22ffSDimitry Andric 2325fe6060f1SDimitry Andric bool RISCVDAGToDAGISel::selectRVVSimm5(SDValue N, unsigned Width, 2326fe6060f1SDimitry Andric SDValue &Imm) { 2327fe6060f1SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(N)) { 2328fe6060f1SDimitry Andric int64_t ImmVal = SignExtend64(C->getSExtValue(), Width); 2329fe6060f1SDimitry Andric 2330fe6060f1SDimitry Andric if (!isInt<5>(ImmVal)) 2331fe6060f1SDimitry Andric return false; 2332fe6060f1SDimitry Andric 2333fe6060f1SDimitry Andric Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), Subtarget->getXLenVT()); 2334fe6060f1SDimitry Andric return true; 2335fe6060f1SDimitry Andric } 2336fe6060f1SDimitry Andric 2337fe6060f1SDimitry Andric return false; 2338fe6060f1SDimitry Andric } 2339fe6060f1SDimitry Andric 2340349cc55cSDimitry Andric // Try to remove sext.w if the input is a W instruction or can be made into 2341349cc55cSDimitry Andric // a W instruction cheaply. 2342349cc55cSDimitry Andric bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) { 2343349cc55cSDimitry Andric // Look for the sext.w pattern, addiw rd, rs1, 0. 2344349cc55cSDimitry Andric if (N->getMachineOpcode() != RISCV::ADDIW || 2345349cc55cSDimitry Andric !isNullConstant(N->getOperand(1))) 2346349cc55cSDimitry Andric return false; 2347349cc55cSDimitry Andric 2348349cc55cSDimitry Andric SDValue N0 = N->getOperand(0); 2349349cc55cSDimitry Andric if (!N0.isMachineOpcode()) 2350349cc55cSDimitry Andric return false; 2351349cc55cSDimitry Andric 2352349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 2353349cc55cSDimitry Andric default: 2354349cc55cSDimitry Andric break; 2355349cc55cSDimitry Andric case RISCV::ADD: 2356349cc55cSDimitry Andric case RISCV::ADDI: 2357349cc55cSDimitry Andric case RISCV::SUB: 2358349cc55cSDimitry Andric case RISCV::MUL: 2359349cc55cSDimitry Andric case RISCV::SLLI: { 2360349cc55cSDimitry Andric // Convert sext.w+add/sub/mul to their W instructions. This will create 2361349cc55cSDimitry Andric // a new independent instruction. This improves latency. 2362349cc55cSDimitry Andric unsigned Opc; 2363349cc55cSDimitry Andric switch (N0.getMachineOpcode()) { 2364349cc55cSDimitry Andric default: 2365349cc55cSDimitry Andric llvm_unreachable("Unexpected opcode!"); 2366349cc55cSDimitry Andric case RISCV::ADD: Opc = RISCV::ADDW; break; 2367349cc55cSDimitry Andric case RISCV::ADDI: Opc = RISCV::ADDIW; break; 2368349cc55cSDimitry Andric case RISCV::SUB: Opc = RISCV::SUBW; break; 2369349cc55cSDimitry Andric case RISCV::MUL: Opc = RISCV::MULW; break; 2370349cc55cSDimitry Andric case RISCV::SLLI: Opc = RISCV::SLLIW; break; 2371349cc55cSDimitry Andric } 2372349cc55cSDimitry Andric 2373349cc55cSDimitry Andric SDValue N00 = N0.getOperand(0); 2374349cc55cSDimitry Andric SDValue N01 = N0.getOperand(1); 2375349cc55cSDimitry Andric 2376349cc55cSDimitry Andric // Shift amount needs to be uimm5. 2377349cc55cSDimitry Andric if (N0.getMachineOpcode() == RISCV::SLLI && 2378349cc55cSDimitry Andric !isUInt<5>(cast<ConstantSDNode>(N01)->getSExtValue())) 2379349cc55cSDimitry Andric break; 2380349cc55cSDimitry Andric 2381349cc55cSDimitry Andric SDNode *Result = 2382349cc55cSDimitry Andric CurDAG->getMachineNode(Opc, SDLoc(N), N->getValueType(0), 2383349cc55cSDimitry Andric N00, N01); 2384349cc55cSDimitry Andric ReplaceUses(N, Result); 2385349cc55cSDimitry Andric return true; 2386349cc55cSDimitry Andric } 2387349cc55cSDimitry Andric case RISCV::ADDW: 2388349cc55cSDimitry Andric case RISCV::ADDIW: 2389349cc55cSDimitry Andric case RISCV::SUBW: 2390349cc55cSDimitry Andric case RISCV::MULW: 2391349cc55cSDimitry Andric case RISCV::SLLIW: 239281ad6265SDimitry Andric case RISCV::GREVIW: 239381ad6265SDimitry Andric case RISCV::GORCIW: 2394349cc55cSDimitry Andric // Result is already sign extended just remove the sext.w. 2395349cc55cSDimitry Andric // NOTE: We only handle the nodes that are selected with hasAllWUsers. 2396349cc55cSDimitry Andric ReplaceUses(N, N0.getNode()); 2397349cc55cSDimitry Andric return true; 2398349cc55cSDimitry Andric } 2399349cc55cSDimitry Andric 2400349cc55cSDimitry Andric return false; 24010b57cec5SDimitry Andric } 24020b57cec5SDimitry Andric 240381ad6265SDimitry Andric // Optimize masked RVV pseudo instructions with a known all-ones mask to their 240481ad6265SDimitry Andric // corresponding "unmasked" pseudo versions. The mask we're interested in will 240581ad6265SDimitry Andric // take the form of a V0 physical register operand, with a glued 240681ad6265SDimitry Andric // register-setting instruction. 240781ad6265SDimitry Andric bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) { 240881ad6265SDimitry Andric const RISCV::RISCVMaskedPseudoInfo *I = 240981ad6265SDimitry Andric RISCV::getMaskedPseudoInfo(N->getMachineOpcode()); 241081ad6265SDimitry Andric if (!I) 241181ad6265SDimitry Andric return false; 241281ad6265SDimitry Andric 241381ad6265SDimitry Andric unsigned MaskOpIdx = I->MaskOpIdx; 241481ad6265SDimitry Andric 241581ad6265SDimitry Andric // Check that we're using V0 as a mask register. 241681ad6265SDimitry Andric if (!isa<RegisterSDNode>(N->getOperand(MaskOpIdx)) || 241781ad6265SDimitry Andric cast<RegisterSDNode>(N->getOperand(MaskOpIdx))->getReg() != RISCV::V0) 241881ad6265SDimitry Andric return false; 241981ad6265SDimitry Andric 242081ad6265SDimitry Andric // The glued user defines V0. 242181ad6265SDimitry Andric const auto *Glued = N->getGluedNode(); 242281ad6265SDimitry Andric 242381ad6265SDimitry Andric if (!Glued || Glued->getOpcode() != ISD::CopyToReg) 242481ad6265SDimitry Andric return false; 242581ad6265SDimitry Andric 242681ad6265SDimitry Andric // Check that we're defining V0 as a mask register. 242781ad6265SDimitry Andric if (!isa<RegisterSDNode>(Glued->getOperand(1)) || 242881ad6265SDimitry Andric cast<RegisterSDNode>(Glued->getOperand(1))->getReg() != RISCV::V0) 242981ad6265SDimitry Andric return false; 243081ad6265SDimitry Andric 243181ad6265SDimitry Andric // Check the instruction defining V0; it needs to be a VMSET pseudo. 243281ad6265SDimitry Andric SDValue MaskSetter = Glued->getOperand(2); 243381ad6265SDimitry Andric 243481ad6265SDimitry Andric const auto IsVMSet = [](unsigned Opc) { 243581ad6265SDimitry Andric return Opc == RISCV::PseudoVMSET_M_B1 || Opc == RISCV::PseudoVMSET_M_B16 || 243681ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B2 || Opc == RISCV::PseudoVMSET_M_B32 || 243781ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B4 || Opc == RISCV::PseudoVMSET_M_B64 || 243881ad6265SDimitry Andric Opc == RISCV::PseudoVMSET_M_B8; 243981ad6265SDimitry Andric }; 244081ad6265SDimitry Andric 244181ad6265SDimitry Andric // TODO: Check that the VMSET is the expected bitwidth? The pseudo has 244281ad6265SDimitry Andric // undefined behaviour if it's the wrong bitwidth, so we could choose to 244381ad6265SDimitry Andric // assume that it's all-ones? Same applies to its VL. 244481ad6265SDimitry Andric if (!MaskSetter->isMachineOpcode() || !IsVMSet(MaskSetter.getMachineOpcode())) 244581ad6265SDimitry Andric return false; 244681ad6265SDimitry Andric 244781ad6265SDimitry Andric // Retrieve the tail policy operand index, if any. 244881ad6265SDimitry Andric Optional<unsigned> TailPolicyOpIdx; 244981ad6265SDimitry Andric const RISCVInstrInfo &TII = *Subtarget->getInstrInfo(); 245081ad6265SDimitry Andric const MCInstrDesc &MaskedMCID = TII.get(N->getMachineOpcode()); 245181ad6265SDimitry Andric 245281ad6265SDimitry Andric bool IsTA = true; 245381ad6265SDimitry Andric if (RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags)) { 245481ad6265SDimitry Andric // The last operand of the pseudo is the policy op, but we might have a 245581ad6265SDimitry Andric // Glue operand last. We might also have a chain. 245681ad6265SDimitry Andric TailPolicyOpIdx = N->getNumOperands() - 1; 245781ad6265SDimitry Andric if (N->getOperand(*TailPolicyOpIdx).getValueType() == MVT::Glue) 245881ad6265SDimitry Andric (*TailPolicyOpIdx)--; 245981ad6265SDimitry Andric if (N->getOperand(*TailPolicyOpIdx).getValueType() == MVT::Other) 246081ad6265SDimitry Andric (*TailPolicyOpIdx)--; 246181ad6265SDimitry Andric 246281ad6265SDimitry Andric if (!(N->getConstantOperandVal(*TailPolicyOpIdx) & 246381ad6265SDimitry Andric RISCVII::TAIL_AGNOSTIC)) { 246481ad6265SDimitry Andric // Keep the true-masked instruction when there is no unmasked TU 246581ad6265SDimitry Andric // instruction 246681ad6265SDimitry Andric if (I->UnmaskedTUPseudo == I->MaskedPseudo && !N->getOperand(0).isUndef()) 246781ad6265SDimitry Andric return false; 246881ad6265SDimitry Andric // We can't use TA if the tie-operand is not IMPLICIT_DEF 246981ad6265SDimitry Andric if (!N->getOperand(0).isUndef()) 247081ad6265SDimitry Andric IsTA = false; 247181ad6265SDimitry Andric } 247281ad6265SDimitry Andric } 247381ad6265SDimitry Andric 247481ad6265SDimitry Andric unsigned Opc = IsTA ? I->UnmaskedPseudo : I->UnmaskedTUPseudo; 247581ad6265SDimitry Andric 247681ad6265SDimitry Andric // Check that we're dropping the mask operand and any policy operand 247781ad6265SDimitry Andric // when we transform to this unmasked pseudo. Additionally, if this insturtion 247881ad6265SDimitry Andric // is tail agnostic, the unmasked instruction should not have a merge op. 247981ad6265SDimitry Andric uint64_t TSFlags = TII.get(Opc).TSFlags; 248081ad6265SDimitry Andric assert((IsTA != RISCVII::hasMergeOp(TSFlags)) && 248181ad6265SDimitry Andric RISCVII::hasDummyMaskOp(TSFlags) && 248281ad6265SDimitry Andric !RISCVII::hasVecPolicyOp(TSFlags) && 248381ad6265SDimitry Andric "Unexpected pseudo to transform to"); 248481ad6265SDimitry Andric (void)TSFlags; 248581ad6265SDimitry Andric 248681ad6265SDimitry Andric SmallVector<SDValue, 8> Ops; 248781ad6265SDimitry Andric // Skip the merge operand at index 0 if IsTA 248881ad6265SDimitry Andric for (unsigned I = IsTA, E = N->getNumOperands(); I != E; I++) { 248981ad6265SDimitry Andric // Skip the mask, the policy, and the Glue. 249081ad6265SDimitry Andric SDValue Op = N->getOperand(I); 249181ad6265SDimitry Andric if (I == MaskOpIdx || I == TailPolicyOpIdx || 249281ad6265SDimitry Andric Op.getValueType() == MVT::Glue) 249381ad6265SDimitry Andric continue; 249481ad6265SDimitry Andric Ops.push_back(Op); 249581ad6265SDimitry Andric } 249681ad6265SDimitry Andric 249781ad6265SDimitry Andric // Transitively apply any node glued to our new node. 249881ad6265SDimitry Andric if (auto *TGlued = Glued->getGluedNode()) 249981ad6265SDimitry Andric Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1)); 250081ad6265SDimitry Andric 250181ad6265SDimitry Andric SDNode *Result = CurDAG->getMachineNode(Opc, SDLoc(N), N->getVTList(), Ops); 250281ad6265SDimitry Andric ReplaceUses(N, Result); 250381ad6265SDimitry Andric 250481ad6265SDimitry Andric return true; 250581ad6265SDimitry Andric } 250681ad6265SDimitry Andric 25070b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 25080b57cec5SDimitry Andric // for instruction scheduling. 250981ad6265SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM, 251081ad6265SDimitry Andric CodeGenOpt::Level OptLevel) { 251181ad6265SDimitry Andric return new RISCVDAGToDAGISel(TM, OptLevel); 25120b57cec5SDimitry Andric } 2513